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-07-18 00:10:31 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-18 00:10:31 +0300
commit9c2ea7751419fb5e50708ea3ef3677cd16c43c7c (patch)
tree39dcd6fef621203e39388391d86eec8acfb3a0b0 /app
parent16964a4834ac976228b3ad69c4eff813d8230d7a (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/admin/users/components/users_table.vue2
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/copy_paste.js8
-rw-r--r--app/assets/javascripts/tracking/constants.js1
-rw-r--r--app/assets/javascripts/tracking/index.js2
-rw-r--r--app/assets/javascripts/tracking/internal_events.js20
-rw-r--r--app/assets/javascripts/tracking/utils.js18
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue417
-rw-r--r--app/controllers/projects/ml/candidates_controller.rb10
-rw-r--r--app/controllers/projects/ml/experiments_controller.rb9
-rw-r--r--app/helpers/sorting_helper.rb11
-rw-r--r--app/policies/project_policy.rb4
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml6
-rw-r--r--app/views/admin/application_settings/_email.html.haml2
-rw-r--r--app/views/admin/application_settings/_runner_registrars_form.html.haml2
-rw-r--r--app/views/groups/settings/ci_cd/_form.html.haml2
-rw-r--r--app/views/projects/merge_requests/_widget.html.haml2
-rw-r--r--app/views/projects/project_templates/_template.html.haml2
-rw-r--r--app/views/projects/runners/_project_runners.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml2
20 files changed, 298 insertions, 228 deletions
diff --git a/app/assets/javascripts/admin/users/components/users_table.vue b/app/assets/javascripts/admin/users/components/users_table.vue
index 2d2c598f953..65737be1e67 100644
--- a/app/assets/javascripts/admin/users/components/users_table.vue
+++ b/app/assets/javascripts/admin/users/components/users_table.vue
@@ -109,7 +109,7 @@ export default {
:empty-text="s__('AdminUsers|No users found')"
show-empty
stacked="md"
- :tbody-tr-attr="{ 'data-qa-selector': 'user_row_content' }"
+ :tbody-tr-attr="{ 'data-testid': 'user-row-content' }"
>
<template #cell(name)="{ item: user }">
<user-avatar :user="user" :admin-user-path="paths.adminUser" />
diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index 6b50abe7014..ce77ede9fe4 100644
--- a/app/assets/javascripts/behaviors/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
@@ -4,7 +4,6 @@ import $ from 'jquery';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
-import { addMarkdownListeners, removeMarkdownListeners } from '~/lib/utils/text_markdown';
import { __ } from '~/locale';
// MarkdownPreview
@@ -129,8 +128,6 @@ $(document).on('markdown-preview:show', (e, $form) => {
return;
}
- removeMarkdownListeners($form);
-
lastTextareaPreviewed = $form.find('textarea.markdown-area');
lastTextareaHeight = lastTextareaPreviewed.height();
@@ -168,7 +165,6 @@ $(document).on('markdown-preview:hide', (e, $form) => {
$form.find('.haml-markdown-button, .js-zen-enter').removeClass('gl-display-none!');
markdownPreview.hideReferencedCommands($form);
- addMarkdownListeners($form);
});
$(document).on('markdown-preview:toggle', (e, keyboardEvent) => {
diff --git a/app/assets/javascripts/content_editor/extensions/copy_paste.js b/app/assets/javascripts/content_editor/extensions/copy_paste.js
index 45a89cc08cf..f484ce98e90 100644
--- a/app/assets/javascripts/content_editor/extensions/copy_paste.js
+++ b/app/assets/javascripts/content_editor/extensions/copy_paste.js
@@ -8,6 +8,7 @@ import { VARIANT_DANGER } from '~/alert';
import createMarkdownDeserializer from '../services/gl_api_markdown_deserializer';
import { ALERT_EVENT, EXTENSION_PRIORITY_HIGHEST } from '../constants';
import CodeBlockHighlight from './code_block_highlight';
+import CodeSuggestion from './code_suggestion';
import Diagram from './diagram';
import Frontmatter from './frontmatter';
@@ -15,7 +16,12 @@ const TEXT_FORMAT = 'text/plain';
const GFM_FORMAT = 'text/x-gfm';
const HTML_FORMAT = 'text/html';
const VS_CODE_FORMAT = 'vscode-editor-data';
-const CODE_BLOCK_NODE_TYPES = [CodeBlockHighlight.name, Diagram.name, Frontmatter.name];
+const CODE_BLOCK_NODE_TYPES = [
+ CodeBlockHighlight.name,
+ CodeSuggestion.name,
+ Diagram.name,
+ Frontmatter.name,
+];
function parseHTML(schema, html) {
const parser = new DOMParser();
diff --git a/app/assets/javascripts/tracking/constants.js b/app/assets/javascripts/tracking/constants.js
index 0e440750fdb..d0447fa167c 100644
--- a/app/assets/javascripts/tracking/constants.js
+++ b/app/assets/javascripts/tracking/constants.js
@@ -19,6 +19,7 @@ export const DEFAULT_SNOWPLOW_OPTIONS = {
export const ACTION_ATTR_SELECTOR = '[data-track-action]';
export const LOAD_ACTION_ATTR_SELECTOR = '[data-track-action="render"]';
+export const INTERNAL_EVENTS_SELECTOR = '[data-event-tracking]';
export const URLS_CACHE_STORAGE_KEY = 'gl-snowplow-pseudonymized-urls';
diff --git a/app/assets/javascripts/tracking/index.js b/app/assets/javascripts/tracking/index.js
index 6494838abac..7c2cd6fde27 100644
--- a/app/assets/javascripts/tracking/index.js
+++ b/app/assets/javascripts/tracking/index.js
@@ -69,4 +69,6 @@ export function initDefaultTrackers() {
Tracking.bindDocument();
Tracking.trackLoadEvents();
+
+ InternalEvents.bindInternalEventDocument();
}
diff --git a/app/assets/javascripts/tracking/internal_events.js b/app/assets/javascripts/tracking/internal_events.js
index 56453373bbf..16cbb3e86e1 100644
--- a/app/assets/javascripts/tracking/internal_events.js
+++ b/app/assets/javascripts/tracking/internal_events.js
@@ -2,6 +2,8 @@ import API from '~/api';
import Tracking from './tracking';
import { GITLAB_INTERNAL_EVENT_CATEGORY, SERVICE_PING_SCHEMA } from './constants';
+import { Tracker } from './tracker';
+import { InternalEventHandler } from './utils';
const InternalEvents = {
/**
@@ -33,6 +35,24 @@ const InternalEvents = {
},
};
},
+ /**
+ * Attaches event handlers for data-attributes powered events.
+ *
+ * @param {HTMLElement} parent - element containing data-attributes
+ * @returns {Object} handler - object containing name of the event and its corresponding function
+ */
+ bindInternalEventDocument(parent = document) {
+ if (!Tracker.enabled() || parent.internalEventsTrackingBound) {
+ return [];
+ }
+
+ // eslint-disable-next-line no-param-reassign
+ parent.internalEventsTrackingBound = true;
+
+ const handler = { name: 'click', func: (e) => InternalEventHandler(e, this.track_event) };
+ parent.addEventListener(handler.name, handler.func);
+ return handler;
+ },
};
export default InternalEvents;
diff --git a/app/assets/javascripts/tracking/utils.js b/app/assets/javascripts/tracking/utils.js
index cc0d7e7a44a..7cbc0f1843e 100644
--- a/app/assets/javascripts/tracking/utils.js
+++ b/app/assets/javascripts/tracking/utils.js
@@ -6,6 +6,7 @@ import {
LOAD_ACTION_ATTR_SELECTOR,
URLS_CACHE_STORAGE_KEY,
REFERRER_TTL,
+ INTERNAL_EVENTS_SELECTOR,
} from './constants';
export const addExperimentContext = (opts) => {
@@ -69,6 +70,23 @@ export const createEventPayload = (el, { suffix = '' } = {}) => {
};
};
+export const createInternalEventPayload = (el) => {
+ const { eventTracking } = el?.dataset || {};
+
+ return eventTracking;
+};
+
+export const InternalEventHandler = (e, func) => {
+ const el = e.target.closest(INTERNAL_EVENTS_SELECTOR);
+
+ if (!el) {
+ return;
+ }
+ const event = createInternalEventPayload(el);
+
+ func(event);
+};
+
export const eventHandler = (e, func, opts = {}) => {
const actionSelector = `${ACTION_ATTR_SELECTOR}:not(${LOAD_ACTION_ATTR_SELECTOR})`;
const el = e.target.closest(actionSelector);
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index 0c6a9c2fa98..a53d5049752 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -275,215 +275,232 @@ export default {
@click="switchPreview"
>{{ previewMarkdown ? $options.i18n.hidePreview : $options.i18n.preview }}</gl-button
>
- <template v-if="!previewMarkdown">
- <template v-if="canSuggest">
- <toolbar-button
- ref="suggestButton"
- :tag="mdSuggestion"
- :prepend="true"
- :button-title="__('Insert suggestion')"
- :cursor-offset="4"
- :tag-content="lineContent"
- icon="doc-code"
- data-qa-selector="suggestion_button"
- class="js-suggestion-btn"
- @click="handleSuggestDismissed"
- />
- <gl-popover
- v-if="suggestPopoverVisible"
- :target="$refs.suggestButton.$el"
- :css-classes="['diff-suggest-popover']"
- placement="bottom"
- :show="suggestPopoverVisible"
- triggers=""
- >
- <strong>{{ __('New! Suggest changes directly') }}</strong>
- <p class="mb-2">
- {{
- __(
- 'Suggest code changes which can be immediately applied in one click. Try it out!',
- )
- }}
- </p>
- <gl-button
- variant="confirm"
- category="primary"
- size="small"
- data-qa-selector="dismiss_suggestion_popover_button"
- @click="handleSuggestDismissed"
- >
- {{ __('Got it') }}
- </gl-button>
- </gl-popover>
- </template>
- <ai-actions-dropdown
- v-if="editorAiActions.length"
- :actions="editorAiActions"
- @input="insertAIAction"
- @replace="replaceTextarea"
- />
- <toolbar-button
- tag="**"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Add bold text (%{modifierKey}B)'), {
- modifierKey,
- }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
- "
- :shortcuts="$options.shortcuts.bold"
- icon="bold"
- />
- <toolbar-button
- tag="_"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Add italic text (%{modifierKey}I)'), {
- modifierKey,
- }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
- "
- :shortcuts="$options.shortcuts.italic"
- icon="italic"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('strikethrough')"
- tag="~~"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}%{shiftKey}X)'), {
- modifierKey,
- shiftKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
- })
- "
- :shortcuts="$options.shortcuts.strikethrough"
- icon="strikethrough"
- />
+ <template v-if="!previewMarkdown && canSuggest">
<toolbar-button
- v-if="!restrictedToolBarItems.includes('quote')"
+ ref="suggestButton"
+ :tag="mdSuggestion"
:prepend="true"
- :tag="tag"
- :button-title="__('Insert a quote')"
- icon="quote"
- @click="handleQuote"
- />
- <toolbar-button tag="`" tag-block="```" :button-title="__('Insert code')" icon="code" />
- <toolbar-button
- tag="[{text}](url)"
- tag-select="url"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Add a link (%{modifierKey}K)'), {
- modifierKey,
- }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
- "
- :shortcuts="$options.shortcuts.link"
- icon="link"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('bullet-list')"
- :prepend="true"
- tag="- "
- :button-title="__('Add a bullet list')"
- icon="list-bulleted"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('numbered-list')"
- :prepend="true"
- tag="1. "
- :button-title="__('Add a numbered list')"
- icon="list-numbered"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('task-list')"
- :prepend="true"
- tag="- [ ] "
- :button-title="__('Add a checklist')"
- icon="list-task"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('indent')"
- class="gl-display-none"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Indent line (%{modifierKey}])'), {
- modifierKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
- })
- "
- :shortcuts="$options.shortcuts.indent"
- command="indentLines"
- icon="list-indent"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('outdent')"
- class="gl-display-none"
- :button-title="
- /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
- sprintf(s__('MarkdownEditor|Outdent line (%{modifierKey}[)'), {
- modifierKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
- })
- "
- :shortcuts="$options.shortcuts.outdent"
- command="outdentLines"
- icon="list-outdent"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('collapsible-section')"
- :tag="mdCollapsibleSection"
- :prepend="true"
- tag-select="Click to expand"
- :button-title="__('Add a collapsible section')"
- icon="details-block"
- />
- <toolbar-button
- v-if="!restrictedToolBarItems.includes('table')"
- :tag="mdTable"
- :prepend="true"
- :button-title="__('Add a table')"
- icon="table"
+ :button-title="__('Insert suggestion')"
+ :cursor-offset="4"
+ :tag-content="lineContent"
+ icon="doc-code"
+ data-qa-selector="suggestion_button"
+ class="js-suggestion-btn"
+ @click="handleSuggestDismissed"
/>
+ <gl-popover
+ v-if="suggestPopoverVisible"
+ :target="$refs.suggestButton.$el"
+ :css-classes="['diff-suggest-popover']"
+ placement="bottom"
+ :show="suggestPopoverVisible"
+ triggers=""
+ >
+ <strong>{{ __('New! Suggest changes directly') }}</strong>
+ <p class="mb-2">
+ {{
+ __(
+ 'Suggest code changes which can be immediately applied in one click. Try it out!',
+ )
+ }}
+ </p>
+ <gl-button
+ variant="confirm"
+ category="primary"
+ size="small"
+ data-qa-selector="dismiss_suggestion_popover_button"
+ @click="handleSuggestDismissed"
+ >
+ {{ __('Got it') }}
+ </gl-button>
+ </gl-popover>
+ </template>
+ <ai-actions-dropdown
+ v-if="!previewMarkdown && editorAiActions.length"
+ :actions="editorAiActions"
+ @input="insertAIAction"
+ @replace="replaceTextarea"
+ />
+ <toolbar-button
+ v-show="!previewMarkdown"
+ tag="**"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Add bold text (%{modifierKey}B)'), {
+ modifierKey,
+ }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
+ "
+ :shortcuts="$options.shortcuts.bold"
+ icon="bold"
+ />
+ <toolbar-button
+ v-show="!previewMarkdown"
+ tag="_"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Add italic text (%{modifierKey}I)'), {
+ modifierKey,
+ }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
+ "
+ :shortcuts="$options.shortcuts.italic"
+ icon="italic"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('strikethrough')"
+ v-show="!previewMarkdown"
+ tag="~~"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}%{shiftKey}X)'), {
+ modifierKey,
+ shiftKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
+ })
+ "
+ :shortcuts="$options.shortcuts.strikethrough"
+ icon="strikethrough"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('quote')"
+ v-show="!previewMarkdown"
+ :prepend="true"
+ :tag="tag"
+ :button-title="__('Insert a quote')"
+ icon="quote"
+ @click="handleQuote"
+ />
+ <toolbar-button
+ v-show="!previewMarkdown"
+ tag="`"
+ tag-block="```"
+ :button-title="__('Insert code')"
+ icon="code"
+ />
+ <toolbar-button
+ v-show="!previewMarkdown"
+ tag="[{text}](url)"
+ tag-select="url"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Add a link (%{modifierKey}K)'), {
+ modifierKey,
+ }) /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */
+ "
+ :shortcuts="$options.shortcuts.link"
+ icon="link"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('bullet-list')"
+ v-show="!previewMarkdown"
+ :prepend="true"
+ tag="- "
+ :button-title="__('Add a bullet list')"
+ icon="list-bulleted"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('numbered-list')"
+ v-show="!previewMarkdown"
+ :prepend="true"
+ tag="1. "
+ :button-title="__('Add a numbered list')"
+ icon="list-numbered"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('task-list')"
+ v-show="!previewMarkdown"
+ :prepend="true"
+ tag="- [ ] "
+ :button-title="__('Add a checklist')"
+ icon="list-task"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('indent')"
+ v-show="!previewMarkdown"
+ class="gl-display-none"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Indent line (%{modifierKey}])'), {
+ modifierKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
+ })
+ "
+ :shortcuts="$options.shortcuts.indent"
+ command="indentLines"
+ icon="list-indent"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('outdent')"
+ v-show="!previewMarkdown"
+ class="gl-display-none"
+ :button-title="
+ /* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */
+ sprintf(s__('MarkdownEditor|Outdent line (%{modifierKey}[)'), {
+ modifierKey /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */,
+ })
+ "
+ :shortcuts="$options.shortcuts.outdent"
+ command="outdentLines"
+ icon="list-outdent"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('collapsible-section')"
+ v-show="!previewMarkdown"
+ :tag="mdCollapsibleSection"
+ :prepend="true"
+ tag-select="Click to expand"
+ :button-title="__('Add a collapsible section')"
+ icon="details-block"
+ />
+ <toolbar-button
+ v-if="!restrictedToolBarItems.includes('table')"
+ v-show="!previewMarkdown"
+ :tag="mdTable"
+ :prepend="true"
+ :button-title="__('Add a table')"
+ icon="table"
+ />
+ <gl-button
+ v-if="!previewMarkdown && !restrictedToolBarItems.includes('attach-file')"
+ v-gl-tooltip
+ :aria-label="__('Attach a file or image')"
+ :title="__('Attach a file or image')"
+ class="gl-mr-3"
+ data-testid="button-attach-file"
+ category="tertiary"
+ icon="paperclip"
+ size="small"
+ @click="handleAttachFile"
+ />
+ <drawio-toolbar-button
+ v-if="!previewMarkdown && drawioEnabled"
+ :uploads-path="uploadsPath"
+ :markdown-preview-path="markdownPreviewPath"
+ />
+ <!-- TODO Add icon and trigger functionality from here -->
+ <toolbar-button
+ v-if="supportsQuickActions"
+ v-show="!previewMarkdown"
+ :prepend="true"
+ tag="/"
+ :button-title="__('Add a quick action')"
+ icon="quick-actions"
+ />
+ <comment-templates-dropdown
+ v-if="!previewMarkdown && newCommentTemplatePath && glFeatures.savedReplies"
+ :new-comment-template-path="newCommentTemplatePath"
+ @select="insertSavedReply"
+ />
+ <div v-if="!previewMarkdown" class="full-screen">
<gl-button
- v-if="!restrictedToolBarItems.includes('attach-file')"
+ v-if="!restrictedToolBarItems.includes('full-screen')"
v-gl-tooltip
- :aria-label="__('Attach a file or image')"
- :title="__('Attach a file or image')"
- class="gl-mr-3"
- data-testid="button-attach-file"
+ class="js-zen-enter"
category="tertiary"
- icon="paperclip"
+ icon="maximize"
size="small"
- @click="handleAttachFile"
- />
- <drawio-toolbar-button
- v-if="drawioEnabled"
- :uploads-path="uploadsPath"
- :markdown-preview-path="markdownPreviewPath"
- />
- <!-- TODO Add icon and trigger functionality from here -->
- <toolbar-button
- v-if="supportsQuickActions"
+ :title="__('Go full screen')"
:prepend="true"
- tag="/"
- :button-title="__('Add a quick action')"
- icon="quick-actions"
- />
- <comment-templates-dropdown
- v-if="newCommentTemplatePath && glFeatures.savedReplies"
- :new-comment-template-path="newCommentTemplatePath"
- @select="insertSavedReply"
+ :aria-label="__('Go full screen')"
/>
- <div class="full-screen">
- <gl-button
- v-if="!restrictedToolBarItems.includes('full-screen')"
- v-gl-tooltip
- class="js-zen-enter"
- category="tertiary"
- icon="maximize"
- size="small"
- :title="__('Go full screen')"
- :prepend="true"
- :aria-label="__('Go full screen')"
- />
- </div>
- </template>
+ </div>
</div>
</div>
</div>
diff --git a/app/controllers/projects/ml/candidates_controller.rb b/app/controllers/projects/ml/candidates_controller.rb
index ed7155fc5f4..9905e454acb 100644
--- a/app/controllers/projects/ml/candidates_controller.rb
+++ b/app/controllers/projects/ml/candidates_controller.rb
@@ -3,7 +3,9 @@
module Projects
module Ml
class CandidatesController < ApplicationController
- before_action :check_feature_enabled, :set_candidate
+ before_action :set_candidate
+ before_action :check_read, only: [:show]
+ before_action :check_write, only: [:destroy]
feature_category :mlops
@@ -26,9 +28,13 @@ module Projects
render_404 unless @candidate.present?
end
- def check_feature_enabled
+ def check_read
render_404 unless can?(current_user, :read_model_experiments, @project)
end
+
+ def check_write
+ render_404 unless can?(current_user, :write_model_experiments, @project)
+ end
end
end
end
diff --git a/app/controllers/projects/ml/experiments_controller.rb b/app/controllers/projects/ml/experiments_controller.rb
index a620e9919e7..85e7f63779c 100644
--- a/app/controllers/projects/ml/experiments_controller.rb
+++ b/app/controllers/projects/ml/experiments_controller.rb
@@ -5,7 +5,8 @@ module Projects
class ExperimentsController < ::Projects::ApplicationController
include Projects::Ml::ExperimentsHelper
- before_action :check_feature_enabled
+ before_action :check_read, only: [:show, :index]
+ before_action :check_write, only: [:destroy]
before_action :set_experiment, only: [:show, :destroy]
feature_category :mlops
@@ -55,10 +56,14 @@ module Projects
private
- def check_feature_enabled
+ def check_read
render_404 unless can?(current_user, :read_model_experiments, @project)
end
+ def check_write
+ render_404 unless can?(current_user, :write_model_experiments, @project)
+ end
+
def set_experiment
@experiment = ::Ml::Experiment.by_project_id_and_iid(@project.id, params[:iid])
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 9038d972f65..1405bc7be37 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -2,6 +2,7 @@
module SortingHelper
include SortingTitlesValuesHelper
+ include ButtonHelper
# rubocop: disable Metrics/AbcSize
def sort_options_hash
@@ -167,10 +168,6 @@ module SortingHelper
}
end
- def sortable_item(item, path, sorted_by)
- link_to item, path, class: sorted_by == item ? 'is-active' : ''
- end
-
def issuable_sort_option_overrides
{
sort_value_oldest_created => sort_value_created_date,
@@ -275,7 +272,7 @@ module SortingHelper
end
def sort_direction_button(reverse_url, reverse_sort, sort_value)
- link_class = 'gl-button btn btn-default btn-icon has-tooltip reverse-sort-btn rspec-reverse-sort'
+ link_class = 'has-tooltip reverse-sort-btn rspec-reverse-sort'
icon = sort_direction_icon(sort_value)
url = reverse_url
@@ -284,9 +281,7 @@ module SortingHelper
link_class += ' disabled'
end
- link_to(url, type: 'button', class: link_class, title: s_('SortOptions|Sort direction')) do
- sprite_icon(icon)
- end
+ link_button_to nil, url, class: link_class, title: s_('SortOptions|Sort direction'), icon: icon
end
def issuable_sort_direction_button(sort_value)
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 0891c66853e..ad6155258ab 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -905,6 +905,10 @@ class ProjectPolicy < BasePolicy
enable :read_model_experiments
end
+ rule { can?(:reporter_access) & model_experiments_enabled }.policy do
+ enable :write_model_experiments
+ end
+
rule { ~admin & created_and_owned_by_banned_user }.policy do
prevent :read_project
end
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index 0c9d5a5a8df..0125c83dc72 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -28,13 +28,13 @@
= f.number_field :max_artifacts_size, class: 'form-control gl-form-input'
.form-text.text-muted
= _("The maximum file size for job artifacts.")
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size')
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'maximum-artifacts-size')
.form-group
= f.label :default_artifacts_expire_in, _('Default artifacts expiration'), class: 'label-bold'
= f.text_field :default_artifacts_expire_in, class: 'form-control gl-form-input'
.form-text.text-muted
= html_escape(_("Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration')
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'default-artifacts-expiration')
.form-group
= f.gitlab_ui_checkbox_component :keep_latest_artifact, s_('AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines'), help_text: s_('AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire.')
.form-group
@@ -42,7 +42,7 @@
= f.text_field :archive_builds_in_human_readable, class: 'form-control gl-form-input'
.form-text.text-muted
= html_escape(_("Jobs older than the configured time are considered expired and are archived. Archived jobs can no longer be retried. Leave empty to never archive jobs automatically. The default unit is in days, but you can use other units, for example %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}. Minimum value is 1 day.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'archive-jobs')
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'archive-jobs')
.form-group
= f.gitlab_ui_checkbox_component :protected_ci_variables, s_('AdminSettings|Protect CI/CD variables by default'), help_text: s_('AdminSettings|New CI/CD variables in projects and groups default to protected.')
.form-group
diff --git a/app/views/admin/application_settings/_email.html.haml b/app/views/admin/application_settings/_email.html.haml
index 80a7d3607ef..2f31eb5f6d1 100644
--- a/app/views/admin/application_settings/_email.html.haml
+++ b/app/views/admin/application_settings/_email.html.haml
@@ -10,7 +10,7 @@
= f.label :commit_email_hostname, _('Custom hostname (for private commit emails)'), class: 'label-bold'
= f.text_field :commit_email_hostname, class: 'form-control gl-form-input'
.form-text.text-muted
- - commit_email_hostname_docs_link = link_to _('Learn more'), help_page_path('user/admin_area/settings/email.md', anchor: 'custom-hostname-for-private-commit-emails'), target: '_blank', rel: 'noopener noreferrer'
+ - commit_email_hostname_docs_link = link_to _('Learn more'), help_page_path('administration/settings/email.md', anchor: 'custom-hostname-for-private-commit-emails'), target: '_blank', rel: 'noopener noreferrer'
= _("Hostname used in private commit emails. %{learn_more}").html_safe % { learn_more: commit_email_hostname_docs_link }
= render_if_exists 'admin/application_settings/email_additional_text_setting', form: f
diff --git a/app/views/admin/application_settings/_runner_registrars_form.html.haml b/app/views/admin/application_settings/_runner_registrars_form.html.haml
index 1329e5aeca9..b112c273aad 100644
--- a/app/views/admin/application_settings/_runner_registrars_form.html.haml
+++ b/app/views/admin/application_settings/_runner_registrars_form.html.haml
@@ -16,7 +16,7 @@
= s_('Runners|Runner registration')
%span.form-text.gl-mb-3.gl-mt-0
= s_('Runners|If both settings are disabled, new runners cannot be registered.')
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
= hidden_field_tag "application_setting[valid_runner_registrars][]", nil
- ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES.each do |type|
= f.gitlab_ui_checkbox_component :valid_runner_registrars, s_("Runners|Members of the %{type} can register runners") % { type: type },
diff --git a/app/views/groups/settings/ci_cd/_form.html.haml b/app/views/groups/settings/ci_cd/_form.html.haml
index d31d22c61be..9b23a8c5e0e 100644
--- a/app/views/groups/settings/ci_cd/_form.html.haml
+++ b/app/views/groups/settings/ci_cd/_form.html.haml
@@ -7,5 +7,5 @@
= f.number_field :max_artifacts_size, class: 'form-control'
%p.form-text.text-muted
= _("The maximum file size in megabytes for individual job artifacts.")
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'maximum-artifacts-size'), target: '_blank', rel: 'noopener noreferrer'
= f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/projects/merge_requests/_widget.html.haml b/app/views/projects/merge_requests/_widget.html.haml
index 9ec4363fa9a..606d4e06d33 100644
--- a/app/views/projects/merge_requests/_widget.html.haml
+++ b/app/views/projects/merge_requests/_widget.html.haml
@@ -13,7 +13,7 @@
window.gl.mrWidgetData.pipeline_must_succeed_docs_path = '#{help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds.md', anchor: 'require-a-successful-pipeline-for-merge')}';
window.gl.mrWidgetData.code_coverage_check_help_page_path = '#{help_page_path('ci/testing/code_coverage.md', anchor: 'coverage-check-approval-rule')}';
window.gl.mrWidgetData.security_configuration_path = '#{project_security_configuration_path(@project)}';
- window.gl.mrWidgetData.license_compliance_docs_path = '#{help_page_path('user/compliance/license_scanning_of_cyclonedx_files')}';
+ window.gl.mrWidgetData.license_compliance_docs_path = '#{help_page_path('user/compliance/license_compliance/index.md')}';
window.gl.mrWidgetData.eligible_approvers_docs_path = '#{help_page_path('user/project/merge_requests/approvals/rules.md', anchor: 'eligible-approvers')}';
window.gl.mrWidgetData.approvals_help_path = '#{help_page_path("user/project/merge_requests/approvals/index.md")}';
window.gl.mrWidgetData.pipelines_empty_svg_path = '#{image_path('illustrations/empty-state/empty-pipeline-md.svg')}';
diff --git a/app/views/projects/project_templates/_template.html.haml b/app/views/projects/project_templates/_template.html.haml
index 9dde86f77b4..93c53fc99fc 100644
--- a/app/views/projects/project_templates/_template.html.haml
+++ b/app/views/projects/project_templates/_template.html.haml
@@ -8,7 +8,7 @@
.text-muted
= template.description
.controls.d-flex.align-items-center
- %a.btn.gl-button.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_action: "click_button", track_value: "" } }
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'gl-mr-3', data: { track_label: "template_preview", track_property: template.name, track_action: "click_button", track_value: "" }, rel: 'noopener noreferrer' }, href: template.preview, target: '_blank') do
= _("Preview")
%label.btn.gl-button.btn-confirm.template-button.choose-template.gl-mb-0{ for: template.name,
'data-testid': "use_template_#{template.name}" }
diff --git a/app/views/projects/runners/_project_runners.html.haml b/app/views/projects/runners/_project_runners.html.haml
index bafdb5fc239..0f2f0c3f21c 100644
--- a/app/views/projects/runners/_project_runners.html.haml
+++ b/app/views/projects/runners/_project_runners.html.haml
@@ -10,7 +10,7 @@
#js-project-runner-registration-dropdown{ data: { registration_token: @project.runners_token, project_id: @project.id } }
- else
= _('Please contact an admin to create runners.')
- = link_to _('Learn more.'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more.'), help_page_path('administration/settings/continuous_integration', anchor: 'restrict-runner-registration-by-all-users-in-an-instance'), target: '_blank', rel: 'noopener noreferrer'
%hr
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 6f64d3f3f76..6eccbd245af 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -75,7 +75,7 @@
= f.number_field :max_artifacts_size, class: 'form-control gl-form-input'
%p.form-text.text-muted
= _("The maximum file size in megabytes for individual job artifacts.")
- = link_to sprite_icon('question-o'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to sprite_icon('question-o'), help_page_path('administration/settings/continuous_integration', anchor: 'maximum-artifacts-size'), target: '_blank', rel: 'noopener noreferrer'
= f.submit _('Save changes'), pajamas_button: true