##// END OF EJS Templates
core: revamp of automation/scheduler/artifacts EE functionality
super-admin -
r5137:f3cd5ebe default
parent child Browse files
Show More
@@ -0,0 +1,38 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 import logging
20
21 from rhodecode.apps._base import BaseAppView
22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
23
24 log = logging.getLogger(__name__)
25
26
27 class AdminAutomationView(BaseAppView):
28
29 def load_default_context(self):
30 c = self._get_local_tmpl_context()
31 return c
32
33 @LoginRequired()
34 @HasPermissionAllDecorator('hg.admin')
35 def automation(self):
36 c = self.load_default_context()
37 c.active = 'automation'
38 return self._get_template_context(c)
@@ -0,0 +1,38 b''
1 # Copyright (C) 2016-2023 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 import logging
20
21 from rhodecode.apps._base import BaseAppView
22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
23
24 log = logging.getLogger(__name__)
25
26
27 class AdminSchedulerView(BaseAppView):
28
29 def load_default_context(self):
30 c = self._get_local_tmpl_context()
31 return c
32
33 @LoginRequired()
34 @HasPermissionAllDecorator('hg.admin')
35 def scheduler(self):
36 c = self.load_default_context()
37 c.active = 'scheduler'
38 return self._get_template_context(c)
@@ -0,0 +1,39 b''
1 <%inherit file="/base/base.mako"/>
2
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='scheduler')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Scheduler Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <p>
31 Scheduler enables management of automation tasks, and defining new custom cron-like actions to be executed within RhodeCode system.
32 </p>
33 </div>
34 </div>
35
36 </div>
37
38
39 </%def>
@@ -0,0 +1,37 b''
1 <%inherit file="/base/base.mako"/>
2
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='automation')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Automation Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
31 </div>
32 </div>
33
34 </div>
35
36
37 </%def>
@@ -42,8 +42,8 b' from rhodecode.model.repo import ReadmeF'
42 42 log = logging.getLogger(__name__)
43 43
44 44
45 ADMIN_PREFIX = '/_admin'
46 STATIC_FILE_PREFIX = '/_static'
45 ADMIN_PREFIX: str = '/_admin'
46 STATIC_FILE_PREFIX: str = '/_static'
47 47
48 48 URL_NAME_REQUIREMENTS = {
49 49 # group name can have a slash in them, but they must not end with a slash
@@ -101,8 +101,6 b' class NavigationRegistry(object):'
101 101 'admin_settings_sessions'),
102 102 NavEntry('open_source', _('Open Source Licenses'),
103 103 'admin_settings_open_source'),
104 NavEntry('automation', _('Automation'),
105 'admin_settings_automation')
106 104 ]
107 105
108 106 _labs_entry = NavEntry('labs', _('Labs'),
@@ -18,6 +18,8 b''
18 18
19 19
20 20 from rhodecode.apps._base import ADMIN_PREFIX
21 from rhodecode.apps._base.navigation import includeme as nav_includeme
22 from rhodecode.apps.admin.views.main_views import AdminMainView
21 23
22 24
23 25 def admin_routes(config):
@@ -26,9 +28,10 b' def admin_routes(config):'
26 28 """
27 29 from rhodecode.apps.admin.views.audit_logs import AdminAuditLogsView
28 30 from rhodecode.apps.admin.views.artifacts import AdminArtifactsView
31 from rhodecode.apps.admin.views.automation import AdminAutomationView
32 from rhodecode.apps.admin.views.scheduler import AdminSchedulerView
29 33 from rhodecode.apps.admin.views.defaults import AdminDefaultSettingsView
30 34 from rhodecode.apps.admin.views.exception_tracker import ExceptionsTrackerView
31 from rhodecode.apps.admin.views.main_views import AdminMainView
32 35 from rhodecode.apps.admin.views.open_source_licenses import OpenSourceLicensesAdminSettingsView
33 36 from rhodecode.apps.admin.views.permissions import AdminPermissionsView
34 37 from rhodecode.apps.admin.views.process_management import AdminProcessManagementView
@@ -76,6 +79,7 b' def admin_routes(config):'
76 79 attr='artifacts',
77 80 route_name='admin_artifacts_show_all', request_method='GET',
78 81 renderer='rhodecode:templates/admin/artifacts/artifacts.mako')
82
79 83 # EE views
80 84 config.add_route(
81 85 name='admin_artifacts_show_info',
@@ -87,6 +91,26 b' def admin_routes(config):'
87 91 name='admin_artifacts_update',
88 92 pattern=ADMIN_PREFIX + '/artifacts/{uid}/update')
89 93
94 # Automation EE feature
95 config.add_route(
96 'admin_automation',
97 pattern=ADMIN_PREFIX + '/automation')
98 config.add_view(
99 AdminAutomationView,
100 attr='automation',
101 route_name='admin_automation', request_method='GET',
102 renderer='rhodecode:templates/admin/automation/automation.mako')
103
104 # Scheduler EE feature
105 config.add_route(
106 'admin_scheduler',
107 pattern=ADMIN_PREFIX + '/scheduler')
108 config.add_view(
109 AdminSchedulerView,
110 attr='scheduler',
111 route_name='admin_scheduler', request_method='GET',
112 renderer='rhodecode:templates/admin/scheduler/scheduler.mako')
113
90 114 config.add_route(
91 115 name='admin_settings_open_source',
92 116 pattern='/settings/open_source')
@@ -440,16 +464,6 b' def admin_routes(config):'
440 464 route_name='admin_settings_labs_update', request_method='POST',
441 465 renderer='rhodecode:templates/admin/settings/settings.mako')
442 466
443 # Automation EE feature
444 config.add_route(
445 'admin_settings_automation',
446 pattern=ADMIN_PREFIX + '/settings/automation')
447 config.add_view(
448 AdminSettingsView,
449 attr='settings_automation',
450 route_name='admin_settings_automation', request_method='GET',
451 renderer='rhodecode:templates/admin/settings/settings.mako')
452
453 467 # global permissions
454 468
455 469 config.add_route(
@@ -1039,9 +1053,6 b' def admin_routes(config):'
1039 1053
1040 1054
1041 1055 def includeme(config):
1042 from rhodecode.apps._base.navigation import includeme as nav_includeme
1043 from rhodecode.apps.admin.views.main_views import AdminMainView
1044
1045 1056 # Create admin navigation registry and add it to the pyramid registry.
1046 1057 nav_includeme(config)
1047 1058
@@ -248,8 +248,9 b' class AdminSettingsView(BaseAppView):'
248 248 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
249 249 PermissionModel().trigger_permission_flush()
250 250
251 def _repr(l):
252 return ', '.join(map(safe_str, l)) or '-'
251 def _repr(rm_repo):
252 return ', '.join(map(safe_str, rm_repo)) or '-'
253
253 254 h.flash(_('Repositories successfully '
254 255 'rescanned added: %s ; removed: %s') %
255 256 (_repr(added), _repr(removed)),
@@ -623,14 +624,6 b' class AdminSettingsView(BaseAppView):'
623 624
624 625 @LoginRequired()
625 626 @HasPermissionAllDecorator('hg.admin')
626 def settings_automation(self):
627 c = self.load_default_context()
628 c.active = 'automation'
629
630 return self._get_template_context(c)
631
632 @LoginRequired()
633 @HasPermissionAllDecorator('hg.admin')
634 627 def settings_labs(self):
635 628 c = self.load_default_context()
636 629 if not c.labs_active:
@@ -413,6 +413,7 b' class RepoFilesView(RepoAppView):'
413 413 archive_cache_disable = self.request.GET.get('no_cache')
414 414
415 415 d_cache = get_archival_cache_store(config=CONFIG)
416
416 417 # NOTE: we get the config to pass to a call to lazy-init the SAME type of cache on vcsserver
417 418 d_cache_conf = get_archival_config(config=CONFIG)
418 419
@@ -30,6 +30,9 b' class PullRequestEvent(RepoEvent):'
30 30
31 31 :param pullrequest: a :class:`PullRequest` instance
32 32 """
33 name = 'pullrequest-event'
34 display_name = lazy_ugettext('pullrequest generic event')
35 description = lazy_ugettext('All events within a context of a pull request')
33 36
34 37 def __init__(self, pullrequest):
35 38 super().__init__(pullrequest.target_repo)
@@ -21,7 +21,7 b' import logging'
21 21 import datetime
22 22
23 23 from rhodecode.translation import lazy_ugettext
24 from rhodecode.model.db import User, Repository, Session
24 from rhodecode.model.db import User, Repository
25 25 from rhodecode.events.base import RhodeCodeIntegrationEvent
26 26 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
27 27
@@ -34,7 +34,7 b' def _commits_as_dict(event, commit_ids, '
34 34
35 35 :param event: class calling this method
36 36 :param commit_ids: commits to get
37 :param repos: list of repos to check
37 :param repos: a list of repos to check
38 38 """
39 39 from rhodecode.lib.utils2 import extract_mentioned_users
40 40 from rhodecode.lib.helpers import (
@@ -154,11 +154,12 b' def _issues_as_dict(commits):'
154 154 class RepoEvent(RhodeCodeIntegrationEvent):
155 155 """
156 156 Base class for events acting on a repository.
157
158 :param repo: a :class:`Repository` instance
159 157 """
160 158
161 159 def __init__(self, repo):
160 """
161 :param repo: a :class:`Repository` instance
162 """
162 163 super().__init__()
163 164 self.repo = repo
164 165
@@ -299,6 +300,9 b' class RepoVCSEvent(RepoEvent):'
299 300 """
300 301 Base class for events triggered by the VCS
301 302 """
303 name = ''
304 display_name = 'generic_vcs_event'
305
302 306 def __init__(self, repo_name, extras):
303 307 self.repo = Repository.get_by_repo_name(repo_name)
304 308 if not self.repo:
@@ -44,7 +44,7 b' def run_task(task, *args, **kwargs):'
44 44 import celery
45 45 log.debug('Got task `%s` for execution, celery mode enabled:%s', task, rhodecode.CELERY_ENABLED)
46 46 if task is None:
47 raise ValueError('Got non-existing task for execution')
47 raise ValueError(f'Got non-existing task: {task} for execution')
48 48
49 49 exec_mode = 'sync'
50 50 allow_async = True
@@ -19,9 +19,7 b''
19 19
20 20 import sqlalchemy
21 21 from sqlalchemy import UnicodeText
22 from sqlalchemy.ext.mutable import Mutable, \
23 MutableList as MutationList, \
24 MutableDict as MutationDict
22 from sqlalchemy.ext.mutable import Mutable, MutableList, MutableDict
25 23
26 24 from rhodecode.lib import ext_json
27 25
@@ -30,7 +28,7 b' class JsonRaw(str):'
30 28 """
31 29 Allows interacting with a JSON types field using a raw string.
32 30
33 For example::
31 For example:
34 32 db_instance = JsonTable()
35 33 db_instance.enabled = True
36 34 db_instance.json_data = JsonRaw('{"a": 4}')
@@ -100,7 +98,7 b' class MutationObj(Mutable):'
100 98 return MutationList.coerce(key, value)
101 99 return value
102 100
103 def de_coerce(self):
101 def de_coerce(self) -> "MutationObj":
104 102 return self
105 103
106 104 @classmethod
@@ -153,6 +151,16 b' class MutationObj(Mutable):'
153 151 propagate=True)
154 152
155 153
154 class MutationList(MutableList):
155 def de_coerce(self):
156 return list(self)
157
158
159 class MutationDict(MutableDict):
160 def de_coerce(self):
161 return dict(self)
162
163
156 164 def JsonType(impl=None, **kwargs):
157 165 """
158 166 Helper for using a mutation obj, it allows to use .with_variant easily.
@@ -5378,14 +5378,14 b' class ScheduleEntry(Base, BaseModel):'
5378 5378 except ValueError:
5379 5379 return dict()
5380 5380
5381 def _as_raw(self, val, indent=None):
5381 def _as_raw(self, val, indent=False):
5382 5382 if hasattr(val, 'de_coerce'):
5383 5383 val = val.de_coerce()
5384 5384 if val:
5385 5385 if indent:
5386 ext_json.formatted_json(val)
5386 val = ext_json.formatted_str_json(val)
5387 5387 else:
5388 val = ext_json.json.dumps(val)
5388 val = ext_json.str_json(val)
5389 5389
5390 5390 return val
5391 5391
@@ -5393,10 +5393,10 b' class ScheduleEntry(Base, BaseModel):'
5393 5393 def schedule_definition_raw(self):
5394 5394 return self._as_raw(self.schedule_definition)
5395 5395
5396 def args_raw(self, indent=None):
5396 def args_raw(self, indent=False):
5397 5397 return self._as_raw(self.task_args, indent)
5398 5398
5399 def kwargs_raw(self, indent=None):
5399 def kwargs_raw(self, indent=False):
5400 5400 return self._as_raw(self.task_kwargs, indent)
5401 5401
5402 5402 def __repr__(self):
@@ -5610,6 +5610,19 b' class FileStore(Base, BaseModel):'
5610 5610 repo_group = relationship('RepoGroup', lazy='joined')
5611 5611
5612 5612 @classmethod
5613 def get_scope(cls, scope_type, scope_id):
5614 if scope_type == 'repo':
5615 return f'repo:{scope_id}'
5616 elif scope_type == 'repo-group':
5617 return f'repo-group:{scope_id}'
5618 elif scope_type == 'user':
5619 return f'user:{scope_id}'
5620 elif scope_type == 'user-group':
5621 return f'user-group:{scope_id}'
5622 else:
5623 return scope_type
5624
5625 @classmethod
5613 5626 def get_by_store_uid(cls, file_store_uid, safe=False):
5614 5627 if safe:
5615 5628 return FileStore.query().filter(FileStore.file_uid == file_store_uid).first()
@@ -25,7 +25,7 b' import colander'
25 25 from rhodecode.translation import _
26 26 from rhodecode.lib.utils2 import glob2re
27 27 from rhodecode.lib.str_utils import safe_str
28 from rhodecode.lib.ext_json import json
28 from rhodecode.lib.ext_json import json, sjson
29 29
30 30 log = logging.getLogger(__name__)
31 31
@@ -152,8 +152,9 b' def json_validator(node, value):'
152 152
153 153
154 154 def json_validator_with_exc(node, value):
155
155 156 try:
156 157 json.loads(value)
157 158 except (Exception,) as e:
158 msg = _(f'Please enter a valid json object: `{e}`')
159 msg = _(f'Please enter a valid json object type={type(value)}: `{e}`')
159 160 raise colander.Invalid(node, msg)
@@ -20,6 +20,8 b' function registerRCRoutes() {'
20 20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
21 21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
22 22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
23 pyroutes.register('admin_automation', '/_admin/automation', []);
24 pyroutes.register('admin_automation_update', '/_admin/automation/%(entry_id)s/update', ['entry_id']);
23 25 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
24 26 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
25 27 pyroutes.register('admin_home', '/_admin', []);
@@ -37,9 +39,9 b' function registerRCRoutes() {'
37 39 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
38 40 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
39 41 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
42 pyroutes.register('admin_scheduler', '/_admin/scheduler', []);
43 pyroutes.register('admin_scheduler_show_tasks', '/_admin/scheduler/_tasks', []);
40 44 pyroutes.register('admin_settings', '/_admin/settings', []);
41 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
42 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
43 45 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
44 46 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
45 47 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
@@ -66,14 +68,12 b' function registerRCRoutes() {'
66 68 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
67 69 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
68 70 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
69 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
70 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
71 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
72 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
73 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
74 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
75 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
71 pyroutes.register('admin_settings_scheduler_create', '/_admin/scheduler/create', []);
72 pyroutes.register('admin_settings_scheduler_delete', '/_admin/scheduler/%(schedule_id)s/delete', ['schedule_id']);
73 pyroutes.register('admin_settings_scheduler_edit', '/_admin/scheduler/%(schedule_id)s', ['schedule_id']);
74 pyroutes.register('admin_settings_scheduler_execute', '/_admin/scheduler/%(schedule_id)s/execute', ['schedule_id']);
75 pyroutes.register('admin_settings_scheduler_new', '/_admin/scheduler/new', []);
76 pyroutes.register('admin_settings_scheduler_update', '/_admin/scheduler/%(schedule_id)s/update', ['schedule_id']);
77 77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
78 78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
79 79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
@@ -308,7 +308,6 b' function registerRCRoutes() {'
308 308 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
309 309 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
310 310 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
311 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
312 311 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 312 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
314 313 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
@@ -362,6 +361,7 b' function registerRCRoutes() {'
362 361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
363 362 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
364 363 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
364 pyroutes.register('repo_settings_quick_actions', '/%(repo_name)s/settings/quick-action', ['repo_name']);
365 365 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
366 366 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
367 367 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
@@ -27,7 +27,10 b''
27 27 </div>
28 28 <div class="panel-body">
29 29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30
30 <p>
31 Artifacts are a binary file storage within RhodeCode that allows asset management next to version control system with fine-grained access control.
32 This functionality allows release builds or other types of binary asset to be stored and managed by RhodeCode.
33 </p>
31 34 </div>
32 35 </div>
33 36
@@ -1,9 +1,37 b''
1 <div class="panel panel-default">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Admin Automation')}</h3>
1 <%inherit file="/base/base.mako"/>
2
3 <%def name="title()">
4 ${_('Artifacts Admin')}
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
8 </%def>
9
10 <%def name="breadcrumbs_links()"></%def>
11
12 <%def name="menu_bar_nav()">
13 ${self.menu_items(active='admin')}
14 </%def>
15
16 <%def name="menu_bar_subnav()">
17 ${self.admin_menu(active='automation')}
18 </%def>
19
20 <%def name="main()">
21
22 <div class="box">
23
24 <div class="panel panel-default">
25 <div class="panel-heading">
26 <h3 class="panel-title">${_('Automation Administration.')}</h3>
27 </div>
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <img alt="admin-automation" style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
31 </div>
4 32 </div>
5 <div class="panel-body">
6 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
7 <img style="width: 100%; height: 100%" src="${h.asset('images/ee_features/admin_automation.png')}"/>
8 </div>
33
9 34 </div>
35
36
37 </%def>
@@ -39,7 +39,7 b''
39 39 % if c.rhodecode_user.username != h.DEFAULT_USER:
40 40 <div class="pull-right">
41 41 <a class="btn btn-primary" href="${h.route_path('gists_new')}" >
42 ${_(u'Create New Gist')}
42 ${_('Create New Gist')}
43 43 </a>
44 44 </div>
45 45 % endif
@@ -61,7 +61,7 b''
61 61 create_url = h.route_path('global_integrations_new')
62 62 %>
63 63 <p class="pull-right">
64 <a href="${create_url}" class="btn btn-small btn-success">${_(u'Create new integration')}</a>
64 <a href="${create_url}" class="btn btn-small btn-success">${_('Create new integration')}</a>
65 65 </p>
66 66
67 67 <table class="rctable integrations">
@@ -99,7 +99,7 b''
99 99 %>
100 100 %endif
101 101
102 <a href="${create_url}">${_(u'Create one')}</a>
102 <a href="${create_url}">${_('Create one')}</a>
103 103 </td>
104 104 </tr>
105 105 %endif
@@ -39,7 +39,7 b''
39 39 <td class="delegated-admin-repo-groups">${len(c.auth_user.repository_groups_admin)}</td>
40 40 <td>
41 41 % if c.can_create_repo_group:
42 <a href="${h.route_path('repo_group_new')}" class="">${_(u'Add Repository Group')}</a>
42 <a href="${h.route_path('repo_group_new')}" class="">${_('Add Repository Group')}</a>
43 43 % endif
44 44 </td>
45 45 </tr>
@@ -48,7 +48,7 b''
48 48 <td class="delegated-admin-user-groups">${len(c.auth_user.user_groups_admin)}</td>
49 49 <td>
50 50 % if c.can_create_user_group:
51 <a href="${h.route_path('user_groups_new')}" class="">${_(u'Add User Group')}</a>
51 <a href="${h.route_path('user_groups_new')}" class="">${_('Add User Group')}</a>
52 52 % endif
53 53 </td>
54 54 </tr>
@@ -27,7 +27,7 b''
27 27 <ul class="links">
28 28 %if c.can_create_repo_group:
29 29 <li>
30 <a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-success">${_(u'Add Repository Group')}</a>
30 <a href="${h.route_path('repo_group_new')}" class="btn btn-small btn-success">${_('Add Repository Group')}</a>
31 31 </li>
32 32 %endif
33 33 </ul>
@@ -27,7 +27,7 b''
27 27 <ul class="links">
28 28 %if c.can_create_repo:
29 29 <li>
30 <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success">${_(u'Add Repository')}</a>
30 <a href="${h.route_path('repo_new')}" class="btn btn-small btn-success">${_('Add Repository')}</a>
31 31 </li>
32 32 %endif
33 33 </ul>
@@ -27,7 +27,7 b''
27 27 <ul class="links">
28 28 %if c.can_create_user_group:
29 29 <li>
30 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_(u'Add User Group')}</a>
30 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_('Add User Group')}</a>
31 31 </li>
32 32 %endif
33 33 </ul>
@@ -27,7 +27,7 b''
27 27
28 28 <ul class="links">
29 29 <li>
30 <a href="${h.route_path('users_new')}" class="btn btn-small btn-success">${_(u'Add User')}</a>
30 <a href="${h.route_path('users_new')}" class="btn btn-small btn-success">${_('Add User')}</a>
31 31 </li>
32 32 </ul>
33 33 </div>
@@ -107,7 +107,7 b''
107 107
108 108 <ul id="context-pages" class="navigation horizontal-list">
109 109
110 ## super-admin case
110 ## super-admin case (Top Menu)
111 111 % if c.is_super_admin:
112 112 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
113 113 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
@@ -115,6 +115,8 b''
115 115 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
116 116 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
117 117 <li class="${h.is_active('artifacts', active)}"><a href="${h.route_path('admin_artifacts')}">${_('Artifacts')}</a></li>
118 <li class="${h.is_active('automation', active)}"><a href="${h.route_path('admin_automation')}">${_('Automation')}</a></li>
119 <li class="${h.is_active('scheduler', active)}"><a href="${h.route_path('admin_scheduler')}">${_('Scheduler')}</a></li>
118 120 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
119 121 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
120 122 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
@@ -540,7 +542,7 b''
540 542
541 543 % if can_create_repo_groups_in_group:
542 544 <li>
543 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
545 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository Group')}</a>
544 546 </li>
545 547 % endif
546 548 % endif
@@ -568,12 +570,12 b''
568 570
569 571 % if can_create_repo_groups:
570 572 <li>
571 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
573 <a href="${h.route_path('repo_group_new')}" >${_('New Repository Group')}</a>
572 574 </li>
573 575 % endif
574 576
575 577 <li>
576 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
578 <a href="${h.route_path('gists_new')}">${_('New Gist')}</a>
577 579 </li>
578 580
579 581 </ol>
General Comments 0
You need to be logged in to leave comments. Login now