diff options
Diffstat (limited to 'app/assets/javascripts/ci')
36 files changed, 308 insertions, 112 deletions
diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue index 6d062d8b7f1..7085397c649 100644 --- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue +++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue @@ -106,7 +106,7 @@ export default { <div class="gl-display-flex"> <pre class="gl-w-85p gl-py-4 gl-display-flex gl-justify-content-space-between gl-m-0 gl-border-r-none" - ><span>{{ generateSnippet(component.path) }}</span> + ><span>{{ generateSnippet(component.includePath) }}</span> </pre> <div class="gl--flex-center gl-bg-gray-10 gl-border gl-border-l-none"> <gl-button @@ -115,7 +115,7 @@ export default { icon="copy-to-clipboard" size="small" :title="$options.i18n.copyText" - :data-clipboard-text="generateSnippet(component.path)" + :data-clipboard-text="generateSnippet(component.includePath)" data-testid="copy-to-clipboard" :aria-label="$options.i18n.copyAriaText" /> diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue index b9d6173a777..929175b964f 100644 --- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue +++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_header.vue @@ -49,7 +49,7 @@ export default { return getIdFromGraphQLId(this.resource.id); }, hasLatestVersion() { - return this.latestVersion?.tagName; + return this.latestVersion?.name; }, hasPipelineStatus() { return this.pipelineStatus?.text; @@ -58,7 +58,7 @@ export default { return this.resource.latestVersion; }, versionBadgeText() { - return this.latestVersion.tagName; + return this.latestVersion.name; }, webPath() { return cleanLeadingSeparator(this.resource?.webPath); @@ -92,7 +92,7 @@ export default { v-if="hasLatestVersion" size="sm" class="gl-ml-3 gl-my-1" - :href="latestVersion.tagPath" + :href="latestVersion.path" > {{ versionBadgeText }} </gl-badge> diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_readme.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_readme.vue index 343b555c4d8..ccef50e469d 100644 --- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_readme.vue +++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_readme.vue @@ -50,6 +50,6 @@ export default { <template> <div> <gl-loading-icon v-if="isLoading" class="gl-mt-5" size="lg" /> - <div v-else v-safe-html="readmeHtml"></div> + <div v-else v-safe-html="readmeHtml" class="md"></div> </div> </template> 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 3a9ec341789..001e3ec3720 100644 --- a/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue +++ b/app/assets/javascripts/ci/catalog/components/list/catalog_header.vue @@ -1,5 +1,6 @@ <script> import { GlBanner, GlLink } from '@gitlab/ui'; +import ChatBubbleSvg from '@gitlab/svgs/dist/illustrations/chat-sm.svg?url'; import { __, s__ } from '~/locale'; import { helpPagePath } from '~/helpers/help_page_helper'; import BetaBadge from '~/vue_shared/components/badges/beta_badge.vue'; @@ -44,6 +45,7 @@ export default { learnMore: __('Learn more'), }, learnMorePath: helpPagePath('ci/components/index'), + ChatBubbleSvg, }; </script> <template> @@ -54,6 +56,7 @@ export default { :title="$options.i18n.banner.title" :button-text="$options.i18n.banner.btnText" button-link="https://gitlab.com/gitlab-org/gitlab/-/issues/407556" + :svg-path="$options.ChatBubbleSvg" @close="handleDismissBanner" > <p> diff --git a/app/assets/javascripts/ci/catalog/components/list/catalog_search.vue b/app/assets/javascripts/ci/catalog/components/list/catalog_search.vue index e074cfda6f7..1319f204573 100644 --- a/app/assets/javascripts/ci/catalog/components/list/catalog_search.vue +++ b/app/assets/javascripts/ci/catalog/components/list/catalog_search.vue @@ -1,5 +1,5 @@ <script> -import { GlSearchBoxByClick, GlSorting, GlSortingItem } from '@gitlab/ui'; +import { GlSearchBoxByClick, GlSorting } from '@gitlab/ui'; import { __ } from '~/locale'; import { SORT_ASC, SORT_DESC, SORT_OPTION_CREATED } from '../../constants'; @@ -7,7 +7,6 @@ export default { components: { GlSearchBoxByClick, GlSorting, - GlSortingItem, }, data() { return { @@ -25,7 +24,7 @@ export default { }, currentSortText() { const currentSort = this.$options.sortOptions.find( - (sort) => sort.key === this.currentSortOption, + (sort) => sort.value === this.currentSortOption, ); return currentSort.text; }, @@ -36,9 +35,6 @@ export default { }, }, methods: { - isActiveSort(sortItem) { - return sortItem === this.currentSortOption; - }, onClear() { this.$emit('update-search-term', ''); }, @@ -49,10 +45,10 @@ export default { this.$emit('update-search-term', this.searchTerm); }, setSelectedSortOption(sortingItem) { - this.currentSortOption = sortingItem.key; + this.currentSortOption = sortingItem; }, }, - sortOptions: [{ key: SORT_OPTION_CREATED, text: __('Created at') }], + sortOptions: [{ value: SORT_OPTION_CREATED, text: __('Created at') }], }; </script> <template> @@ -66,16 +62,10 @@ export default { <gl-sorting :is-ascending="isAscending" :text="currentSortText" + :sort-options="$options.sortOptions" + :sort-by="currentSortOption" + @sortByChange="setSelectedSortOption" @sortDirectionChange="onSortDirectionChange" - > - <gl-sorting-item - v-for="sortingItem in $options.sortOptions" - :key="sortingItem.key" - :active="isActiveSort(sortingItem.key)" - @click="setSelectedSortOption(sortingItem)" - > - {{ sortingItem.text }} - </gl-sorting-item> - </gl-sorting> + /> </div> </template> diff --git a/app/assets/javascripts/ci/catalog/components/list/catalog_tabs.vue b/app/assets/javascripts/ci/catalog/components/list/catalog_tabs.vue new file mode 100644 index 00000000000..f43255ab76b --- /dev/null +++ b/app/assets/javascripts/ci/catalog/components/list/catalog_tabs.vue @@ -0,0 +1,67 @@ +<script> +import { GlBadge, GlTab, GlTabs, GlLoadingIcon } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { SCOPE } from '../../constants'; + +export default { + components: { + GlBadge, + GlTab, + GlTabs, + GlLoadingIcon, + }, + props: { + isLoading: { + type: Boolean, + required: true, + }, + resourceCounts: { + type: Object, + required: true, + }, + }, + computed: { + tabs() { + return [ + { + text: s__('CiCatalog|All'), + scope: SCOPE.all, + testId: 'resources-all-tab', + count: this.resourceCounts.all, + }, + { + text: s__('CiCatalog|Your resources'), + scope: SCOPE.namespaces, + testId: 'resources-your-tab', + count: this.resourceCounts.namespaces, + }, + ]; + }, + showLoadingIcon() { + return this.isLoading; + }, + }, +}; +</script> + +<template> + <div class="gl-display-flex align-items-lg-center"> + <gl-tabs content-class="gl-py-0" class="gl-w-full"> + <gl-tab + v-for="tab in tabs" + :key="tab.text" + :data-testid="tab.testId" + @click="$emit('setScope', tab.scope)" + > + <template #title> + <span>{{ tab.text }}</span> + <gl-loading-icon v-if="showLoadingIcon" class="gl-ml-3" /> + + <gl-badge v-else size="sm" class="gl-tab-counter-badge"> + {{ tab.count }} + </gl-badge> + </template> + </gl-tab> + </gl-tabs> + </div> +</template> diff --git a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue index 57d19af614f..42f8cea8727 100644 --- a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue +++ b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue @@ -67,8 +67,8 @@ export default { releasedAt() { return getTimeago().format(this.latestVersion?.releasedAt); }, - tagName() { - return this.latestVersion?.tagName || this.$options.i18n.unreleased; + name() { + return this.latestVersion?.name || this.$options.i18n.unreleased; }, webPath() { return cleanLeadingSeparator(this.resource?.webPath); @@ -117,7 +117,7 @@ export default { <b> {{ resource.name }}</b> </gl-link> <div class="gl-display-flex gl-flex-grow-1 gl-md-justify-content-space-between"> - <gl-badge size="sm" class="gl-h-5 gl-align-self-center">{{ tagName }}</gl-badge> + <gl-badge size="sm" class="gl-h-5 gl-align-self-center">{{ name }}</gl-badge> <span class="gl-display-flex gl-align-items-center gl-ml-5"> <span v-gl-tooltip.top 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 index e1c86f38d7e..08500d3093c 100644 --- a/app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue +++ b/app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue @@ -3,6 +3,7 @@ import { createAlert } from '~/alert'; import { s__ } from '~/locale'; import { ciCatalogResourcesItemsCount } from '~/ci/catalog/graphql/settings'; import CatalogSearch from '../list/catalog_search.vue'; +import CatalogTabs from '../list/catalog_tabs.vue'; import CiResourcesList from '../list/ci_resources_list.vue'; import CatalogListSkeletonLoader from '../list/catalog_list_skeleton_loader.vue'; import CatalogHeader from '../list/catalog_header.vue'; @@ -10,29 +11,60 @@ import EmptyState from '../list/empty_state.vue'; import getCatalogResources from '../../graphql/queries/get_ci_catalog_resources.query.graphql'; import getCurrentPage from '../../graphql/queries/client/get_current_page.query.graphql'; import updateCurrentPageMutation from '../../graphql/mutations/client/update_current_page.mutation.graphql'; +import getCatalogResourcesCount from '../../graphql/queries/get_ci_catalog_resources_count.query.graphql'; +import { DEFAULT_SORT_VALUE, SCOPE } from '../../constants'; export default { + i18n: { + fetchError: s__('CiCatalog|There was an error fetching CI/CD Catalog resources.'), + countFetchError: s__('CiCatalog|There was an error fetching the CI/CD Catalog resource count.'), + }, components: { CatalogHeader, CatalogListSkeletonLoader, CatalogSearch, + CatalogTabs, CiResourcesList, EmptyState, }, data() { return { catalogResources: [], + catalogResourcesCount: { all: 0, namespaces: 0 }, currentPage: 1, pageInfo: {}, - searchTerm: '', - totalCount: 0, + scope: SCOPE.all, + searchTerm: null, + sortValue: DEFAULT_SORT_VALUE, }; }, apollo: { + catalogResourcesCount: { + query: getCatalogResourcesCount, + variables() { + return { + searchTerm: this.searchTerm, + }; + }, + update({ namespaces, all }) { + return { + namespaces: namespaces.count, + all: all.count, + }; + }, + error(e) { + createAlert({ + message: e.message || this.$options.i18n.countFetchError, + }); + }, + }, catalogResources: { query: getCatalogResources, variables() { return { + scope: this.scope, + searchTerm: this.searchTerm, + sortValue: this.sortValue, first: ciCatalogResourcesItemsCount, }; }, @@ -42,10 +74,9 @@ export default { 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' }); + createAlert({ message: e.message || this.$options.i18n.fetchError }); }, }, currentPage: { @@ -62,11 +93,14 @@ export default { isLoading() { return this.$apollo.queries.catalogResources.loading; }, - isSearching() { - return this.searchTerm?.length > 0; + isLoadingCounts() { + return this.$apollo.queries.catalogResourcesCount.loading; + }, + namespacesCount() { + return this.catalogResourcesCount.namespaces; }, - showEmptyState() { - return !this.hasResources && !this.isSearching; + currentTabTotalCount() { + return this.catalogResourcesCount[this.scope.toLowerCase()]; }, }, methods: { @@ -103,6 +137,11 @@ export default { createAlert({ message: e?.message || this.$options.i18n.fetchError, variant: 'danger' }); } }, + handleSetScope(scope) { + if (this.scope === scope) return; + + this.scope = scope; + }, updatePageCount(pageNumber) { this.$apollo.mutate({ mutation: updateCurrentPageMutation, @@ -120,30 +159,28 @@ export default { onUpdateSearchTerm(searchTerm) { this.searchTerm = !searchTerm.length ? null : searchTerm; this.resetPageCount(); - this.$apollo.queries.catalogResources.refetch({ - searchTerm: this.searchTerm, - }); }, onUpdateSorting(sortValue) { + this.sortValue = sortValue; this.resetPageCount(); - this.$apollo.queries.catalogResources.refetch({ - sortValue, - }); }, resetPageCount() { this.updatePageCount(1); }, }, - i18n: { - fetchError: s__('CiCatalog|There was an error fetching CI/CD Catalog resources.'), - }, }; </script> <template> <div> <catalog-header /> + <catalog-tabs + :is-loading="isLoadingCounts" + :resource-counts="catalogResourcesCount" + class="gl-mb-3" + @setScope="handleSetScope" + /> <catalog-search - class="gl-py-4 gl-border-b-1 gl-border-gray-100 gl-border-b-solid gl-border-t-1 gl-border-t-solid" + class="gl-py-2" @update-search-term="onUpdateSearchTerm" @update-sorting="onUpdateSorting" /> @@ -156,7 +193,7 @@ export default { :prev-text="__('Prev')" :next-text="__('Next')" :resources="catalogResources" - :total-count="totalCount" + :total-count="currentTabTotalCount" @onPrevPage="handlePrevPage" @onNextPage="handleNextPage" /> diff --git a/app/assets/javascripts/ci/catalog/constants.js b/app/assets/javascripts/ci/catalog/constants.js index 34c0ac797c1..a180aa84344 100644 --- a/app/assets/javascripts/ci/catalog/constants.js +++ b/app/assets/javascripts/ci/catalog/constants.js @@ -2,8 +2,14 @@ import { helpPagePath } from '~/helpers/help_page_helper'; export const CATALOG_FEEDBACK_DISMISSED_KEY = 'catalog_feedback_dismissed'; +export const SCOPE = { + all: 'ALL', + namespaces: 'NAMESPACES', +}; + export const SORT_OPTION_CREATED = 'CREATED'; export const SORT_ASC = 'ASC'; export const SORT_DESC = 'DESC'; +export const DEFAULT_SORT_VALUE = `${SORT_OPTION_CREATED}_${SORT_DESC}`; export const COMPONENTS_DOCS_URL = helpPagePath('ci/components/index'); diff --git a/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql b/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql index b3a750e9604..316308e96d7 100644 --- a/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql +++ b/app/assets/javascripts/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql @@ -7,8 +7,8 @@ fragment CatalogResourceFields on CiCatalogResource { starCount latestVersion { id - tagName - tagPath + name + path releasedAt author { id diff --git a/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_create.mutation.graphql b/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_create.mutation.graphql new file mode 100644 index 00000000000..c3b73ebf248 --- /dev/null +++ b/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_create.mutation.graphql @@ -0,0 +1,5 @@ +mutation catalogResourcesCreate($input: CatalogResourcesCreateInput!) { + catalogResourcesCreate(input: $input) { + errors + } +} diff --git a/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_destroy.mutation.graphql b/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_destroy.mutation.graphql new file mode 100644 index 00000000000..fa42b081a5f --- /dev/null +++ b/app/assets/javascripts/ci/catalog/graphql/mutations/catalog_resources_destroy.mutation.graphql @@ -0,0 +1,5 @@ +mutation catalogResourcesDestroy($input: CatalogResourcesDestroyInput!) { + catalogResourcesDestroy(input: $input) { + errors + } +} diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql index 41ac72aa9de..bf1edf1af6e 100644 --- a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql +++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql @@ -8,7 +8,7 @@ query getCiCatalogResourceComponents($fullPath: ID!) { nodes { id name - path + includePath inputs { name required diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_details.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_details.query.graphql index a77e8f12d03..efc8aa777d4 100644 --- a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_details.query.graphql +++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_details.query.graphql @@ -22,7 +22,7 @@ query getCiCatalogResourceDetails($fullPath: ID!) { } } } - tagName + name releasedAt } } 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 index 1cf213dec63..24789e9c4ed 100644 --- 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 @@ -1,6 +1,7 @@ #import "~/ci/catalog/graphql/fragments/catalog_resource.fragment.graphql" query getCatalogResources( + $scope: CiCatalogResourceScope $searchTerm: String $sortValue: CiCatalogResourceSort $after: String @@ -9,6 +10,7 @@ query getCatalogResources( $last: Int ) { ciCatalogResources( + scope: $scope search: $searchTerm sort: $sortValue after: $after @@ -22,7 +24,6 @@ query getCatalogResources( hasNextPage hasPreviousPage } - count nodes { ...CatalogResourceFields } diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources_count.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources_count.query.graphql new file mode 100644 index 00000000000..d4a298e7e09 --- /dev/null +++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resources_count.query.graphql @@ -0,0 +1,8 @@ +query getCatalogResourcesCount($searchTerm: String) { + all: ciCatalogResources(scope: ALL, search: $searchTerm) { + count + } + namespaces: ciCatalogResources(scope: NAMESPACES, search: $searchTerm) { + count + } +} diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_settings.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_settings.query.graphql new file mode 100644 index 00000000000..0de06028386 --- /dev/null +++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_settings.query.graphql @@ -0,0 +1,6 @@ +query getCiCatalogSettings($fullPath: ID!) { + project(fullPath: $fullPath) { + id + isCatalogResource + } +} diff --git a/app/assets/javascripts/ci/catalog/graphql/settings.js b/app/assets/javascripts/ci/catalog/graphql/settings.js index 4038188a7ce..abc95592b14 100644 --- a/app/assets/javascripts/ci/catalog/graphql/settings.js +++ b/app/assets/javascripts/ci/catalog/graphql/settings.js @@ -15,7 +15,7 @@ export const cacheConfig = { }); }, ciCatalogResources: { - keyArgs: false, + keyArgs: ['scope', 'search', 'sort'], }, }, }, diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue b/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue index 77af643cbb3..2d2e3e280c0 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue +++ b/app/assets/javascripts/ci/ci_environments_dropdown/ci_environments_dropdown.vue @@ -3,8 +3,12 @@ import { debounce, uniq } from 'lodash'; import { GlDropdownDivider, GlDropdownItem, GlCollapsibleListbox, GlSprintf } from '@gitlab/ui'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { __, s__, sprintf } from '~/locale'; -import { convertEnvironmentScope } from '../utils'; -import { ENVIRONMENT_QUERY_LIMIT } from '../constants'; +import { convertEnvironmentScope } from './utils'; +import { + ALL_ENVIRONMENTS_OPTION, + ENVIRONMENT_QUERY_LIMIT, + NO_ENVIRONMENT_OPTION, +} from './constants'; export default { name: 'CiEnvironmentsDropdown', @@ -16,10 +20,20 @@ export default { }, mixins: [glFeatureFlagsMixin()], props: { + isEnvironmentRequired: { + type: Boolean, + required: false, + default: true, + }, areEnvironmentsLoading: { type: Boolean, required: true, }, + canCreateWildcard: { + type: Boolean, + required: false, + default: true, + }, environments: { type: Array, required: true, @@ -51,22 +65,31 @@ export default { searchedEnvironments() { let filtered = this.environments; - // If there is no search term, make sure to include * - if (!this.searchTerm) { - filtered = uniq([...filtered, '*']); - } - // add custom env scope if it matches the search term if (this.customEnvScope && this.customEnvScope.startsWith(this.searchTerm)) { filtered = uniq([...filtered, this.customEnvScope]); } + // If there is no search term, make sure to include * + if (!this.searchTerm) { + filtered = uniq([...filtered, ALL_ENVIRONMENTS_OPTION.type]); + + // lastly, add Not Applicable (None) as the first option if isEnvironmentRequired is true + if (!this.isEnvironmentRequired) { + filtered = [NO_ENVIRONMENT_OPTION.type, ...filtered]; + } + } + return filtered.sort().map((environment) => ({ value: environment, text: environment, })); }, shouldRenderCreateButton() { + if (!this.canCreateWildcard) { + return false; + } + return ( this.searchTerm && ![...this.environments, this.customEnvScope].includes(this.searchTerm) ); diff --git a/app/assets/javascripts/ci/ci_environments_dropdown/constants.js b/app/assets/javascripts/ci/ci_environments_dropdown/constants.js new file mode 100644 index 00000000000..98e543a75d0 --- /dev/null +++ b/app/assets/javascripts/ci/ci_environments_dropdown/constants.js @@ -0,0 +1,14 @@ +import { __ } from '~/locale'; + +export const ENVIRONMENT_QUERY_LIMIT = 30; + +export const ALL_ENVIRONMENTS_OPTION = { + type: '*', + text: __('All (default)'), +}; + +export const NO_ENVIRONMENT_OPTION = { + // TODO: This is a placeholder value. It will be replaced with the actual value used once it's implemented on the backend + type: 'Not applicable', + text: __('Not applicable'), +}; diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_environments.query.graphql b/app/assets/javascripts/ci/ci_environments_dropdown/graphql/queries/group_environments.query.graphql index 5768d370474..5768d370474 100644 --- a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/group_environments.query.graphql +++ b/app/assets/javascripts/ci/ci_environments_dropdown/graphql/queries/group_environments.query.graphql diff --git a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_environments.query.graphql b/app/assets/javascripts/ci/ci_environments_dropdown/graphql/queries/project_environments.query.graphql index 26d1b6a3aaa..26d1b6a3aaa 100644 --- a/app/assets/javascripts/ci/ci_variable_list/graphql/queries/project_environments.query.graphql +++ b/app/assets/javascripts/ci/ci_environments_dropdown/graphql/queries/project_environments.query.graphql diff --git a/app/assets/javascripts/ci/ci_variable_list/utils.js b/app/assets/javascripts/ci/ci_environments_dropdown/utils.js index a7e020206ea..093b04dab0c 100644 --- a/app/assets/javascripts/ci/ci_variable_list/utils.js +++ b/app/assets/javascripts/ci/ci_environments_dropdown/utils.js @@ -1,4 +1,4 @@ -import { allEnvironments } from './constants'; +import { ALL_ENVIRONMENTS_OPTION, NO_ENVIRONMENT_OPTION } from './constants'; /** * This function job is to convert the * wildcard to text when applicable @@ -10,11 +10,14 @@ import { allEnvironments } from './constants'; */ export const convertEnvironmentScope = (environmentScope = '') => { - if (environmentScope === allEnvironments.type || !environmentScope) { - return allEnvironments.text; + switch (environmentScope) { + case ALL_ENVIRONMENTS_OPTION.type || '': + return ALL_ENVIRONMENTS_OPTION.text; + case NO_ENVIRONMENT_OPTION.type: + return NO_ENVIRONMENT_OPTION.text; + default: + return environmentScope; } - - return environmentScope; }; /** diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_group_variables.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_group_variables.vue index 842d88e1267..b118d54d2b0 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_group_variables.vue +++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_group_variables.vue @@ -2,8 +2,8 @@ import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { getGroupEnvironments } from '~/ci/common/private/ci_environments_dropdown'; import { ADD_MUTATION_ACTION, DELETE_MUTATION_ACTION, UPDATE_MUTATION_ACTION } from '../constants'; -import getGroupEnvironments from '../graphql/queries/group_environments.query.graphql'; import getGroupVariables from '../graphql/queries/group_variables.query.graphql'; import addGroupVariable from '../graphql/mutations/group_add_variable.mutation.graphql'; import deleteGroupVariable from '../graphql/mutations/group_delete_variable.mutation.graphql'; diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_project_variables.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_project_variables.vue index 43938e9b88f..822a2b01f24 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_project_variables.vue +++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_project_variables.vue @@ -2,8 +2,8 @@ import { TYPENAME_PROJECT } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { getProjectEnvironments } from '~/ci/common/private/ci_environments_dropdown'; import { ADD_MUTATION_ACTION, DELETE_MUTATION_ACTION, UPDATE_MUTATION_ACTION } from '../constants'; -import getProjectEnvironments from '../graphql/queries/project_environments.query.graphql'; import getProjectVariables from '../graphql/queries/project_variables.query.graphql'; import addProjectVariable from '../graphql/mutations/project_add_variable.mutation.graphql'; import deleteProjectVariable from '../graphql/mutations/project_delete_variable.mutation.graphql'; diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue index 2ad6c7c6578..ad4b7b790d0 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue +++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue @@ -20,8 +20,8 @@ import { DRAWER_Z_INDEX } from '~/lib/utils/constants'; import { getContentWrapperHeight } from '~/lib/utils/dom_utils'; import { helpPagePath } from '~/helpers/help_page_helper'; import Tracking from '~/tracking'; +import CiEnvironmentsDropdown from '~/ci/common/private/ci_environments_dropdown'; import { - allEnvironments, defaultVariableState, DRAWER_EVENT_LABEL, EDIT_VARIABLE_ACTION, @@ -34,7 +34,6 @@ import { variableOptions, WHITESPACE_REG_EX, } from '../constants'; -import CiEnvironmentsDropdown from './ci_environments_dropdown.vue'; import { awsTokenList } from './ci_variable_autocomplete_tokens'; const trackingMixin = Tracking.mixin({ label: DRAWER_EVENT_LABEL }); @@ -43,9 +42,10 @@ const KEY_REGEX = /^\w+$/; export const i18n = { addVariable: s__('CiVariables|Add variable'), cancel: __('Cancel'), - defaultScope: allEnvironments.text, + defaultScope: __('All (default)'), deleteVariable: s__('CiVariables|Delete variable'), editVariable: s__('CiVariables|Edit variable'), + saveVariable: __('Save changes'), environments: __('Environments'), environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE, expandedField: s__('CiVariables|Expand variable reference'), @@ -259,9 +259,12 @@ export default { return validationIssuesText.trim(); }, - modalActionText() { + modalTitle() { return this.isEditing ? this.$options.i18n.editVariable : this.$options.i18n.addVariable; }, + modalActionText() { + return this.isEditing ? this.$options.i18n.saveVariable : this.$options.i18n.addVariable; + }, removeVariableMessage() { return sprintf(this.$options.i18n.modalDeleteMessage, { key: this.variable.key }); }, @@ -359,7 +362,7 @@ export default { @close="close" > <template #title> - <h2 class="gl-m-0">{{ modalActionText }}</h2> + <h2 class="gl-m-0">{{ modalTitle }}</h2> </template> <gl-form-group :label="$options.i18n.type" @@ -493,8 +496,8 @@ export default { v-model="variable.value" :spellcheck="false" class="gl-border-none gl-font-monospace!" - rows="3" - max-rows="10" + rows="5" + :no-resize="false" data-testid="ci-variable-value" /> <p @@ -515,9 +518,15 @@ export default { > {{ $options.i18n.variableReferenceDescription }} </gl-alert> - <div class="gl-display-flex gl-justify-content-end"> - <gl-button category="secondary" class="gl-mr-3" data-testid="cancel-button" @click="close" - >{{ $options.i18n.cancel }} + <div class="gl-display-flex"> + <gl-button + category="primary" + class="gl-mr-3" + variant="confirm" + :disabled="!canSubmit" + data-testid="ci-variable-confirm-button" + @click="submit" + >{{ modalActionText }} </gl-button> <gl-button v-if="isEditing" @@ -528,13 +537,8 @@ export default { data-testid="ci-variable-delete-button" >{{ $options.i18n.deleteVariable }}</gl-button > - <gl-button - category="primary" - variant="confirm" - :disabled="!canSubmit" - data-testid="ci-variable-confirm-button" - @click="submit" - >{{ modalActionText }} + <gl-button category="secondary" class="gl-mr-3" data-testid="cancel-button" @click="close" + >{{ $options.i18n.cancel }} </gl-button> </div> </gl-drawer> diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue index 011a424b6c2..609b8523612 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue +++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue @@ -3,11 +3,13 @@ import { createAlert } from '~/alert'; import { __ } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { reportToSentry } from '~/ci/utils'; -import { mapEnvironmentNames } from '../utils'; +import { + ENVIRONMENT_QUERY_LIMIT, + mapEnvironmentNames, +} from '~/ci/common/private/ci_environments_dropdown'; import { ADD_MUTATION_ACTION, DELETE_MUTATION_ACTION, - ENVIRONMENT_QUERY_LIMIT, SORT_DIRECTIONS, UPDATE_MUTATION_ACTION, mapMutationActionToToast, diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue index 86287d586ec..901bd39930a 100644 --- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue +++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue @@ -15,13 +15,13 @@ import { } from '@gitlab/ui'; import { __, s__, sprintf } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { convertEnvironmentScope } from '~/ci/common/private/ci_environments_dropdown'; import { DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT, EXCEEDS_VARIABLE_LIMIT_TEXT, MAXIMUM_VARIABLE_LIMIT_REACHED, variableTypes, } from '../constants'; -import { convertEnvironmentScope } from '../utils'; export default { defaultFields: [ diff --git a/app/assets/javascripts/ci/ci_variable_list/constants.js b/app/assets/javascripts/ci/ci_variable_list/constants.js index 4ec7333f465..c4f92fed829 100644 --- a/app/assets/javascripts/ci/ci_variable_list/constants.js +++ b/app/assets/javascripts/ci/ci_variable_list/constants.js @@ -1,7 +1,5 @@ import { __, s__, sprintf } from '~/locale'; -export const ENVIRONMENT_QUERY_LIMIT = 30; - export const MASKED_VALUE_MIN_LENGTH = 8; export const WHITESPACE_REG_EX = /\s/; @@ -15,18 +13,13 @@ export const variableTypes = { fileType: 'FILE', }; -export const allEnvironments = { - type: '*', - text: __('All (default)'), -}; - export const variableOptions = [ { value: variableTypes.envType, text: __('Variable (default)') }, { value: variableTypes.fileType, text: __('File') }, ]; export const defaultVariableState = { - environmentScope: allEnvironments.type, + environmentScope: '*', key: '', masked: false, protected: false, diff --git a/app/assets/javascripts/ci/common/private/ci_environments_dropdown.js b/app/assets/javascripts/ci/common/private/ci_environments_dropdown.js new file mode 100644 index 00000000000..f8958f9600c --- /dev/null +++ b/app/assets/javascripts/ci/common/private/ci_environments_dropdown.js @@ -0,0 +1,9 @@ +import CiEnvironmentsDropdown from '~/ci/ci_environments_dropdown/ci_environments_dropdown.vue'; + +export default CiEnvironmentsDropdown; + +export { getGroupEnvironments } from '~/ci/ci_environments_dropdown/graphql/queries/group_environments.query.graphql'; +export { getProjectEnvironments } from '~/ci/ci_environments_dropdown/graphql/queries/project_environments.query.graphql'; + +export { ENVIRONMENT_QUERY_LIMIT } from '~/ci/ci_environments_dropdown/constants'; +export * from '~/ci/ci_environments_dropdown/utils'; diff --git a/app/assets/javascripts/ci/pipeline_details/constants.js b/app/assets/javascripts/ci/pipeline_details/constants.js index 51d0e980e78..90e723ea442 100644 --- a/app/assets/javascripts/ci/pipeline_details/constants.js +++ b/app/assets/javascripts/ci/pipeline_details/constants.js @@ -5,7 +5,7 @@ export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source export const NEEDS_PROPERTY = 'needs'; export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds'; -export const TestStatus = { +export const testStatus = { FAILED: 'failed', SKIPPED: 'skipped', SUCCESS: 'success', diff --git a/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js index e3984685094..87081e61e48 100644 --- a/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js +++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js @@ -1,6 +1,6 @@ import { __, sprintf } from '~/locale'; import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; -import { TestStatus } from '../../constants'; +import { testStatus } from '../../constants'; /** * Removes `./` from the beginning of a file path so it can be appended onto a blob path @@ -13,15 +13,15 @@ export function formatFilePath(file) { export function iconForTestStatus(status) { switch (status) { - case TestStatus.SUCCESS: + case testStatus.SUCCESS: return 'status_success'; - case TestStatus.FAILED: + case testStatus.FAILED: return 'status_failed'; - case TestStatus.ERROR: + case testStatus.ERROR: return 'status_warning'; - case TestStatus.SKIPPED: + case testStatus.SKIPPED: return 'status_skipped'; - case TestStatus.UNKNOWN: + case testStatus.UNKNOWN: default: return 'status_notfound'; } diff --git a/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue index 6e9a705c046..5fd9f7cfd4f 100644 --- a/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue +++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue @@ -2,7 +2,12 @@ import { GlLoadingIcon } from '@gitlab/ui'; // eslint-disable-next-line no-restricted-imports import { mapActions, mapGetters, mapState } from 'vuex'; -import { getParameterValues } from '~/lib/utils/url_utility'; +import { + getParameterValues, + updateHistory, + setUrlParams, + removeParams, +} from '~/lib/utils/url_utility'; import EmptyState from './empty_state.vue'; import TestSuiteTable from './test_suite_table.vue'; import TestSummary from './test_summary.vue'; @@ -49,12 +54,28 @@ export default { ]), summaryBackClick() { this.removeSelectedSuiteIndex(); + + updateHistory({ + url: removeParams(['job_name']), + title: document.title, + replace: true, + }); }, summaryTableRowClick(index) { this.setSelectedSuiteIndex(index); // Fetch the test suite when the user clicks to see more details this.fetchTestSuite(index); + + const urlParams = { + job_name: this.getSelectedSuite.name, + }; + + updateHistory({ + url: setUrlParams(urlParams), + title: document.title, + replace: true, + }); }, beforeEnterTransition() { document.documentElement.style.overflowX = 'hidden'; diff --git a/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue b/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue index 1d152a63407..a6e679e6d4e 100644 --- a/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue +++ b/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue @@ -13,6 +13,7 @@ import { } from '@gitlab/ui'; import { s__, __ } from '~/locale'; import Tracking from '~/tracking'; +import { helpPagePath } from '~/helpers/help_page_helper'; import { pipelineEditorTrackingOptions } from '../../constants'; import ValidatePipelinePopover from '../popovers/validate_pipeline_popover.vue'; import CiLintResults from '../lint/ci_lint_results.vue'; @@ -189,6 +190,7 @@ export default { }, i18n, BASE_CLASSES, + lintHref: helpPagePath('ci/lint.md'), }; </script> @@ -290,7 +292,7 @@ export default { <code>{{ content }}</code> </template> <template #link="{ content }"> - <gl-link target="_blank" href="#">{{ content }}</gl-link> + <gl-link target="_blank" :href="$options.lintHref">{{ content }}</gl-link> </template> </gl-sprintf> </gl-alert> diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue index e287e4e17d1..63957d9b7fc 100644 --- a/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue +++ b/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue @@ -33,16 +33,13 @@ export default { </script> <template> - <div> + <div class="gl-display-flex gl-flex-wrap gl-gap-2"> <runner-status-badge :contacted-at="contactedAt" :status="status" - class="gl-display-inline-block gl-max-w-full gl-text-truncate" - /> - <runner-paused-badge - v-if="paused" - class="gl-display-inline-block gl-max-w-full gl-text-truncate" + class="gl-max-w-full gl-text-truncate" /> + <runner-paused-badge v-if="paused" class="gl-max-w-full gl-text-truncate" /> <slot :runner="runner" name="runner-job-status-badge"></slot> </div> </template> diff --git a/app/assets/javascripts/ci/runner/components/runner_job_status_badge.vue b/app/assets/javascripts/ci/runner/components/runner_job_status_badge.vue index bed592e3f30..0dc23882cdc 100644 --- a/app/assets/javascripts/ci/runner/components/runner_job_status_badge.vue +++ b/app/assets/javascripts/ci/runner/components/runner_job_status_badge.vue @@ -26,12 +26,12 @@ export default { switch (this.jobStatus) { case JOB_STATUS_RUNNING: return { - classes: 'gl-text-blue-600! gl-border gl-border-blue-600!', + classes: 'gl-text-blue-600! gl-inset-border-1-gray-400 gl-border-blue-600!', label: I18N_JOB_STATUS_RUNNING, }; case JOB_STATUS_IDLE: return { - classes: 'gl-text-gray-700! gl-border gl-border-gray-500!', + classes: 'gl-text-gray-700! gl-inset-border-1-gray-400 gl-border-gray-500!', label: I18N_JOB_STATUS_IDLE, }; default: @@ -45,7 +45,7 @@ export default { <gl-badge v-if="badge" v-bind="$attrs" - class="gl-display-inline-block gl-max-w-full gl-text-truncate gl-bg-transparent!" + class="gl-max-w-full gl-text-truncate gl-bg-transparent!" variant="muted" :class="badge.classes" > |