diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-14 03:17:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-14 03:17:46 +0300 |
commit | 270353e1ff556a43333f82f171c3a485958126f0 (patch) | |
tree | c7bb4ac335b1e101b9bf92905ec2e8e170c6696c /app | |
parent | b2e3da6a38f143a8c782dae4baceae3ed764733d (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
30 files changed, 143 insertions, 326 deletions
diff --git a/app/assets/javascripts/content_editor/components/wrappers/code_block.vue b/app/assets/javascripts/content_editor/components/wrappers/code_block.vue index 81f9b1f0af5..55cf38dfcbb 100644 --- a/app/assets/javascripts/content_editor/components/wrappers/code_block.vue +++ b/app/assets/javascripts/content_editor/components/wrappers/code_block.vue @@ -80,7 +80,7 @@ export default { <template> <editor-state-observer @transaction="updateDiagramPreview"> <node-view-wrapper - :class="`content-editor-code-block gl-relative code highlight ${$options.userColorScheme}`" + :class="`content-editor-code-block gl-relative code highlight gl-p-3 ${$options.userColorScheme}`" as="pre" > <div diff --git a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue index 7c6ff002014..373c5970e64 100644 --- a/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue +++ b/app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue @@ -42,8 +42,8 @@ export default { }, mounted() { this.gitlabBasePath = retrieveBaseUrl(); - setApiBaseURL(this.gitlabBasePath); if (this.gitlabBasePath !== GITLAB_COM_BASE_PATH) { + setApiBaseURL(this.gitlabBasePath); this.showSetupInstructions = true; } }, diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js index dee8d11c065..2e6fcbea80d 100644 --- a/app/assets/javascripts/lib/graphql.js +++ b/app/assets/javascripts/lib/graphql.js @@ -53,6 +53,15 @@ export const typePolicies = { TreeEntry: { keyFields: ['webPath'], }, + Subscription: { + fields: { + aiCompletionResponse: { + read(value) { + return value ?? null; + }, + }, + }, + }, }; export const stripWhitespaceFromQuery = (url, path) => { diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index a1539aba786..fd002e29afc 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -89,9 +89,11 @@ initRails(); function deferredInitialisation() { const $body = $('body'); - if (!gon.use_new_navigation) initTopNav(); + if (!gon.use_new_navigation) { + initTopNav(); + initTodoToggle(); + } initBreadcrumbs(); - initTodoToggle(); initPrefetchLinks('.js-prefetch-document'); initLogoAnimation(); initServicePingConsent(); diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index 6d5460da2e5..dee13f60008 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -61,7 +61,14 @@ const initRefSwitcher = () => { initRefSwitcher(); if (viewBlobEl) { - const { blobPath, projectPath, targetBranch, originalBranch } = viewBlobEl.dataset; + const { + blobPath, + projectPath, + targetBranch, + originalBranch, + resourceId, + userId, + } = viewBlobEl.dataset; // eslint-disable-next-line no-new new Vue({ @@ -72,6 +79,8 @@ if (viewBlobEl) { provide: { targetBranch, originalBranch, + resourceId, + userId, }, render(createElement) { return createElement(BlobContentViewer, { diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index b5568393313..294c0c13648 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -32,7 +32,7 @@ Vue.use(PerformancePlugin, { export default function setupVueRepositoryList() { const el = document.getElementById('js-tree-list'); const { dataset } = el; - const { projectPath, projectShortPath, ref, escapedRef, fullName } = dataset; + const { projectPath, projectShortPath, ref, escapedRef, fullName, resourceId, userId } = dataset; const router = createRouter(projectPath, escapedRef); apolloProvider.clients.defaultClient.cache.writeQuery({ @@ -281,6 +281,7 @@ export default function setupVueRepositoryList() { store: createStore(), router, apolloProvider, + provide: { resourceId, userId }, render(h) { return h(App); }, diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js index d71785d7fac..1e4b1e36514 100644 --- a/app/assets/javascripts/search/index.js +++ b/app/assets/javascripts/search/index.js @@ -15,6 +15,7 @@ export const initSearchApp = () => { const store = createStore({ query, navigation, + useNewNavigation: gon.use_new_navigation, }); initTopbar(store); diff --git a/app/assets/javascripts/search/store/constants.js b/app/assets/javascripts/search/store/constants.js index 3f586c5fed8..c8ee0a3f9d9 100644 --- a/app/assets/javascripts/search/store/constants.js +++ b/app/assets/javascripts/search/store/constants.js @@ -17,3 +17,15 @@ export const SIDEBAR_PARAMS = [ ]; export const NUMBER_FORMATING_OPTIONS = { notation: 'compact', compactDisplay: 'short' }; + +export const ICON_MAP = { + blobs: 'code', + issues: 'issues', + merge_requests: 'merge-request', + commits: 'commit', + notes: 'comments', + milestones: 'tag', + users: 'users', + projects: 'project', + wiki_blobs: 'overview', +}; diff --git a/app/assets/javascripts/search/store/getters.js b/app/assets/javascripts/search/store/getters.js index 0e387607af7..135c9a3d67c 100644 --- a/app/assets/javascripts/search/store/getters.js +++ b/app/assets/javascripts/search/store/getters.js @@ -1,7 +1,8 @@ import { findKey, has } from 'lodash'; import { languageFilterData } from '~/search/sidebar/components/language_filter/data'; +import { formatSearchResultCount, addCountOverLimit } from '~/search/store/utils'; -import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; +import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, ICON_MAP } from './constants'; export const frequentGroups = (state) => { return state.frequentItems[GROUPS_LOCAL_STORAGE_KEY]; @@ -26,3 +27,13 @@ export const queryLanguageFilters = (state) => state.query[languageFilterData.fi export const currentUrlQueryHasLanguageFilters = (state) => has(state.urlQuery, languageFilterData.filterParam) && state.urlQuery[languageFilterData.filterParam]?.length > 0; + +export const navigationItems = (state) => + Object.values(state.navigation).map((item) => ({ + title: item.label, + icon: ICON_MAP[item.scope] || '', + link: item.link, + is_active: Boolean(item?.active), + pill_count: `${formatSearchResultCount(item?.count)}${addCountOverLimit(item?.count)}` || '', + items: [], + })); diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js index e20a43808cf..634f8f7a7fa 100644 --- a/app/assets/javascripts/search/store/index.js +++ b/app/assets/javascripts/search/store/index.js @@ -7,11 +7,11 @@ import createState from './state'; Vue.use(Vuex); -export const getStoreConfig = ({ query, navigation }) => ({ +export const getStoreConfig = ({ query, navigation, useNewNavigation }) => ({ actions, getters, mutations, - state: createState({ query, navigation }), + state: createState({ query, navigation, useNewNavigation }), }); const createStore = (config) => new Vuex.Store(getStoreConfig(config)); diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js index d85a135bb4e..a62b6728819 100644 --- a/app/assets/javascripts/search/store/state.js +++ b/app/assets/javascripts/search/store/state.js @@ -1,7 +1,7 @@ import { cloneDeep } from 'lodash'; import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; -const createState = ({ query, navigation }) => ({ +const createState = ({ query, navigation, useNewNavigation }) => ({ urlQuery: cloneDeep(query), query, groups: [], @@ -14,6 +14,7 @@ const createState = ({ query, navigation }) => ({ }, sidebarDirty: false, navigation, + useNewNavigation, aggregations: { error: false, fetching: false, diff --git a/app/assets/javascripts/search/store/utils.js b/app/assets/javascripts/search/store/utils.js index 9d1743e64ad..2f02ef3475c 100644 --- a/app/assets/javascripts/search/store/utils.js +++ b/app/assets/javascripts/search/store/utils.js @@ -144,3 +144,7 @@ export const prepareSearchAggregations = (state, aggregationData) => return item; }); + +export const addCountOverLimit = (count = '') => { + return count.includes('+') ? '+' : ''; +}; diff --git a/app/assets/javascripts/sidebar/utils.js b/app/assets/javascripts/sidebar/utils.js index 6b90fb80abf..a61b4e4f066 100644 --- a/app/assets/javascripts/sidebar/utils.js +++ b/app/assets/javascripts/sidebar/utils.js @@ -12,7 +12,7 @@ export const updateGlobalTodoCount = (additionalTodoCount) => { if (countContainer === null) return; - const currentCount = parseInt(countContainer.innerText, 10); + const currentCount = parseInt(countContainer.innerText, 10) || 0; const todoToggleEvent = new CustomEvent('todo:toggle', { detail: { diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue index b69ebc6be17..e96b896825a 100644 --- a/app/assets/javascripts/super_sidebar/components/user_bar.vue +++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue @@ -2,6 +2,7 @@ import { GlBadge, GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui'; import { __, s__, sprintf } from '~/locale'; import SafeHtml from '~/vue_shared/directives/safe_html'; +import { highCountTrim } from '~/lib/utils/text_utility'; import logo from '../../../../views/shared/_logo.svg'; import { toggleSuperSidebarCollapsed } from '../super_sidebar_collapsed_state_manager'; import CreateMenu from './create_menu.vue'; @@ -59,12 +60,27 @@ export default { data() { return { mrMenuShown: false, + todoCount: this.sidebarData.todos_pending_count, }; }, + computed: { + formattedTodoCount() { + return highCountTrim(this.todoCount); + }, + }, + mounted() { + document.addEventListener('todo:toggle', this.updateTodos); + }, + beforeDestroy() { + document.removeEventListener('todo:toggle', this.updateTodos); + }, methods: { collapseSidebar() { toggleSuperSidebarCollapsed(true, true, true); }, + updateTodos(e) { + this.todoCount = e.detail.count || 0; + }, }, }; </script> @@ -94,8 +110,9 @@ export default { :href="sidebarData.canary_toggle_com_url" size="sm" class="gl-ml-2" - >{{ $options.NEXT_LABEL }}</gl-badge > + {{ $options.NEXT_LABEL }} + </gl-badge> <div class="gl-flex-grow-1"></div> <gl-button v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.collapseSidebar" @@ -165,9 +182,9 @@ export default { </merge-request-menu> <counter v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.todoList" - class="gl-flex-basis-third shortcuts-todos" + class="gl-flex-basis-third shortcuts-todos js-todos-count" icon="todo-done" - :count="sidebarData.todos_pending_count" + :count="formattedTodoCount" href="/dashboard/todos" :label="$options.i18n.todoList" data-qa-selector="todos_shortcut_button" diff --git a/app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_todo.vue b/app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_todo.vue index f2c27cf611e..0577279cdd0 100644 --- a/app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_todo.vue +++ b/app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_todo.vue @@ -53,11 +53,11 @@ export default { }, methods: { updateToDoCount(add) { - const oldCount = parseInt(document.querySelector('.js-todos-count').innerText, 10); + const oldCount = parseInt(document.querySelector('.js-todos-count').innerText, 10) || 0; const count = add ? oldCount + 1 : oldCount - 1; const headerTodoEvent = new CustomEvent('todo:toggle', { detail: { - count, + count: Math.max(count, 0), }, }); diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb index 6c4e978125e..8fd80b1a9b9 100644 --- a/app/graphql/resolvers/paginated_tree_resolver.rb +++ b/app/graphql/resolvers/paginated_tree_resolver.rb @@ -22,7 +22,7 @@ module Resolvers alias_method :repository, :object def resolve(**args) - return unless repository.exists? + return if repository.empty? cursor = args.delete(:after) args[:ref] ||= :head diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index 88f1ef1a8a8..b101f184ca6 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -97,7 +97,7 @@ module NavHelper def super_sidebar_supported? return true if @nav.nil? - %w(your_work explore project group profile user_profile search).include?(@nav) + %w(your_work explore project group profile user_profile search admin).include?(@nav) end def get_header_links diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb index 8af4204e5e1..bf223cfe41c 100644 --- a/app/helpers/sidebars_helper.rb +++ b/app/helpers/sidebars_helper.rb @@ -65,7 +65,7 @@ module SidebarsHelper can_sign_out: current_user_menu?(:sign_out), sign_out_link: destroy_user_session_path, assigned_open_issues_count: format_user_bar_count(user.assigned_open_issues_count), - todos_pending_count: format_user_bar_count(user.todos_pending_count), + todos_pending_count: user.todos_pending_count, issues_dashboard_path: issues_dashboard_path(assignee_username: user.username), total_merge_requests_count: format_user_bar_count(user_merge_requests_counts[:total]), create_new_menu_groups: create_new_menu_groups(group: group, project: project), @@ -116,6 +116,8 @@ module SidebarsHelper when 'search' context = Sidebars::Context.new(current_user: user, container: nil, **context_adds) Sidebars::Search::Panel.new(context) + when 'admin' + Sidebars::Admin::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds)) else context = your_work_sidebar_context(user, **context_adds) Sidebars::YourWork::Panel.new(context) diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index b8d6434d9c9..010c88179df 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -97,7 +97,7 @@ module ApplicationSettingImplementation group_import_limit: 6, help_page_hide_commercial_content: false, help_page_text: nil, - help_page_documentation_base_url: nil, + help_page_documentation_base_url: 'https://docs.gitlab.com', hide_third_party_offers: false, housekeeping_enabled: true, housekeeping_full_repack_period: 50, diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb index 795ba94776b..468ea26c51a 100644 --- a/app/models/concerns/has_user_type.rb +++ b/app/models/concerns/has_user_type.rb @@ -18,7 +18,8 @@ module HasUserType security_policy_bot: 10, # Currently not in use. See https://gitlab.com/gitlab-org/gitlab/-/issues/384174 admin_bot: 11, suggested_reviewers_bot: 12, - service_account: 13 + service_account: 13, + llm_bot: 14 }.with_indifferent_access.freeze BOT_USER_TYPES = %w[ @@ -33,6 +34,7 @@ module HasUserType admin_bot suggested_reviewers_bot service_account + llm_bot ].freeze # `service_account` allows instance/namespaces to configure a user for external integrations/automations diff --git a/app/models/integrations/harbor.rb b/app/models/integrations/harbor.rb index 01a04743d5d..079811e0df0 100644 --- a/app/models/integrations/harbor.rb +++ b/app/models/integrations/harbor.rb @@ -17,7 +17,8 @@ module Integrations field :project_name, title: -> { s_('HarborIntegration|Harbor project name') }, - help: -> { s_('HarborIntegration|The name of the project in Harbor.') } + help: -> { s_('HarborIntegration|The name of the project in Harbor.') }, + required: true field :username, title: -> { s_('HarborIntegration|Harbor username') }, @@ -62,7 +63,7 @@ module Integrations end def test(*_args) - client.ping + client.check_project_availability end def ci_variables diff --git a/app/models/todo.rb b/app/models/todo.rb index 62252912c32..ac41b5d0b2c 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -76,7 +76,7 @@ class Todo < ApplicationRecord scope :for_target, -> (id) { where(target_id: id) } scope :for_commit, -> (id) { where(commit_id: id) } scope :with_entity_associations, -> do - preload(:target, :author, :note, group: :route, project: [:route, { namespace: [:route, :owner] }, :project_setting]) + preload(:target, :author, :note, group: :route, project: [:route, :group, { namespace: [:route, :owner] }, :project_setting]) end scope :joins_issue_and_assignees, -> { left_joins(issue: :assignees) } scope :for_internal_notes, -> { joins(:note).where(note: { confidential: true }) } diff --git a/app/models/user.rb b/app/models/user.rb index 71ea185b6f1..044c9d3c24b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -924,6 +924,17 @@ class User < ApplicationRecord end end + def llm_bot + email_pattern = "llm-bot%s@#{Settings.gitlab.host}" + + unique_internal(where(user_type: :llm_bot), 'GitLab-Llm-Bot', email_pattern) do |u| + u.bio = 'The Gitlab LLM bot used for fetching LLM-generated content' + u.name = 'GitLab LLM Bot' + u.avatar = bot_avatar(image: 'support-bot.png') # todo: add an avatar for llm-bot + u.confirmed_at = Time.zone.now + end + end + def admin_bot email_pattern = "admin-bot%s@#{Settings.gitlab.host}" diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index 1ce866bd910..7c745c5731f 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -39,6 +39,10 @@ class BasePolicy < DeclarativePolicy::Base with_options scope: :user, score: 0 condition(:automation_bot) { @user&.automation_bot? } + desc "User is llm bot" + with_options scope: :user, score: 0 + condition(:llm_bot) { @user&.llm_bot? } + desc "User email is unconfirmed or user account is locked" with_options scope: :user, score: 0 condition(:inactive) { @user&.confirmation_required_on_sign_in? || @user&.access_locked? } @@ -63,7 +67,7 @@ class BasePolicy < DeclarativePolicy::Base end rule { admin }.policy do - # Only for actual administrator accounts, behaviour affected by admin mode application setting + # Only for actual administrator accounts, behavior affected by admin mode application setting enable :admin_all_resources # Policy extended in EE to also enable auditors enable :read_all_resources diff --git a/app/services/work_items/parent_links/create_service.rb b/app/services/work_items/parent_links/create_service.rb index 60747daa5f8..4747d2f17e4 100644 --- a/app/services/work_items/parent_links/create_service.rb +++ b/app/services/work_items/parent_links/create_service.rb @@ -10,7 +10,18 @@ module WorkItems link = set_parent(issuable, work_item) link.move_to_end - create_notes(work_item) if link.changed? && link.save + + if link.changed? && link.save + relate_child_note = create_notes(work_item) + + ResourceLinkEvent.create( + user: current_user, + work_item: link.work_item_parent, + child_work_item: link.work_item, + action: ResourceLinkEvent.actions[:add], + system_note_metadata_id: relate_child_note&.system_note_metadata&.id + ) + end link end diff --git a/app/services/work_items/parent_links/destroy_service.rb b/app/services/work_items/parent_links/destroy_service.rb index 19770b3e4b5..97145d0b360 100644 --- a/app/services/work_items/parent_links/destroy_service.rb +++ b/app/services/work_items/parent_links/destroy_service.rb @@ -15,7 +15,15 @@ module WorkItems private def create_notes - SystemNoteService.unrelate_work_item(parent, child, current_user) + unrelate_note = SystemNoteService.unrelate_work_item(parent, child, current_user) + + ResourceLinkEvent.create( + user: @current_user, + work_item: @link.work_item_parent, + child_work_item: @link.work_item, + action: ResourceLinkEvent.actions[:remove], + system_note_metadata_id: unrelate_note&.system_note_metadata&.id + ) end def not_found_message diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index 10b1e257ac6..ca6b1071f03 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -2,6 +2,7 @@ = render_two_factor_auth_recovery_settings_check = render_dashboard_ultimate_trial(current_user) += render_if_exists 'dashboard/todos/saml_reauth_notice' - add_page_specific_style 'page_bundles/todos' - add_page_specific_style 'page_bundles/issuable' diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 2d61e403623..bffc030dbd9 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -1,299 +1 @@ -%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), 'aria-label': _('Admin navigation'), data: { qa_selector: 'admin_sidebar_content' } } - .nav-sidebar-inner-scroll - .context-header - = link_to admin_root_path, title: _('Admin Overview'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do - %span{ class: ['avatar-container', 'settings-avatar', 'rect-avatar', 's32'] } - = sprite_icon('admin', size: 18) - %span.sidebar-context-title - = _('Admin Area') - %ul.sidebar-top-level-items{ data: { qa_selector: 'admin_overview_submenu_content' } } - = nav_link(controller: %w[dashboard admin admin/projects users groups admin/topics gitaly_servers cohorts], html_options: {class: 'home'}) do - = link_to admin_root_path, class: 'has-sub-items' do - .nav-icon-container - = sprite_icon('overview') - %span.nav-item-name - = _('Overview') - %ul.sidebar-sub-level-items - = nav_link(controller: %w[dashboard admin admin/projects users groups gitaly_servers cohorts], html_options: { class: "fly-out-top-item" }) do - = link_to admin_root_path do - %strong.fly-out-top-item-name - = _('Overview') - %li.divider.fly-out-top-item - = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to admin_root_path, title: _('Overview') do - %span - = _('Dashboard') - = nav_link(controller: [:admin, 'admin/projects']) do - = link_to admin_projects_path, title: _('Projects') do - %span - = _('Projects') - = nav_link(controller: %w[users cohorts]) do - = link_to admin_users_path, title: _('Users'), data: { qa_selector: 'admin_overview_users_link' } do - %span - = _('Users') - = nav_link(controller: :groups) do - = link_to admin_groups_path, title: _('Groups'), data: { qa_selector: 'admin_overview_groups_link' } do - %span - = _('Groups') - = nav_link(controller: [:admin, 'admin/topics']) do - = link_to admin_topics_path, title: _('Topics') do - %span - = _('Topics') - = nav_link(controller: :gitaly_servers) do - = link_to admin_gitaly_servers_path, title: 'Gitaly Servers' do - %span - = _('Gitaly Servers') - - = nav_link(controller: %w[runners jobs]) do - = link_to admin_runners_path, class: 'has-sub-items' do - .nav-icon-container - = sprite_icon('rocket') - %span.nav-item-name - = _('CI/CD') - %ul.sidebar-sub-level-items - = nav_link(controller: %w[runners jobs], html_options: { class: "fly-out-top-item" }) do - = link_to admin_runners_path do - %strong.fly-out-top-item-name - = _('CI/CD') - %li.divider.fly-out-top-item - = nav_link(controller: :runners) do - = link_to admin_runners_path, title: _('Runners') do - %span - = _('Runners') - = nav_link(controller: :jobs) do - = link_to admin_jobs_path, title: _('Jobs') do - %span - = _('Jobs') - - = nav_link(controller: admin_analytics_nav_links) do - = link_to admin_dev_ops_reports_path, data: { qa_selector: 'admin_analytics_link' }, class: 'has-sub-items' do - .nav-icon-container - = sprite_icon('chart') - %span.nav-item-name - = _('Analytics') - - %ul.sidebar-sub-level-items{ data: { qa_selector: 'admin_sidebar_analytics_submenu_content' } } - = nav_link(controller: admin_analytics_nav_links, html_options: { class: "fly-out-top-item" }) do - = link_to admin_dev_ops_reports_path do - %strong.fly-out-top-item-name - = _('Analytics') - %li.divider.fly-out-top-item - = nav_link(controller: :dev_ops_report) do - = link_to admin_dev_ops_reports_path, title: _('DevOps Reports') do - %span - = _('DevOps Reports') - = nav_link(controller: :usage_trends) do - = link_to admin_usage_trends_path, title: _('Usage Trends') do - %span - = _('Usage Trends') - - = nav_link(controller: admin_monitoring_nav_links) do - = link_to admin_system_info_path, data: { qa_selector: 'admin_monitoring_menu_link' }, class: 'has-sub-items' do - .nav-icon-container - = sprite_icon('monitor') - %span.nav-item-name - = _('Monitoring') - - %ul.sidebar-sub-level-items{ data: { qa_selector: 'admin_monitoring_submenu_content' } } - = nav_link(controller: admin_monitoring_nav_links, html_options: { class: "fly-out-top-item" }) do - = link_to admin_system_info_path do - %strong.fly-out-top-item-name - = _('Monitoring') - %li.divider.fly-out-top-item - = nav_link(controller: :system_info) do - = link_to admin_system_info_path, title: _('System Info') do - %span - = _('System Info') - = nav_link(controller: :background_migrations) do - = link_to admin_background_migrations_path, title: _('Background Migrations') do - %span - = _('Background Migrations') - = nav_link(controller: :background_jobs) do - = link_to admin_background_jobs_path, title: _('Background Jobs') do - %span - = _('Background Jobs') - = nav_link(controller: :health_check) do - = link_to admin_health_check_path, title: _('Health Check') do - %span - = _('Health Check') - - if Gitlab::CurrentSettings.current_application_settings.grafana_enabled? - = nav_link do - = link_to Gitlab::CurrentSettings.current_application_settings.grafana_url, target: '_blank', title: _('Metrics Dashboard'), rel: 'noopener noreferrer' do - %span - = _('Metrics Dashboard') - = render_if_exists 'layouts/nav/ee/admin/new_monitoring_sidebar' - - = nav_link(controller: :broadcast_messages) do - = link_to admin_broadcast_messages_path do - .nav-icon-container - = sprite_icon('messages') - %span.nav-item-name - = _('Messages') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :broadcast_messages, html_options: { class: "fly-out-top-item" }) do - = link_to admin_broadcast_messages_path do - %strong.fly-out-top-item-name - = _('Messages') - - = nav_link(controller: [:hooks, :hook_logs]) do - = link_to admin_hooks_path do - .nav-icon-container - = sprite_icon('hook') - %span.nav-item-name - = _('System Hooks') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: [:hooks, :hook_logs], html_options: { class: "fly-out-top-item" }) do - = link_to admin_hooks_path do - %strong.fly-out-top-item-name - = _('System Hooks') - - = nav_link(controller: :applications) do - = link_to admin_applications_path do - .nav-icon-container - = sprite_icon('applications') - %span.nav-item-name - = _('Applications') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :applications, html_options: { class: "fly-out-top-item" }) do - = link_to admin_applications_path do - %strong.fly-out-top-item-name - = _('Applications') - - = nav_link(controller: :abuse_reports) do - = link_to admin_abuse_reports_path do - .nav-icon-container - = sprite_icon('slight-frown') - %span.nav-item-name - = _('Abuse Reports') - = gl_badge_tag number_with_delimiter(AbuseReport.count(:all)), variant: :info, size: :sm - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :abuse_reports, html_options: { class: "fly-out-top-item" }) do - = link_to admin_abuse_reports_path do - %strong.fly-out-top-item-name - = _('Abuse Reports') - = gl_badge_tag number_with_delimiter(AbuseReport.count(:all)), variant: :info, size: :sm - - = render_if_exists 'layouts/nav/sidebar/licenses_link' - - - if instance_clusters_enabled? - = nav_link(controller: :clusters) do - = link_to admin_clusters_path do - .nav-icon-container - = sprite_icon('cloud-gear') - %span.nav-item-name - = _('Kubernetes') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :clusters, html_options: { class: "fly-out-top-item" }) do - = link_to admin_clusters_path do - %strong.fly-out-top-item-name - = _('Kubernetes') - - - if anti_spam_service_enabled? - = nav_link(controller: :spam_logs) do - = link_to admin_spam_logs_path do - .nav-icon-container - = sprite_icon('spam') - %span.nav-item-name - = _('Spam Logs') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :spam_logs, html_options: { class: "fly-out-top-item" }) do - = link_to admin_spam_logs_path do - %strong.fly-out-top-item-name - = _('Spam Logs') - - = render_if_exists 'layouts/nav/sidebar/push_rules_link' - - = render_if_exists 'layouts/nav/ee/admin/geo_sidebar' - - = nav_link(controller: :deploy_keys) do - = link_to admin_deploy_keys_path do - .nav-icon-container - = sprite_icon('key') - %span.nav-item-name - = _('Deploy Keys') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :deploy_keys, html_options: { class: "fly-out-top-item" }) do - = link_to admin_deploy_keys_path do - %strong.fly-out-top-item-name - = _('Deploy Keys') - - = render_if_exists 'layouts/nav/sidebar/credentials_link' - - = nav_link(controller: :labels) do - = link_to admin_labels_path do - .nav-icon-container - = sprite_icon('labels') - %span.nav-item-name - = _('Labels') - %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :labels, html_options: { class: "fly-out-top-item" }) do - = link_to admin_labels_path do - %strong.fly-out-top-item-name - = _('Labels') - - = nav_link(controller: [:application_settings, :integrations, :appearances]) do - = link_to general_admin_application_settings_path, class: 'has-sub-items' do - .nav-icon-container - = sprite_icon('settings') - %span.nav-item-name{ data: { qa_selector: 'admin_settings_menu_link' } } - = _('Settings') - - %ul.sidebar-sub-level-items{ data: { qa_selector: 'admin_settings_submenu_content' } } - -# This active_nav_link check is also used in `app/views/layouts/admin.html.haml` - = nav_link(controller: [:application_settings, :integrations, :appearances], html_options: { class: "fly-out-top-item" }) do - = link_to general_admin_application_settings_path do - %strong.fly-out-top-item-name - = _('Settings') - %li.divider.fly-out-top-item - = nav_link(path: 'application_settings#general') do - = link_to general_admin_application_settings_path, title: _('General'), data: { qa_selector: 'admin_settings_general_link' } do - %span - = _('General') - - = render_if_exists 'layouts/nav/sidebar/advanced_search', data: { qa_selector: 'admin_settings_advanced_search_link' } - - - if instance_level_integrations? - = nav_link(path: ['application_settings#integrations', 'integrations#edit']) do - = link_to integrations_admin_application_settings_path, title: _('Integrations'), data: { qa_selector: 'admin_settings_integrations_link' } do - %span - = _('Integrations') - = nav_link(path: 'application_settings#repository') do - = link_to repository_admin_application_settings_path, title: _('Repository'), data: { qa_selector: 'admin_settings_repository_link' } do - %span - = _('Repository') - - if Gitlab.ee? && License.feature_available?(:custom_file_templates) - = nav_link(path: 'application_settings#templates') do - = link_to templates_admin_application_settings_path, title: _('Templates'), data: { qa_selector: 'admin_settings_templates_link' } do - %span - = _('Templates') - = nav_link(path: 'application_settings#ci_cd') do - = link_to ci_cd_admin_application_settings_path, title: _('CI/CD') do - %span - = _('CI/CD') - = render_if_exists 'layouts/nav/ee/admin/security_and_compliance_sidebar' - = nav_link(path: 'application_settings#reporting') do - = link_to reporting_admin_application_settings_path, title: _('Reporting') do - %span - = _('Reporting') - = nav_link(path: 'application_settings#metrics_and_profiling') do - = link_to metrics_and_profiling_admin_application_settings_path, title: _('Metrics and profiling'), data: { qa_selector: 'admin_settings_metrics_and_profiling_link' } do - %span - = _('Metrics and profiling') - = nav_link(path: ['application_settings#service_usage_data']) do - = link_to service_usage_data_admin_application_settings_path, title: _('Service usage data') do - %span - = _('Service usage data') - = nav_link(path: 'application_settings#network') do - = link_to network_admin_application_settings_path, title: _('Network'), data: { qa_selector: 'admin_settings_network_link' } do - %span - = _('Network') - = nav_link(controller: :appearances) do - = link_to admin_application_settings_appearances_path do - %span - = _('Appearance') - = nav_link(path: 'application_settings#preferences') do - = link_to preferences_admin_application_settings_path, title: _('Preferences'), data: { qa_selector: 'admin_settings_preferences_link' } do - %span - = _('Preferences') - - = render 'shared/sidebar_toggle_button' += render partial: 'shared/nav/sidebar', object: Sidebars::Admin::Panel.new(Sidebars::Context.new(current_user: current_user, container: nil)) diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 6565cd223e8..d11bf36a610 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -24,6 +24,8 @@ -# Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/330406 #js-view-blob-app{ data: { blob_path: blob.path, project_path: @project.full_path, + resource_id: @project.to_global_id, + user_id: current_user.present? ? current_user.to_global_id : '', target_branch: project.empty_repo? ? ref : @ref, original_branch: @ref } } = gl_loading_icon(size: 'md') diff --git a/app/views/shared/nav/_admin_scope_header.html.haml b/app/views/shared/nav/_admin_scope_header.html.haml new file mode 100644 index 00000000000..3a18b3660d4 --- /dev/null +++ b/app/views/shared/nav/_admin_scope_header.html.haml @@ -0,0 +1,6 @@ +%li.context-header + = link_to admin_root_path, title: _('Admin Area'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do + %span.avatar-container.icon-avatar.rect-avatar.s32 + = sprite_icon('admin', size: 18) + %span.sidebar-context-title + = _('Admin Area') |