diff options
Diffstat (limited to 'app/assets/javascripts/groups')
4 files changed, 91 insertions, 25 deletions
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 2241d57f96f..7345afb8545 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -4,13 +4,24 @@ import { GlLoadingIcon, GlBadge, GlIcon, + GlLabel, + GlButton, + GlPopover, + GlLink, GlTooltipDirective, GlSafeHtmlDirective, } from '@gitlab/ui'; import { visitUrl } from '~/lib/utils/url_utility'; import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue'; import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants'; -import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '../constants'; +import { helpPagePath } from '~/helpers/help_page_helper'; +import { __ } from '~/locale'; +import { + VISIBILITY_TYPE_ICON, + GROUP_VISIBILITY_TYPE, + ITEM_TYPE, + VISIBILITY_PRIVATE, +} from '../constants'; import eventHub from '../event_hub'; import itemActions from './item_actions.vue'; @@ -28,16 +39,17 @@ export default { GlBadge, GlLoadingIcon, GlIcon, + GlLabel, + GlButton, + GlPopover, + GlLink, UserAccessRoleBadge, - ComplianceFrameworkLabel: () => - import( - 'ee_component/vue_shared/components/compliance_framework_label/compliance_framework_label.vue' - ), itemCaret, itemTypeIcon, itemActions, itemStats, }, + inject: ['currentGroupVisibility'], props: { parentGroup: { type: Object, @@ -58,6 +70,9 @@ export default { groupDomId() { return `group-${this.group.id}`; }, + itemTestId() { + return `group-overview-item-${this.group.id}`; + }, rowClass() { return { 'is-open': this.group.isOpen, @@ -76,10 +91,10 @@ export default { return Boolean(this.group.complianceFramework?.name); }, isGroup() { - return this.group.type === 'group'; + return this.group.type === ITEM_TYPE.GROUP; }, isGroupPendingRemoval() { - return this.group.type === 'group' && this.group.pendingRemoval; + return this.group.type === ITEM_TYPE.GROUP && this.group.pendingRemoval; }, visibilityIcon() { return VISIBILITY_TYPE_ICON[this.group.visibility]; @@ -96,6 +111,13 @@ export default { showActionsMenu() { return this.isGroup && (this.group.canEdit || this.group.canRemove || this.group.canLeave); }, + shouldShowVisibilityWarning() { + return ( + this.action === 'shared' && + this.currentGroupVisibility === VISIBILITY_PRIVATE && + this.group.visibility !== VISIBILITY_PRIVATE + ); + }, }, methods: { onClickRowGroup(e) { @@ -112,6 +134,17 @@ export default { } }, }, + i18n: { + popoverTitle: __('Less restrictive visibility'), + popoverBody: __('Project visibility level is less restrictive than the group settings.'), + learnMore: __('Learn more'), + }, + shareProjectsWithGroupsHelpPagePath: helpPagePath( + 'user/project/members/share_project_with_groups', + { + anchor: 'share-a-public-project-with-private-group', + }, + ), safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] }, AVATAR_SHAPE_OPTION_RECT, }; @@ -120,6 +153,7 @@ export default { <template> <li :id="groupDomId" + :data-testid="itemTestId" :class="rowClass" class="group-row" :itemprop="microdata.itemprop" @@ -165,7 +199,7 @@ export default { data-testid="group-name" :href="group.relativePath" :title="group.fullName" - class="no-expand gl-mr-3 gl-mt-3 gl-text-gray-900!" + class="no-expand gl-mr-3 gl-text-gray-900!" :itemprop="microdata.nameItemprop" > {{ @@ -176,20 +210,44 @@ export default { </a> <gl-icon v-gl-tooltip.hover.bottom - class="gl-display-inline-flex gl-align-items-center gl-mr-3 gl-mt-3 gl-text-gray-500" + class="gl-display-inline-flex gl-align-items-center gl-mr-3 gl-text-gray-500" :name="visibilityIcon" :title="visibilityTooltip" data-testid="group-visibility-icon" /> - <user-access-role-badge v-if="group.permission" class="gl-mt-3"> + <template v-if="shouldShowVisibilityWarning"> + <gl-button + ref="visibilityWarningButton" + class="gl-p-1! gl-bg-transparent! gl-mr-3" + category="tertiary" + icon="warning" + :aria-label="$options.i18n.popoverTitle" + @click.stop + /> + <gl-popover + :target="() => $refs.visibilityWarningButton.$el" + :title="$options.i18n.popoverTitle" + triggers="hover focus" + > + {{ $options.i18n.popoverBody }} + <div class="gl-mt-3"> + <gl-link + class="gl-font-sm" + :href="$options.shareProjectsWithGroupsHelpPagePath" + >{{ $options.i18n.learnMore }}</gl-link + > + </div> + </gl-popover> + </template> + <user-access-role-badge v-if="group.permission" class="gl-mr-3"> {{ group.permission }} </user-access-role-badge> - <compliance-framework-label + <gl-label v-if="hasComplianceFramework" - class="gl-mt-3" - :name="complianceFramework.name" - :color="complianceFramework.color" + :title="complianceFramework.name" + :background-color="complianceFramework.color" :description="complianceFramework.description" + size="sm" /> </div> <div v-if="group.description" class="description"> diff --git a/app/assets/javascripts/groups/components/group_name_and_path.vue b/app/assets/javascripts/groups/components/group_name_and_path.vue index f9bd8701199..983535d3e9c 100644 --- a/app/assets/javascripts/groups/components/group_name_and_path.vue +++ b/app/assets/javascripts/groups/components/group_name_and_path.vue @@ -133,6 +133,8 @@ export default { signal: this.activeApiRequestAbortController.signal, }); + this.apiLoading = false; + if (exists) { if (suggests.length) { return Promise.resolve({ exists, suggests }); @@ -148,14 +150,14 @@ export default { return Promise.resolve({ exists, suggests }); } catch (error) { if (!axios.isCancel(error)) { + this.apiLoading = false; + createAlert({ message: this.$options.i18n.apiErrorMessage, }); } return Promise.reject(); - } finally { - this.apiLoading = false; } }, handlePathInput(value) { diff --git a/app/assets/javascripts/groups/constants.js b/app/assets/javascripts/groups/constants.js index cacba2dfd23..29981d09155 100644 --- a/app/assets/javascripts/groups/constants.js +++ b/app/assets/javascripts/groups/constants.js @@ -28,28 +28,32 @@ export const ITEM_TYPE = { GROUP: 'group', }; +export const VISIBILITY_PUBLIC = 'public'; +export const VISIBILITY_INTERNAL = 'internal'; +export const VISIBILITY_PRIVATE = 'private'; + export const GROUP_VISIBILITY_TYPE = { - public: __( + [VISIBILITY_PUBLIC]: __( 'Public - The group and any public projects can be viewed without any authentication.', ), - internal: __( + [VISIBILITY_INTERNAL]: __( 'Internal - The group and any internal projects can be viewed by any logged in user except external users.', ), - private: __('Private - The group and its projects can only be viewed by members.'), + [VISIBILITY_PRIVATE]: __('Private - The group and its projects can only be viewed by members.'), }; export const PROJECT_VISIBILITY_TYPE = { - public: __('Public - The project can be accessed without any authentication.'), - internal: __( + [VISIBILITY_PUBLIC]: __('Public - The project can be accessed without any authentication.'), + [VISIBILITY_INTERNAL]: __( 'Internal - The project can be accessed by any logged in user except external users.', ), - private: __( + [VISIBILITY_PRIVATE]: __( 'Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.', ), }; export const VISIBILITY_TYPE_ICON = { - public: 'earth', - internal: 'shield', - private: 'lock', + [VISIBILITY_PUBLIC]: 'earth', + [VISIBILITY_INTERNAL]: 'shield', + [VISIBILITY_PRIVATE]: 'lock', }; diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js index dfcee80aec7..a502fcd31ad 100644 --- a/app/assets/javascripts/groups/index.js +++ b/app/assets/javascripts/groups/index.js @@ -55,6 +55,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => { renderEmptyState, canCreateSubgroups, canCreateProjects, + currentGroupVisibility, }, } = this.$options.el; @@ -67,6 +68,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => { renderEmptyState: parseBoolean(renderEmptyState), canCreateSubgroups: parseBoolean(canCreateSubgroups), canCreateProjects: parseBoolean(canCreateProjects), + currentGroupVisibility, }; }, data() { |