diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-28 18:07:23 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-28 18:07:23 +0300 |
commit | 20d52aa39ef79bc199e1459e385387baeb04d99f (patch) | |
tree | e13dc3aec8c70ad4c522452068b96fd98f2b3fa5 /app | |
parent | d30b2ead9a6606035a5d650216b9b5630b010421 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
10 files changed, 111 insertions, 60 deletions
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue index 00e0649deed..5e0c5735bc0 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue @@ -1,14 +1,5 @@ <script> -import { - GlButton, - GlButtonGroup, - GlDropdown, - GlDropdownItem, - GlDropdownText, - GlDropdownSectionHeader, - GlSearchBoxByType, - GlTruncate, -} from '@gitlab/ui'; +import { GlButton, GlButtonGroup, GlCollapsibleListbox } from '@gitlab/ui'; import { createAlert } from '~/flash'; import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants'; import { s__ } from '~/locale'; @@ -20,12 +11,7 @@ export default { components: { GlButton, GlButtonGroup, - GlDropdown, - GlDropdownItem, - GlDropdownText, - GlDropdownSectionHeader, - GlSearchBoxByType, - GlTruncate, + GlCollapsibleListbox, }, apollo: { project: { @@ -61,24 +47,25 @@ export default { }; }, computed: { + loading() { + return this.$apollo.queries.project.loading; + }, rootUrl() { return `${gon.gitlab_url}/`; }, namespaces() { return this.project.forkTargets?.nodes || []; }, - hasMatches() { - return this.namespaces.length; - }, dropdownText() { return this.selectedNamespace?.fullPath || s__('ForkProject|Select a namespace'); }, + namespaceItems() { + return this.namespaces?.map(({ id, fullPath }) => ({ value: id, text: fullPath })); + }, }, methods: { - handleDropdownShown() { - this.$refs.search.focusInput(); - }, - setNamespace(namespace) { + setNamespace(namespaceId) { + const namespace = this.namespaces.find(({ id }) => id === namespaceId); const id = getIdFromGraphQLId(namespace.id); this.$emit('select', { @@ -89,6 +76,9 @@ export default { this.selectedNamespace = { id, fullPath: namespace.fullPath }; }, + searchNamespaces(search) { + this.search = search; + }, }, }; </script> @@ -98,39 +88,19 @@ export default { <gl-button class="gl-text-truncate gl-flex-grow-0! gl-max-w-34" label :title="rootUrl">{{ rootUrl }}</gl-button> - - <gl-dropdown + <gl-collapsible-listbox class="gl-flex-grow-1" - toggle-class="gl-rounded-top-right-base! gl-rounded-bottom-right-base! gl-w-20" data-qa-selector="select_namespace_dropdown" data-testid="select_namespace_dropdown" - no-flip - @shown="handleDropdownShown" - > - <template #button-text> - <gl-truncate :text="dropdownText" position="start" with-tooltip /> - </template> - <gl-search-box-by-type - ref="search" - v-model.trim="search" - :is-loading="$apollo.queries.project.loading" - data-qa-selector="select_namespace_dropdown_search_field" - data-testid="select_namespace_dropdown_search_field" - /> - <template v-if="!$apollo.queries.project.loading"> - <template v-if="hasMatches"> - <gl-dropdown-section-header>{{ __('Namespaces') }}</gl-dropdown-section-header> - <gl-dropdown-item - v-for="namespace of namespaces" - :key="namespace.id" - data-qa-selector="select_namespace_dropdown_item" - @click="setNamespace(namespace)" - > - {{ namespace.fullPath }} - </gl-dropdown-item> - </template> - <gl-dropdown-text v-else>{{ __('No matches found') }}</gl-dropdown-text> - </template> - </gl-dropdown> + :items="namespaceItems" + :header-text="__('Namespaces')" + :no-results-text="__('No matches found')" + :searchable="true" + :searching="loading" + toggle-class="gl-flex-direction-column gl-align-items-stretch!" + :toggle-text="dropdownText" + @search="searchNamespaces" + @select="setNamespace" + /> </gl-button-group> </template> diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 1efbc226ca2..94fe67fdcf7 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -623,10 +623,12 @@ export default { <work-item-tree v-if="workItemType === $options.WORK_ITEM_TYPE_VALUE_OBJECTIVE" :work-item-type="workItemType" + :parent-work-item-type="workItem.workItemType.name" :work-item-id="workItem.id" :children="children" :can-update="canUpdate" :project-path="fullPath" + :confidential="workItem.confidential" @addWorkItemChild="addChild" @removeChild="removeChild" /> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue index faadb5fa6fa..b078711ec5d 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue @@ -399,6 +399,7 @@ export default { :parent-iteration="issuableIteration" :parent-milestone="issuableMilestone" :form-type="formType" + :parent-work-item-type="workItem.workItemType.name" @cancel="hideAddForm" @addWorkItemChild="addChild" /> diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue index 5cf0c4154bb..34f7e659600 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue @@ -1,5 +1,14 @@ <script> -import { GlAlert, GlFormGroup, GlForm, GlTokenSelector, GlButton, GlFormInput } from '@gitlab/ui'; +import { + GlAlert, + GlFormGroup, + GlForm, + GlTokenSelector, + GlButton, + GlFormInput, + GlFormCheckbox, + GlTooltip, +} from '@gitlab/ui'; import { debounce } from 'lodash'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; @@ -17,6 +26,8 @@ import { I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, I18N_WORK_ITEM_ADD_BUTTON_LABEL, I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL, + I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, + I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, sprintfWorkItem, } from '../../constants'; @@ -28,6 +39,8 @@ export default { GlButton, GlFormGroup, GlFormInput, + GlFormCheckbox, + GlTooltip, }, mixins: [glFeatureFlagMixin()], inject: ['projectPath', 'hasIterationsFeature'], @@ -61,6 +74,11 @@ export default { type: String, required: true, }, + parentWorkItemType: { + type: String, + required: false, + default: '', + }, childrenType: { type: String, required: false, @@ -108,6 +126,7 @@ export default { error: null, childToCreateTitle: null, workItemsToAdd: [], + confidential: this.parentConfidential, }; }, computed: { @@ -119,7 +138,7 @@ export default { hierarchyWidget: { parentId: this.issuableGid, }, - confidential: this.parentConfidential, + confidential: this.parentConfidential || this.confidential, }; if (this.parentMilestoneId) { @@ -162,6 +181,16 @@ export default { } return sprintfWorkItem(I18N_WORK_ITEM_ADD_BUTTON_LABEL, this.childrenTypeName); }, + confidentialityCheckboxLabel() { + return sprintfWorkItem(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, this.childrenTypeName); + }, + confidentialityCheckboxTooltip() { + return sprintfWorkItem( + I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, + this.childrenTypeName, + this.parentWorkItemType, + ); + }, addOrCreateMethod() { return this.isCreateForm ? this.createChild : this.addChild; }, @@ -192,6 +221,11 @@ export default { }, methods: { getIdFromGraphQLId, + getConfidentialityTooltipTarget() { + // We want tooltip to be anchored to `input` within checkbox component + // but `$el.querySelector('input')` doesn't work. 🤷♂️ + return this.$refs.confidentialityCheckbox?.$el; + }, unsetError() { this.error = null; }, @@ -299,8 +333,22 @@ export default { autofocus /> </gl-form-group> + <gl-form-checkbox + ref="confidentialityCheckbox" + v-model="confidential" + name="isConfidential" + class="gl-md-mt-5 gl-mb-5 gl-md-mb-3!" + :disabled="parentConfidential" + >{{ confidentialityCheckboxLabel }}</gl-form-checkbox + > + <gl-tooltip + v-if="parentConfidential" + :target="getConfidentialityTooltipTarget" + triggers="hover" + >{{ confidentialityCheckboxTooltip }}</gl-tooltip + > <gl-token-selector - v-else + v-if="!isCreateForm" v-model="workItemsToAdd" :dropdown-items="availableWorkItems" :loading="isLoading" diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue index f06de2ca048..532a3b4aa18 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue @@ -40,10 +40,20 @@ export default { type: String, required: true, }, + parentWorkItemType: { + type: String, + required: false, + default: '', + }, workItemId: { type: String, required: true, }, + confidential: { + type: Boolean, + required: false, + default: false, + }, children: { type: Array, required: false, @@ -221,8 +231,10 @@ export default { data-testid="add-tree-form" :issuable-gid="workItemId" :form-type="formType" + :parent-work-item-type="parentWorkItemType" :children-type="childType" :children-ids="childrenIds" + :parent-confidential="confidential" @addWorkItemChild="$emit('addWorkItemChild', $event)" @cancel="hideAddForm" /> @@ -233,6 +245,7 @@ export default { :can-update="canUpdate" :issuable-gid="workItemId" :child-item="child" + :confidential="child.confidential" :work-item-type="workItemType" :has-indirect-children="hasIndirectChildren" @mouseover="prefetchWorkItem(child)" diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 7e4fd1d547d..21af1449e50 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -73,12 +73,19 @@ export const I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL = s__('WorkItem|Add %{work export const I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER = s__( 'WorkItem|Search existing %{workItemType}s', ); +export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL = s__( + 'WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access', +); +export const I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP = s__( + 'WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}.', +); -export const sprintfWorkItem = (msg, workItemTypeArg) => { +export const sprintfWorkItem = (msg, workItemTypeArg, parentWorkItemType = '') => { const workItemType = workItemTypeArg || s__('WorkItem|Work item'); return capitalizeFirstCharacter( sprintf(msg, { workItemType: workItemType.toLocaleLowerCase(), + parentWorkItemType: parentWorkItemType.toLocaleLowerCase(), }), ); }; diff --git a/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql index 7fcf622cdb2..7d7bb9c7fc5 100644 --- a/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql +++ b/app/assets/javascripts/work_items/graphql/work_item_links.query.graphql @@ -3,6 +3,7 @@ query workItemLinksQuery($id: WorkItemID!) { id workItemType { id + name } title userPermissions { diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss index 36e6f7941f6..5eb76be4bbf 100644 --- a/app/assets/stylesheets/utilities.scss +++ b/app/assets/stylesheets/utilities.scss @@ -255,6 +255,12 @@ to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1709 } } +.gl-md-mb-3\! { + @include gl-media-breakpoint-up(md) { + margin-bottom: $gl-spacing-scale-3 !important; + } +} + .gl-gap-2 { gap: $gl-spacing-scale-2; diff --git a/app/controllers/groups/usage_quotas_controller.rb b/app/controllers/groups/usage_quotas_controller.rb index 29878f0001d..b660eb3af99 100644 --- a/app/controllers/groups/usage_quotas_controller.rb +++ b/app/controllers/groups/usage_quotas_controller.rb @@ -16,8 +16,7 @@ module Groups private def verify_usage_quotas_enabled! - render_404 unless Feature.enabled?(:usage_quotas_for_all_editions, group) - render_404 if group.has_parent? + render_404 unless group.usage_quotas_enabled? end # To be overriden in ee/app/controllers/ee/groups/usage_quotas_controller.rb diff --git a/app/models/group.rb b/app/models/group.rb index 2067eed9989..37dcbf95e63 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -915,6 +915,10 @@ class Group < Namespace feature_flag_enabled_for_self_or_ancestor?(:work_items_create_from_markdown) end + def usage_quotas_enabled? + ::Feature.enabled?(:usage_quotas_for_all_editions, self) && root? + end + # Check for enabled features, similar to `Project#feature_available?` # NOTE: We still want to keep this after removing `Namespace#feature_available?`. override :feature_available? |