Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-14 03:17:46 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-14 03:17:46 +0300
commit270353e1ff556a43333f82f171c3a485958126f0 (patch)
treec7bb4ac335b1e101b9bf92905ec2e8e170c6696c /app
parentb2e3da6a38f143a8c782dae4baceae3ed764733d (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/code_block.vue2
-rw-r--r--app/assets/javascripts/jira_connect/subscriptions/pages/sign_in/sign_in_gitlab_multiversion/index.vue2
-rw-r--r--app/assets/javascripts/lib/graphql.js9
-rw-r--r--app/assets/javascripts/main.js6
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js11
-rw-r--r--app/assets/javascripts/repository/index.js3
-rw-r--r--app/assets/javascripts/search/index.js1
-rw-r--r--app/assets/javascripts/search/store/constants.js12
-rw-r--r--app/assets/javascripts/search/store/getters.js13
-rw-r--r--app/assets/javascripts/search/store/index.js4
-rw-r--r--app/assets/javascripts/search/store/state.js3
-rw-r--r--app/assets/javascripts/search/store/utils.js4
-rw-r--r--app/assets/javascripts/sidebar/utils.js2
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue23
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_todo.vue4
-rw-r--r--app/graphql/resolvers/paginated_tree_resolver.rb2
-rw-r--r--app/helpers/nav_helper.rb2
-rw-r--r--app/helpers/sidebars_helper.rb4
-rw-r--r--app/models/application_setting_implementation.rb2
-rw-r--r--app/models/concerns/has_user_type.rb4
-rw-r--r--app/models/integrations/harbor.rb5
-rw-r--r--app/models/todo.rb2
-rw-r--r--app/models/user.rb11
-rw-r--r--app/policies/base_policy.rb6
-rw-r--r--app/services/work_items/parent_links/create_service.rb13
-rw-r--r--app/services/work_items/parent_links/destroy_service.rb10
-rw-r--r--app/views/dashboard/todos/index.html.haml1
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml300
-rw-r--r--app/views/projects/blob/_blob.html.haml2
-rw-r--r--app/views/shared/nav/_admin_scope_header.html.haml6
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')