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:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/batch_comments/components/submit_dropdown.vue68
-rw-r--r--app/assets/javascripts/ci/catalog/components/list/catalog_header.vue14
-rw-r--r--app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue112
-rw-r--r--app/assets/javascripts/ci/catalog/global_catalog.vue10
-rw-r--r--app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources.query.graphql16
-rw-r--r--app/assets/javascripts/ci/catalog/index.js37
-rw-r--r--app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue17
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js2
-rw-r--r--app/assets/javascripts/emoji/index.js25
-rw-r--r--app/assets/javascripts/pages/explore/catalog/index.js3
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue14
-rw-r--r--app/assets/javascripts/search/sidebar/components/archived_filter/data.js11
-rw-r--r--app/assets/javascripts/search/sidebar/components/wiki_blobs_filters.vue18
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js2
-rw-r--r--app/assets/javascripts/terraform/components/init_command_modal.vue11
-rw-r--r--app/assets/javascripts/work_items/components/notes/system_note.vue22
-rw-r--r--app/assets/stylesheets/page_bundles/_system_note_styles.scss59
-rw-r--r--app/assets/stylesheets/page_bundles/issuable.scss59
-rw-r--r--app/assets/stylesheets/page_bundles/work_items.scss1
-rw-r--r--app/controllers/projects/merge_requests/drafts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/repositories/git_http_controller.rb7
-rw-r--r--app/finders/data_transfer/mocked_transfer_finder.rb27
-rw-r--r--app/graphql/mutations/ci/catalog/resources/create.rb2
-rw-r--r--app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb16
-rw-r--r--app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb16
-rw-r--r--app/graphql/types/data_transfer/project_data_transfer_type.rb1
-rw-r--r--app/helpers/auth_helper.rb11
-rw-r--r--app/helpers/projects/pipeline_helper.rb1
-rw-r--r--app/services/ci/catalog/add_resource_service.rb41
-rw-r--r--app/services/ci/catalog/resources/create_service.rb31
-rw-r--r--app/services/ci/enqueue_job_service.rb11
-rw-r--r--app/views/dashboard/todos/index.html.haml2
-rw-r--r--app/views/explore/catalog/show.html.haml2
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml16
-rw-r--r--app/views/shared/deploy_tokens/_new_deploy_token.html.haml6
36 files changed, 490 insertions, 204 deletions
diff --git a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
index 4b9fe01e997..b5cb1862b45 100644
--- a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
+++ b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue
@@ -1,7 +1,15 @@
<script>
-import { GlDisclosureDropdown, GlButton, GlIcon, GlForm, GlFormCheckbox } from '@gitlab/ui';
+import {
+ GlDisclosureDropdown,
+ GlButton,
+ GlIcon,
+ GlForm,
+ GlFormCheckbox,
+ GlFormRadioGroup,
+} from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapGetters, mapActions, mapState } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __ } from '~/locale';
import { createAlert } from '~/alert';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
@@ -34,12 +42,14 @@ export default {
GlButton,
GlIcon,
GlForm,
+ GlFormRadioGroup,
GlFormCheckbox,
MarkdownEditor,
ApprovalPassword: () => import('ee_component/batch_comments/components/approval_password.vue'),
SummarizeMyReview: () =>
import('ee_component/batch_comments/components/summarize_my_review.vue'),
},
+ mixins: [glFeatureFlagsMixin()],
inject: {
canSummarize: { default: false },
},
@@ -53,6 +63,7 @@ export default {
note: '',
approve: false,
approval_password: '',
+ reviewer_state: 'reviewed',
},
formFieldProps: {
id: 'review-note-body',
@@ -74,6 +85,38 @@ export default {
autosaveKey() {
return `submit_review_dropdown/${this.getNoteableData.id}`;
},
+ radioGroupOptions() {
+ return [
+ {
+ html: [
+ __('Comment'),
+ `<p class="help-text">
+ ${__('Submit general feedback without explicit approval.')}
+ </p>`,
+ ].join('<br />'),
+ value: 'reviewed',
+ },
+ {
+ html: [
+ __('Approve'),
+ `<p class="help-text">
+ ${__('Submit feedback and approve these changes.')}
+ </p>`,
+ ].join('<br />'),
+ value: 'approved',
+ disabled: !this.userPermissions.canApprove,
+ },
+ {
+ html: [
+ __('Request changes'),
+ `<p class="help-text">
+ ${__('Submit feedback that should be addressed before merging.')}
+ </p>`,
+ ].join('<br />'),
+ value: 'requested_changes',
+ },
+ ];
+ },
},
watch: {
'noteData.approve': function noteDataApproveWatch() {
@@ -208,7 +251,14 @@ export default {
@keydown.ctrl.enter="submitReview"
/>
</div>
- <template v-if="userPermissions.canApprove">
+ <gl-form-radio-group
+ v-if="glFeatures.mrRequestChanges"
+ v-model="noteData.reviewer_state"
+ :options="radioGroupOptions"
+ class="gl-mt-4"
+ data-testid="reviewer_states"
+ />
+ <template v-else-if="userPermissions.canApprove">
<gl-form-checkbox
v-model="noteData.approve"
data-testid="approve_merge_request"
@@ -216,14 +266,14 @@ export default {
>
{{ __('Approve merge request') }}
</gl-form-checkbox>
- <approval-password
- v-if="getNoteableData.require_password_to_approve"
- v-show="noteData.approve"
- v-model="noteData.approval_password"
- class="gl-mt-3"
- data-testid="approve_password"
- />
</template>
+ <approval-password
+ v-if="userPermissions.canApprove && getNoteableData.require_password_to_approve"
+ v-show="noteData.approve || noteData.reviewer_state === 'approved'"
+ v-model="noteData.approval_password"
+ class="gl-mt-3"
+ data-testid="approve_password"
+ />
<div class="gl-display-flex gl-justify-content-start gl-mt-4">
<gl-button
:loading="isSubmitting"
diff --git a/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue b/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue
index 487215875c0..db84eaa82c2 100644
--- a/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue
+++ b/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue
@@ -4,12 +4,22 @@ import { __, s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import { CATALOG_FEEDBACK_DISMISSED_KEY } from '../../constants';
+const defaultTitle = __('CI/CD Catalog');
+const defaultDescription = s__(
+ 'CiCatalog|Discover CI configuration resources for a seamless CI/CD experience.',
+);
+
export default {
components: {
GlBanner,
GlLink,
},
- inject: ['pageTitle', 'pageDescription'],
+ inject: {
+ pageTitle: { default: defaultTitle },
+ pageDescription: {
+ default: defaultDescription,
+ },
+ },
data() {
return {
isFeedbackBannerDismissed: localStorage.getItem(CATALOG_FEEDBACK_DISMISSED_KEY) === 'true',
@@ -50,7 +60,7 @@ export default {
</gl-banner>
<h1 class="gl-font-size-h-display">{{ pageTitle }}</h1>
<p>
- <span>{{ pageDescription }}</span>
+ <span data-testid="description">{{ pageDescription }}</span>
<gl-link :href="$options.learnMorePath" target="_blank">{{
$options.i18n.learnMore
}}</gl-link>
diff --git a/app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue b/app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue
new file mode 100644
index 00000000000..5e8727a3ed0
--- /dev/null
+++ b/app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue
@@ -0,0 +1,112 @@
+<script>
+import { createAlert } from '~/alert';
+import { s__ } from '~/locale';
+import CatalogHeader from '~/ci/catalog/components/list/catalog_header.vue';
+import CatalogListSkeletonLoader from '~/ci/catalog/components/list/catalog_list_skeleton_loader.vue';
+import CiResourcesList from '~/ci/catalog/components/list/ci_resources_list.vue';
+import EmptyState from '~/ci/catalog/components/list/empty_state.vue';
+import { ciCatalogResourcesItemsCount } from '~/ci/catalog/graphql/settings';
+import getCatalogResources from '../../graphql/queries/get_ci_catalog_resources.query.graphql';
+
+export default {
+ components: {
+ CatalogHeader,
+ CatalogListSkeletonLoader,
+ CiResourcesList,
+ EmptyState,
+ },
+ data() {
+ return {
+ catalogResources: [],
+ currentPage: 1,
+ totalCount: 0,
+ pageInfo: {},
+ };
+ },
+ apollo: {
+ catalogResources: {
+ query: getCatalogResources,
+ variables() {
+ return {
+ first: ciCatalogResourcesItemsCount,
+ };
+ },
+ update(data) {
+ return data?.ciCatalogResources?.nodes || [];
+ },
+ result({ data }) {
+ const { pageInfo } = data?.ciCatalogResources || {};
+ this.pageInfo = pageInfo;
+ this.totalCount = data?.ciCatalogResources?.count || 0;
+ },
+ error(e) {
+ createAlert({ message: e.message || this.$options.i18n.fetchError, variant: 'danger' });
+ },
+ },
+ },
+ computed: {
+ hasResources() {
+ return this.catalogResources.length > 0;
+ },
+ isLoading() {
+ return this.$apollo.queries.catalogResources.loading;
+ },
+ },
+ methods: {
+ async handlePrevPage() {
+ try {
+ await this.$apollo.queries.catalogResources.fetchMore({
+ variables: {
+ before: this.pageInfo.startCursor,
+ last: ciCatalogResourcesItemsCount,
+ first: null,
+ },
+ });
+
+ this.currentPage -= 1;
+ } catch (e) {
+ // Ensure that the current query is properly stoped if an error occurs.
+ this.$apollo.queries.catalogResources.stop();
+ createAlert({ message: e?.message || this.$options.i18n.fetchError, variant: 'danger' });
+ }
+ },
+ async handleNextPage() {
+ try {
+ await this.$apollo.queries.catalogResources.fetchMore({
+ variables: {
+ after: this.pageInfo.endCursor,
+ },
+ });
+
+ this.currentPage += 1;
+ } catch (e) {
+ // Ensure that the current query is properly stoped if an error occurs.
+ this.$apollo.queries.catalogResources.stop();
+
+ createAlert({ message: e?.message || this.$options.i18n.fetchError, variant: 'danger' });
+ }
+ },
+ },
+ i18n: {
+ fetchError: s__('CiCatalog|There was an error fetching CI/CD Catalog resources.'),
+ },
+};
+</script>
+<template>
+ <div>
+ <catalog-header />
+ <catalog-list-skeleton-loader v-if="isLoading" class="gl-w-full gl-mt-3" />
+ <empty-state v-else-if="!hasResources" />
+ <ci-resources-list
+ v-else
+ :current-page="currentPage"
+ :page-info="pageInfo"
+ :prev-text="__('Prev')"
+ :next-text="__('Next')"
+ :resources="catalogResources"
+ :total-count="totalCount"
+ @onPrevPage="handlePrevPage"
+ @onNextPage="handleNextPage"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/catalog/global_catalog.vue b/app/assets/javascripts/ci/catalog/global_catalog.vue
new file mode 100644
index 00000000000..76eac11a122
--- /dev/null
+++ b/app/assets/javascripts/ci/catalog/global_catalog.vue
@@ -0,0 +1,10 @@
+<script>
+import CiCatalogHome from './components/ci_catalog_home.vue';
+
+export default {
+ components: { CiCatalogHome },
+};
+</script>
+<template>
+ <ci-catalog-home />
+</template>
diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources.query.graphql
new file mode 100644
index 00000000000..aae29edef5e
--- /dev/null
+++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources.query.graphql
@@ -0,0 +1,16 @@
+#import "~/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql"
+
+query getCatalogResources($after: String, $before: String, $first: Int = 20, $last: Int) {
+ ciCatalogResources(after: $after, before: $before, first: $first, last: $last) {
+ pageInfo {
+ startCursor
+ endCursor
+ hasNextPage
+ hasPreviousPage
+ }
+ count
+ nodes {
+ ...CatalogResourceFields
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci/catalog/index.js b/app/assets/javascripts/ci/catalog/index.js
new file mode 100644
index 00000000000..5815245506c
--- /dev/null
+++ b/app/assets/javascripts/ci/catalog/index.js
@@ -0,0 +1,37 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { cacheConfig, resolvers } from '~/ci/catalog/graphql/settings';
+
+import GlobalCatalog from './global_catalog.vue';
+import CiResourcesPage from './components/pages/ci_resources_page.vue';
+import { createRouter } from './router';
+
+export const initCatalog = (selector = '#js-ci-cd-catalog') => {
+ const el = document.querySelector(selector);
+ if (!el) {
+ return null;
+ }
+
+ const { dataset } = el;
+ const { ciCatalogPath } = dataset;
+
+ Vue.use(VueApollo);
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(resolvers, cacheConfig),
+ });
+
+ return new Vue({
+ el,
+ name: 'GlobalCatalog',
+ router: createRouter(ciCatalogPath, CiResourcesPage),
+ apolloProvider,
+ provide: {
+ ciCatalogPath,
+ },
+ render(h) {
+ return h(GlobalCatalog);
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue b/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue
index dc4a2d91c84..ed5ce02c32e 100644
--- a/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue
+++ b/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue
@@ -64,7 +64,7 @@ export default {
latestBadgeTooltip: __('Latest pipeline for the most recent commit on this branch'),
mergeTrainBadgeText: s__('Pipelines|merge train'),
mergeTrainBadgeTooltip: s__(
- 'Pipelines|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
+ 'Pipelines|This pipeline ran on the contents of the merge request combined with the contents of all other merge requests queued for merging into the target branch.',
),
invalidBadgeText: s__('Pipelines|yaml invalid'),
failedBadgeText: s__('Pipelines|error'),
@@ -74,7 +74,11 @@ export default {
),
detachedBadgeText: s__('Pipelines|merge request'),
detachedBadgeTooltip: s__(
- "Pipelines|This pipeline ran on the contents of this merge request's source branch, not the target branch.",
+ "Pipelines|This pipeline ran on the contents of the merge request's source branch, not the target branch.",
+ ),
+ mergedResultsBadgeText: s__('Pipelines|merged results'),
+ mergedResultsBadgeTooltip: s__(
+ 'Pipelines|This pipeline ran on the contents of the merge request combined with the contents of the target branch.',
),
stuckBadgeText: s__('Pipelines|stuck'),
stuckBadgeTooltip: s__('Pipelines|This pipeline is stuck'),
@@ -527,6 +531,15 @@ export default {
{{ $options.i18n.detachedBadgeText }}
</gl-badge>
<gl-badge
+ v-if="badges.mergedResultsPipeline"
+ v-gl-tooltip
+ :title="$options.i18n.mergedResultsBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ {{ $options.i18n.mergedResultsBadgeText }}
+ </gl-badge>
+ <gl-badge
v-if="badges.stuck"
v-gl-tooltip
:title="$options.i18n.stuckBadgeTooltip"
diff --git a/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js b/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js
index 067ec3f305e..0ab5d9bcda0 100644
--- a/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js
+++ b/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js
@@ -26,6 +26,7 @@ export const createPipelineDetailsHeaderApp = (elSelector, apolloProvider, graph
child,
latest,
mergeTrainPipeline,
+ mergedResultsPipeline,
invalid,
failed,
autoDevops,
@@ -62,6 +63,7 @@ export const createPipelineDetailsHeaderApp = (elSelector, apolloProvider, graph
child: parseBoolean(child),
latest: parseBoolean(latest),
mergeTrainPipeline: parseBoolean(mergeTrainPipeline),
+ mergedResultsPipeline: parseBoolean(mergedResultsPipeline),
invalid: parseBoolean(invalid),
failed: parseBoolean(failed),
autoDevops: parseBoolean(autoDevops),
diff --git a/app/assets/javascripts/emoji/index.js b/app/assets/javascripts/emoji/index.js
index a78b901af48..f98369c2fde 100644
--- a/app/assets/javascripts/emoji/index.js
+++ b/app/assets/javascripts/emoji/index.js
@@ -25,12 +25,22 @@ export const EMOJI_VERSION = '3';
const isLocalStorageAvailable = AccessorUtilities.canUseLocalStorage();
async function loadEmoji() {
- if (
- isLocalStorageAvailable &&
- window.localStorage.getItem(CACHE_VERSION_KEY) === EMOJI_VERSION &&
- window.localStorage.getItem(CACHE_KEY)
- ) {
- return JSON.parse(window.localStorage.getItem(CACHE_KEY));
+ try {
+ window.localStorage.removeItem(CACHE_VERSION_KEY);
+ } catch {
+ // Cleanup after us and remove the old EMOJI_VERSION_KEY
+ }
+
+ try {
+ if (isLocalStorageAvailable) {
+ const parsed = JSON.parse(window.localStorage.getItem(CACHE_KEY));
+ if (parsed?.EMOJI_VERSION === EMOJI_VERSION && parsed.data) {
+ return parsed.data;
+ }
+ }
+ } catch {
+ // Maybe the stored data was corrupted or the version didn't match.
+ // Let's not error out.
}
// We load the JSON file direct from the server
@@ -41,8 +51,7 @@ async function loadEmoji() {
);
try {
- window.localStorage.setItem(CACHE_VERSION_KEY, EMOJI_VERSION);
- window.localStorage.setItem(CACHE_KEY, JSON.stringify(data));
+ window.localStorage.setItem(CACHE_KEY, JSON.stringify({ data, EMOJI_VERSION }));
} catch {
// Setting data in localstorage may fail when storage quota is exceeded.
// We should continue even when this fails.
diff --git a/app/assets/javascripts/pages/explore/catalog/index.js b/app/assets/javascripts/pages/explore/catalog/index.js
new file mode 100644
index 00000000000..fec738a93a6
--- /dev/null
+++ b/app/assets/javascripts/pages/explore/catalog/index.js
@@ -0,0 +1,3 @@
+import { initCatalog } from '~/ci/catalog/';
+
+initCatalog();
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index b50a82ff676..86a5f5107f8 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -1,6 +1,7 @@
<script>
// eslint-disable-next-line no-restricted-imports
import { mapState, mapGetters } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue';
import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue';
import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
@@ -15,6 +16,7 @@ import {
SCOPE_NOTES,
SCOPE_COMMITS,
SCOPE_MILESTONES,
+ SCOPE_WIKI_BLOBS,
SEARCH_TYPE_ADVANCED,
} from '../constants';
import IssuesFilters from './issues_filters.vue';
@@ -24,6 +26,7 @@ import ProjectsFilters from './projects_filters.vue';
import NotesFilters from './notes_filters.vue';
import CommitsFilters from './commits_filters.vue';
import MilestonesFilters from './milestones_filters.vue';
+import WikiBlobsFilters from './wiki_blobs_filters.vue';
export default {
name: 'GlobalSearchSidebar',
@@ -33,6 +36,7 @@ export default {
BlobsFilters,
ProjectsFilters,
NotesFilters,
+ WikiBlobsFilters,
ScopeLegacyNavigation,
ScopeSidebarNavigation,
SidebarPortal,
@@ -41,6 +45,7 @@ export default {
CommitsFilters,
MilestonesFilters,
},
+ mixins: [glFeatureFlagsMixin()],
computed: {
// useSidebarNavigation refers to whether the new left sidebar navigation is enabled
...mapState(['useSidebarNavigation', 'searchType']),
@@ -66,6 +71,12 @@ export default {
showMilestonesFilters() {
return this.currentScope === SCOPE_MILESTONES;
},
+ showWikiBlobsFilters() {
+ return (
+ this.currentScope === SCOPE_WIKI_BLOBS &&
+ this.glFeatures?.searchProjectWikisHideArchivedProjects
+ );
+ },
showScopeNavigation() {
// showScopeNavigation refers to whether the scope navigation should be shown
// while the legacy navigation is being used and there are no search results
@@ -93,6 +104,7 @@ export default {
<notes-filters v-if="showNotesFilters" />
<commits-filters v-if="showCommitsFilters" />
<milestones-filters v-if="showMilestonesFilters" />
+ <wiki-blobs-filters v-if="showWikiBlobsFilters" />
</sidebar-portal>
</section>
@@ -109,6 +121,7 @@ export default {
<notes-filters v-if="showNotesFilters" />
<commits-filters v-if="showCommitsFilters" />
<milestones-filters v-if="showMilestonesFilters" />
+ <wiki-blobs-filters v-if="showWikiBlobsFilters" />
</div>
<small-screen-drawer-navigation class="gl-lg-display-none">
<scope-legacy-navigation />
@@ -119,6 +132,7 @@ export default {
<notes-filters v-if="showNotesFilters" />
<commits-filters v-if="showCommitsFilters" />
<milestones-filters v-if="showMilestonesFilters" />
+ <wiki-blobs-filters v-if="showWikiBlobsFilters" />
</small-screen-drawer-navigation>
</section>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
index ed90e2aaded..96a6f119da2 100644
--- a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
+++ b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
@@ -5,7 +5,16 @@ const checkboxLabel = s__('GlobalSearch|Include archived');
export const TRACKING_NAMESPACE = 'search:archived:select';
export const TRACKING_LABEL_CHECKBOX = 'checkbox';
-const scopes = ['projects', 'issues', 'merge_requests', 'notes', 'blobs', 'commits', 'milestones'];
+const scopes = [
+ 'projects',
+ 'issues',
+ 'merge_requests',
+ 'notes',
+ 'blobs',
+ 'commits',
+ 'milestones',
+ 'wiki_blobs',
+];
const filterParam = 'include_archived';
diff --git a/app/assets/javascripts/search/sidebar/components/wiki_blobs_filters.vue b/app/assets/javascripts/search/sidebar/components/wiki_blobs_filters.vue
new file mode 100644
index 00000000000..b1f386d9f4f
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/wiki_blobs_filters.vue
@@ -0,0 +1,18 @@
+<script>
+import ArchivedFilter from './archived_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
+export default {
+ name: 'WikiBlobsFilters',
+ components: {
+ ArchivedFilter,
+ FiltersTemplate,
+ },
+};
+</script>
+
+<template>
+ <filters-template>
+ <archived-filter class="gl-mb-5" />
+ </filters-template>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
index b5446ecbb42..1559155a941 100644
--- a/app/assets/javascripts/search/sidebar/constants/index.js
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -5,6 +5,8 @@ export const SCOPE_PROJECTS = 'projects';
export const SCOPE_NOTES = 'notes';
export const SCOPE_COMMITS = 'commits';
export const SCOPE_MILESTONES = 'milestones';
+export const SCOPE_WIKI_BLOBS = 'wiki_blobs';
+
export const LABEL_DEFAULT_CLASSES = [
'gl-display-flex',
'gl-flex-direction-row',
diff --git a/app/assets/javascripts/terraform/components/init_command_modal.vue b/app/assets/javascripts/terraform/components/init_command_modal.vue
index 74c41700f43..7962c8573df 100644
--- a/app/assets/javascripts/terraform/components/init_command_modal.vue
+++ b/app/assets/javascripts/terraform/components/init_command_modal.vue
@@ -40,15 +40,14 @@ export default {
},
methods: {
getModalInfoCopyStr() {
- const stateNameEncoded = this.stateName
- ? encodeURIComponent(this.stateName)
- : '<YOUR-STATE-NAME>';
+ const stateNameEncoded = this.stateName ? encodeURIComponent(this.stateName) : 'default';
return `export GITLAB_ACCESS_TOKEN=<YOUR-ACCESS-TOKEN>
+export TF_STATE_NAME=${stateNameEncoded}
terraform init \\
- -backend-config="address=${this.terraformApiUrl}/${stateNameEncoded}" \\
- -backend-config="lock_address=${this.terraformApiUrl}/${stateNameEncoded}/lock" \\
- -backend-config="unlock_address=${this.terraformApiUrl}/${stateNameEncoded}/lock" \\
+ -backend-config="address=${this.terraformApiUrl}/$TF_STATE_NAME" \\
+ -backend-config="lock_address=${this.terraformApiUrl}/$TF_STATE_NAME/lock" \\
+ -backend-config="unlock_address=${this.terraformApiUrl}/$TF_STATE_NAME/lock" \\
-backend-config="username=${this.username}" \\
-backend-config="password=$GITLAB_ACCESS_TOKEN" \\
-backend-config="lock_method=POST" \\
diff --git a/app/assets/javascripts/work_items/components/notes/system_note.vue b/app/assets/javascripts/work_items/components/notes/system_note.vue
index 7903adea9bd..31cfe387b6e 100644
--- a/app/assets/javascripts/work_items/components/notes/system_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/system_note.vue
@@ -26,6 +26,11 @@ import { __ } from '~/locale';
import NoteHeader from '~/notes/components/note_header.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
+const ALLOWED_ICONS = ['issue-close'];
+const ICON_COLORS = {
+ 'issue-close': 'gl-bg-blue-100! gl-text-blue-700',
+};
+
export default {
i18n: {
deleteButtonLabel: __('Remove description history'),
@@ -66,6 +71,12 @@ export default {
noteAnchorId() {
return `note_${this.noteId}`;
},
+ getIconColor() {
+ return ICON_COLORS[this.note.systemNoteIconName] || '';
+ },
+ isAllowedIcon() {
+ return ALLOWED_ICONS.includes(this.note.systemNoteIconName);
+ },
isTargetNote() {
return this.targetNoteHash === this.noteAnchorId;
},
@@ -102,9 +113,16 @@ export default {
class="note system-note note-wrapper"
>
<div
- class="gl-float-left gl--flex-center gl-rounded-full gl-mt-n1 gl-ml-2 gl-w-6 gl-h-6 gl-bg-gray-50 gl-text-gray-600"
+ :class="[
+ getIconColor,
+ {
+ 'gl-bg-gray-50 gl-text-gray-600 system-note-icon': isAllowedIcon,
+ 'system-note-tiny-dot gl-bg-gray-900!': !isAllowedIcon,
+ },
+ ]"
+ class="gl-float-left gl--flex-center gl-rounded-full gl-relative"
>
- <gl-icon :name="note.systemNoteIconName" />
+ <gl-icon v-if="isAllowedIcon" :size="12" :name="note.systemNoteIconName" />
</div>
<div class="timeline-content">
<div class="note-header">
diff --git a/app/assets/stylesheets/page_bundles/_system_note_styles.scss b/app/assets/stylesheets/page_bundles/_system_note_styles.scss
new file mode 100644
index 00000000000..68e2b747c52
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/_system_note_styles.scss
@@ -0,0 +1,59 @@
+/**
+Shared styles for system note dot and icon styles used for MR, Issue, Work Item
+*/
+.system-note-tiny-dot {
+ width: 8px;
+ height: 8px;
+ margin-top: 6px;
+ margin-left: 12px;
+ margin-right: 8px;
+ border: 2px solid var(--gray-50, $gray-50);
+ }
+
+ .system-note-icon {
+ width: 20px;
+ height: 20px;
+ margin-left: 6px;
+
+ &.gl-bg-green-100 {
+ --bg-color: var(--green-100, #{$green-100});
+ }
+
+ &.gl-bg-red-100 {
+ --bg-color: var(--red-100, #{$red-100});
+ }
+
+ &.gl-bg-blue-100 {
+ --bg-color: var(--blue-100, #{$blue-100});
+ }
+ }
+
+ .system-note-icon:not(.mr-system-note-empty)::before {
+ content: '';
+ display: block;
+ position: absolute;
+ left: calc(50% - 1px);
+ bottom: 100%;
+ width: 2px;
+ height: 20px;
+ background: linear-gradient(to bottom, transparent, var(--bg-color));
+
+ .system-note:first-child & {
+ display: none;
+ }
+ }
+
+ .system-note-icon:not(.mr-system-note-empty)::after {
+ content: '';
+ display: block;
+ position: absolute;
+ left: calc(50% - 1px);
+ top: 100%;
+ width: 2px;
+ height: 20px;
+ background: linear-gradient(to bottom, var(--bg-color), transparent);
+
+ .system-note:last-child & {
+ display: none;
+ }
+ } \ No newline at end of file
diff --git a/app/assets/stylesheets/page_bundles/issuable.scss b/app/assets/stylesheets/page_bundles/issuable.scss
index 43369efe851..05563f8e314 100644
--- a/app/assets/stylesheets/page_bundles/issuable.scss
+++ b/app/assets/stylesheets/page_bundles/issuable.scss
@@ -1,4 +1,5 @@
@import 'mixins_and_variables_and_functions';
+@import 'system_note_styles';
.issuable-details {
section {
@@ -104,61 +105,3 @@
@include gl-font-weight-normal;
}
}
-
-.system-note-tiny-dot {
- width: 8px;
- height: 8px;
- margin-top: 6px;
- margin-left: 12px;
- margin-right: 8px;
- border: 2px solid var(--gray-50, $gray-50);
-}
-
-
-.system-note-icon {
- width: 20px;
- height: 20px;
- margin-left: 6px;
-
- &.gl-bg-green-100 {
- --bg-color: var(--green-100, #{$green-100});
- }
-
- &.gl-bg-red-100 {
- --bg-color: var(--red-100, #{$red-100});
- }
-
- &.gl-bg-blue-100 {
- --bg-color: var(--blue-100, #{$blue-100});
- }
-}
-
-.system-note-icon:not(.mr-system-note-empty)::before {
- content: '';
- display: block;
- position: absolute;
- left: calc(50% - 1px);
- bottom: 100%;
- width: 2px;
- height: 20px;
- background: linear-gradient(to bottom, transparent, var(--bg-color));
-
- .system-note:first-child & {
- display: none;
- }
-}
-
-.system-note-icon:not(.mr-system-note-empty)::after {
- content: '';
- display: block;
- position: absolute;
- left: calc(50% - 1px);
- top: 100%;
- width: 2px;
- height: 20px;
- background: linear-gradient(to bottom, var(--bg-color), transparent);
-
- .system-note:last-child & {
- display: none;
- }
-}
diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss
index 154803c7d88..ec73f27ed09 100644
--- a/app/assets/stylesheets/page_bundles/work_items.scss
+++ b/app/assets/stylesheets/page_bundles/work_items.scss
@@ -1,4 +1,5 @@
@import 'mixins_and_variables_and_functions';
+@import 'system_note_styles';
$work-item-field-inset-shadow: inset 0 0 0 $gl-border-size-1 var(--gray-200, $gray-200) !important;
$work-item-overview-right-sidebar-width: 23rem;
diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb
index 1ec25d44bfa..fb0073e0ad4 100644
--- a/app/controllers/projects/merge_requests/drafts_controller.rb
+++ b/app/controllers/projects/merge_requests/drafts_controller.rb
@@ -190,7 +190,7 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli
def update_reviewer_state
if reviewer_state_params[:reviewer_state] === 'approved'
::MergeRequests::ApprovalService
- .new(project: @project, current_user: current_user)
+ .new(project: @project, current_user: current_user, params: approve_params)
.execute(merge_request)
else
::MergeRequests::UpdateReviewerStateService
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index a9e15c0bd90..8a92db36311 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -46,6 +46,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:mr_pipelines_graphql, project)
push_frontend_feature_flag(:notifications_todos_buttons, current_user)
push_frontend_feature_flag(:widget_pipeline_pass_subscription_update, project)
+ push_frontend_feature_flag(:mr_request_changes, current_user)
end
before_action only: [:edit] do
diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb
index f78a28c89dd..48edda13904 100644
--- a/app/controllers/repositories/git_http_controller.rb
+++ b/app/controllers/repositories/git_http_controller.rb
@@ -125,6 +125,13 @@ module Repositories
def log_user_activity
Users::ActivityService.new(author: user, project: project, namespace: project&.namespace).execute
end
+
+ def append_info_to_payload(payload)
+ super
+
+ payload[:metadata] ||= {}
+ payload[:metadata][:repository_storage] = project&.repository_storage
+ end
end
end
diff --git a/app/finders/data_transfer/mocked_transfer_finder.rb b/app/finders/data_transfer/mocked_transfer_finder.rb
deleted file mode 100644
index 9c5551005ea..00000000000
--- a/app/finders/data_transfer/mocked_transfer_finder.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-# Mocked data for data transfer
-# Follow this epic for recent progress: https://gitlab.com/groups/gitlab-org/-/epics/9330
-module DataTransfer
- class MockedTransferFinder
- def execute
- start_date = Date.new(2023, 0o1, 0o1)
- date_for_index = ->(i) { (start_date + i.months).strftime('%Y-%m-%d') }
-
- 0.upto(11).map do |i|
- {
- date: date_for_index.call(i),
- repository_egress: rand(70000..550000),
- artifacts_egress: rand(70000..550000),
- packages_egress: rand(70000..550000),
- registry_egress: rand(70000..550000)
- }.tap do |hash|
- hash[:total_egress] = hash
- .slice(:repository_egress, :artifacts_egress, :packages_egress, :registry_egress)
- .values
- .sum
- end
- end
- end
- end
-end
diff --git a/app/graphql/mutations/ci/catalog/resources/create.rb b/app/graphql/mutations/ci/catalog/resources/create.rb
index 258f83a3e19..7f934e101c8 100644
--- a/app/graphql/mutations/ci/catalog/resources/create.rb
+++ b/app/graphql/mutations/ci/catalog/resources/create.rb
@@ -15,7 +15,7 @@ module Mutations
def resolve(project_path:)
project = authorized_find!(project_path: project_path)
- response = ::Ci::Catalog::AddResourceService.new(project, current_user).execute
+ response = ::Ci::Catalog::Resources::CreateService.new(project, current_user).execute
errors = response.success? ? [] : [response.message]
diff --git a/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb
index 83bb144017c..133b86623f1 100644
--- a/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb
+++ b/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb
@@ -16,16 +16,12 @@ module Resolvers
def resolve(**args)
return { egress_nodes: [] } unless Feature.enabled?(:data_transfer_monitoring, group)
- results = if Feature.enabled?(:data_transfer_monitoring_mock_data, group)
- ::DataTransfer::MockedTransferFinder.new.execute
- else
- ::DataTransfer::GroupDataTransferFinder.new(
- group: group,
- from: args[:from],
- to: args[:to],
- user: current_user
- ).execute.map(&:attributes)
- end
+ results = ::DataTransfer::GroupDataTransferFinder.new(
+ group: group,
+ from: args[:from],
+ to: args[:to],
+ user: current_user
+ ).execute.map(&:attributes)
{ egress_nodes: results.to_a }
end
diff --git a/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb
index c3296f7d4c3..d711f837251 100644
--- a/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb
+++ b/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb
@@ -16,16 +16,12 @@ module Resolvers
def resolve(**args)
return { egress_nodes: [] } unless Feature.enabled?(:data_transfer_monitoring, project.group)
- results = if Feature.enabled?(:data_transfer_monitoring_mock_data, project.group)
- ::DataTransfer::MockedTransferFinder.new.execute
- else
- ::DataTransfer::ProjectDataTransferFinder.new(
- project: project,
- from: args[:from],
- to: args[:to],
- user: current_user
- ).execute
- end
+ results = ::DataTransfer::ProjectDataTransferFinder.new(
+ project: project,
+ from: args[:from],
+ to: args[:to],
+ user: current_user
+ ).execute
{ egress_nodes: results }
end
diff --git a/app/graphql/types/data_transfer/project_data_transfer_type.rb b/app/graphql/types/data_transfer/project_data_transfer_type.rb
index 36afa20194e..363b675209d 100644
--- a/app/graphql/types/data_transfer/project_data_transfer_type.rb
+++ b/app/graphql/types/data_transfer/project_data_transfer_type.rb
@@ -13,7 +13,6 @@ module Types
def total_egress(parent:)
return unless Feature.enabled?(:data_transfer_monitoring, parent.group)
- return 40_000_000 if Feature.enabled?(:data_transfer_monitoring_mock_data, parent.group)
object[:egress_nodes].sum('repository_egress + artifacts_egress + packages_egress + registry_egress')
end
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index fc157df3891..e447940e2af 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -93,16 +93,11 @@ module AuthHelper
end
def saml_providers
- auth_providers.select do |provider|
- provider == :saml || auth_strategy_class(provider) == 'OmniAuth::Strategies::SAML'
+ providers = Gitlab.config.omniauth.providers.select do |provider|
+ provider.name == 'saml' || provider.dig('args', 'strategy_class') == 'OmniAuth::Strategies::SAML'
end
- end
-
- def auth_strategy_class(provider)
- config = Gitlab::Auth::OAuth::Provider.config_for(provider)
- return if config.nil? || config['args'].blank?
- config.args['strategy_class']
+ providers.map(&:name).map(&:to_sym)
end
def any_form_based_providers_enabled?
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index 0c3b7d26fe2..1558f013462 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -40,6 +40,7 @@ module Projects
child: pipeline.child?.to_s,
latest: pipeline.latest?.to_s,
merge_train_pipeline: pipeline.merge_train_pipeline?.to_s,
+ merged_results_pipeline: (pipeline.merged_result_pipeline? && !pipeline.merge_train_pipeline?).to_s,
invalid: pipeline.has_yaml_errors?.to_s,
failed: pipeline.failure_reason?.to_s,
auto_devops: pipeline.auto_devops_source?.to_s,
diff --git a/app/services/ci/catalog/add_resource_service.rb b/app/services/ci/catalog/add_resource_service.rb
deleted file mode 100644
index c22e7e84c3c..00000000000
--- a/app/services/ci/catalog/add_resource_service.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module Ci
- module Catalog
- class AddResourceService
- include Gitlab::Allowable
-
- attr_reader :project, :current_user
-
- def initialize(project, user)
- @current_user = user
- @project = project
- end
-
- def execute
- raise Gitlab::Access::AccessDeniedError unless can?(current_user, :add_catalog_resource, project)
-
- validation_response = Ci::Catalog::Resources::ValidateService.new(project, project.default_branch).execute
-
- if validation_response.success?
- create_catalog_resource
- else
- ServiceResponse.error(message: validation_response.message)
- end
- end
-
- private
-
- def create_catalog_resource
- catalog_resource = Ci::Catalog::Resource.new(project: project)
-
- if catalog_resource.valid?
- catalog_resource.save!
- ServiceResponse.success(payload: catalog_resource)
- else
- ServiceResponse.error(message: catalog_resource.errors.full_messages.join(', '))
- end
- end
- end
- end
-end
diff --git a/app/services/ci/catalog/resources/create_service.rb b/app/services/ci/catalog/resources/create_service.rb
new file mode 100644
index 00000000000..89367c70e82
--- /dev/null
+++ b/app/services/ci/catalog/resources/create_service.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ module Resources
+ class CreateService
+ include Gitlab::Allowable
+
+ attr_reader :project, :current_user
+
+ def initialize(project, user)
+ @current_user = user
+ @project = project
+ end
+
+ def execute
+ raise Gitlab::Access::AccessDeniedError unless can?(current_user, :add_catalog_resource, project)
+
+ catalog_resource = Ci::Catalog::Resource.new(project: project)
+
+ if catalog_resource.valid?
+ catalog_resource.save!
+ ServiceResponse.success(payload: catalog_resource)
+ else
+ ServiceResponse.error(message: catalog_resource.errors.full_messages.join(', '))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/ci/enqueue_job_service.rb b/app/services/ci/enqueue_job_service.rb
index 9e3bea3fd28..db616473336 100644
--- a/app/services/ci/enqueue_job_service.rb
+++ b/app/services/ci/enqueue_job_service.rb
@@ -11,11 +11,14 @@ module Ci
end
def execute(&transition)
- job.user = current_user
- job.job_variables_attributes = variables if variables
-
transition ||= ->(job) { job.enqueue! }
- Gitlab::OptimisticLocking.retry_lock(job, name: 'ci_enqueue_job', &transition)
+
+ Gitlab::OptimisticLocking.retry_lock(job, name: 'ci_enqueue_job') do |job|
+ job.user = current_user
+ job.job_variables_attributes = variables if variables
+
+ transition.call(job)
+ end
ResetSkippedJobsService.new(job.project, current_user).execute(job)
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 684231d3a37..e4d894ede1c 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -83,7 +83,7 @@
%ul.content-list.todos-list
= render @allowed_todos
= paginate @todos, theme: "gitlab"
- .js-nothing-here-container.gl-empty-state.gl-text-center.hidden
+ .col.js-nothing-here-container.gl-empty-state.gl-text-center.hidden
.svg-content.svg-150
= image_tag 'illustrations/empty-todos-all-done-md.svg'
.text-content.gl-text-center
diff --git a/app/views/explore/catalog/show.html.haml b/app/views/explore/catalog/show.html.haml
index 6c10ba7dfd7..7c8d788f8e3 100644
--- a/app/views/explore/catalog/show.html.haml
+++ b/app/views/explore/catalog/show.html.haml
@@ -1,3 +1,3 @@
- page_title _('CI/CD Catalog')
-#js-ci-cd-catalog
+#js-ci-cd-catalog{ data: { ci_catalog_path: explore_catalog_index_path } }
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index b172e3bf94f..109bd559762 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -6,12 +6,12 @@
.form-group
= f.label :name, class: 'label-bold'
- = f.text_field :name, class: 'form-control gl-form-input', data: { qa_selector: 'deploy_token_name_field' }, required: true
+ = f.text_field :name, class: 'form-control gl-form-input', data: { testid: 'deploy-token-name-field' }, required: true
.text-secondary= s_('DeployTokens|Enter a unique name for your deploy token.')
.form-group
= f.label :expires_at, _('Expiration date (optional)'), class: 'label-bold'
- = f.gitlab_ui_datepicker :expires_at, data: { qa_selector: 'deploy_token_expires_at_field' }, value: f.object.expires_at
+ = f.gitlab_ui_datepicker :expires_at, data: { testid: 'deploy-token-expires-at-field' }, value: f.object.expires_at
.text-secondary= s_('DeployTokens|Enter an expiration date for your token. Defaults to never expire.')
.form-group
@@ -22,15 +22,15 @@
.form-group
= f.label :scopes, _('Scopes (select at least one)'), class: 'label-bold'
- = f.gitlab_ui_checkbox_component :read_repository, 'read_repository', help_text: s_('DeployTokens|Allows read-only access to the repository.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_repository_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_repository, 'read_repository', help_text: s_('DeployTokens|Allows read-only access to the repository.'), checkbox_options: { data: { testid: 'deploy-token-read-repository-checkbox' } }
- if container_registry_enabled?(group_or_project)
- = f.gitlab_ui_checkbox_component :read_registry, 'read_registry', help_text: s_('DeployTokens|Allows read-only access to registry images.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_registry_checkbox' } }
- = f.gitlab_ui_checkbox_component :write_registry, 'write_registry', help_text: s_('DeployTokens|Allows write access to registry images.'), checkbox_options: { data: { qa_selector: 'deploy_token_write_registry_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_registry, 'read_registry', help_text: s_('DeployTokens|Allows read-only access to registry images.'), checkbox_options: { data: { testid: 'deploy-token-read-registry-checkbox' } }
+ = f.gitlab_ui_checkbox_component :write_registry, 'write_registry', help_text: s_('DeployTokens|Allows write access to registry images.'), checkbox_options: { data: { testid: 'deploy-token-write-registry-checkbox' } }
- if packages_registry_enabled?(group_or_project)
- = f.gitlab_ui_checkbox_component :read_package_registry, 'read_package_registry', help_text: s_('DeployTokens|Allows read-only access to the package registry.'), checkbox_options: { data: { qa_selector: 'deploy_token_read_package_registry_checkbox' } }
- = f.gitlab_ui_checkbox_component :write_package_registry, 'write_package_registry', help_text: s_('DeployTokens|Allows read and write access to the package registry.'), checkbox_options: { data: { qa_selector: 'deploy_token_write_package_registry_checkbox' } }
+ = f.gitlab_ui_checkbox_component :read_package_registry, 'read_package_registry', help_text: s_('DeployTokens|Allows read-only access to the package registry.'), checkbox_options: { data: { testid: 'deploy-token-read-package-registry-checkbox' } }
+ = f.gitlab_ui_checkbox_component :write_package_registry, 'write_package_registry', help_text: s_('DeployTokens|Allows read and write access to the package registry.'), checkbox_options: { data: { testid: 'deploy-token-write-package-registry-checkbox' } }
.gl-mt-3
- = f.submit s_('DeployTokens|Create deploy token'), data: { qa_selector: 'create_deploy_token_button' }, pajamas_button: true
+ = f.submit s_('DeployTokens|Create deploy token'), data: { testid: 'create-deploy-token-button' }, pajamas_button: true
diff --git a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
index 30917ee6fff..2bc2e6c5b81 100644
--- a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
+++ b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
@@ -1,11 +1,11 @@
-.created-deploy-token-container.info-well{ data: { qa_selector: 'created_deploy_token_container' } }
+.created-deploy-token-container.info-well{ data: { testid: 'created-deploy-token-container' } }
.well-segment
%h5.gl-mt-0
= s_('DeployTokens|Your new Deploy Token username')
.form-group
.input-group
- = text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_user_field' }
+ = text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { testid: 'deploy-token-user-field' }
.input-group-append
= deprecated_clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-success
@@ -15,7 +15,7 @@
.form-group
.input-group
- = text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_field' }
+ = text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { testid: 'deploy-token-field' }
.input-group-append
= deprecated_clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-danger