diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-18 00:10:31 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-18 00:10:31 +0300 |
commit | 9c2ea7751419fb5e50708ea3ef3677cd16c43c7c (patch) | |
tree | 39dcd6fef621203e39388391d86eec8acfb3a0b0 /app | |
parent | 16964a4834ac976228b3ad69c4eff813d8230d7a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
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 |