diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-22 15:09:21 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-22 15:09:21 +0300 |
commit | 4fc46d75644b28789e83c95ec4d1309498bb4ba3 (patch) | |
tree | c9609e71d701f19835ccad3f5f1c4b24490d4049 /app/assets/javascripts/vue_shared | |
parent | 48641ca0e8b4517fbc73704b132c0157943deec6 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared')
6 files changed, 132 insertions, 33 deletions
diff --git a/app/assets/javascripts/vue_shared/components/list_actions/constants.js b/app/assets/javascripts/vue_shared/components/list_actions/constants.js new file mode 100644 index 00000000000..b1506ae1e93 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/list_actions/constants.js @@ -0,0 +1,16 @@ +import { __ } from '~/locale'; + +export const ACTION_EDIT = 'edit'; +export const ACTION_DELETE = 'delete'; + +export const BASE_ACTIONS = { + [ACTION_EDIT]: { + text: __('Edit'), + }, + [ACTION_DELETE]: { + text: __('Delete'), + extraAttrs: { + class: 'gl-text-red-500!', + }, + }, +}; diff --git a/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js new file mode 100644 index 00000000000..d34729c2373 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js @@ -0,0 +1,44 @@ +import { makeContainer } from 'storybook_addons/make_container'; +import ListActions from './list_actions.vue'; +import { ACTION_DELETE, ACTION_EDIT } from './constants'; + +export default { + component: ListActions, + title: 'vue_shared/list_actions', + decorators: [makeContainer({ height: '115px' })], + parameters: { + docs: { + description: { + component: ` +This component renders actions used by lists of resources such as groups and projects. +Currently it is used by \`ProjectsListItem\`. There are base actions defined in \`~/vue_shared/components/list_actions\` +that help reduce the amount of boilerplate needed for common actions such as edit and delete. This component accepts an +\`actions\` prop that can extend the base actions and/or add custom actions. These actions should follow the format of +a [disclosure dropdown item](https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/base-new-dropdowns-disclosure--docs#setting-disclosure-dropdown-items). +The \`availableActions\` prop defines what actions to render and in what order. This prop will generally be set by checking +permissions of the current user. +`, + }, + }, + }, +}; + +const Template = (args, { argTypes }) => ({ + components: { ListActions }, + props: Object.keys(argTypes), + template: '<list-actions v-bind="$props" />', +}); + +export const Default = Template.bind({}); +Default.args = { + actions: { + [ACTION_EDIT]: { + href: '/?path=/story/vue-shared-list-actions--default', + }, + [ACTION_DELETE]: { + // eslint-disable-next-line no-console + action: () => console.log('Deleted'), + }, + }, + availableActions: [ACTION_EDIT, ACTION_DELETE], +}; diff --git a/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue new file mode 100644 index 00000000000..7b78cc1da8f --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue @@ -0,0 +1,52 @@ +<script> +import { GlDisclosureDropdown } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { BASE_ACTIONS } from './constants'; + +export default { + name: 'ListActions', + i18n: { + actions: __('Actions'), + }, + components: { + GlDisclosureDropdown, + }, + props: { + // Can extend `BASE_ACTIONS` and/or add new actions. + // Expected format: https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/base-new-dropdowns-disclosure--docs#setting-disclosure-dropdown-items + actions: { + type: Object, + required: true, + }, + availableActions: { + type: Array, + required: true, + }, + }, + computed: { + items() { + return this.availableActions.reduce((accumulator, action) => { + return [ + ...accumulator, + { + ...BASE_ACTIONS[action], + ...this.actions[action], + }, + ]; + }, []); + }, + }, +}; +</script> + +<template> + <gl-disclosure-dropdown + :items="items" + icon="ellipsis_v" + no-caret + :toggle-text="$options.i18n.actions" + text-sr-only + placement="right" + category="tertiary" + /> +</template> diff --git a/app/assets/javascripts/vue_shared/components/projects_list/constants.js b/app/assets/javascripts/vue_shared/components/projects_list/constants.js deleted file mode 100644 index aa0b1418a06..00000000000 --- a/app/assets/javascripts/vue_shared/components/projects_list/constants.js +++ /dev/null @@ -1,2 +0,0 @@ -export const ACTION_EDIT = 'edit'; -export const ACTION_DELETE = 'delete'; diff --git a/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue b/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue index 9fc4571b0dc..ce75e305473 100644 --- a/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue +++ b/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue @@ -7,7 +7,6 @@ import { GlTooltipDirective, GlPopover, GlSprintf, - GlDisclosureDropdown, } from '@gitlab/ui'; import uniqueId from 'lodash/uniqueId'; @@ -20,8 +19,9 @@ import { numberToMetricPrefix } from '~/lib/utils/number_utils'; import { truncate } from '~/lib/utils/text_utility'; import SafeHtml from '~/vue_shared/directives/safe_html'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import ListActions from '~/vue_shared/components/list_actions/list_actions.vue'; +import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants'; import DeleteModal from '~/projects/components/shared/delete_modal.vue'; -import { ACTION_EDIT, ACTION_DELETE } from './constants'; const MAX_TOPICS_TO_SHOW = 3; const MAX_TOPIC_TITLE_LENGTH = 15; @@ -51,8 +51,8 @@ export default { GlPopover, GlSprintf, TimeAgoTooltip, - GlDisclosureDropdown, DeleteModal, + ListActions, }, directives: { GlTooltip: GlTooltipDirective, @@ -163,30 +163,21 @@ export default { return numberToMetricPrefix(this.project.openIssuesCount); }, - actionsDropdownItems() { - return [ - { - id: ACTION_EDIT, - text: __('Edit'), + actions() { + return { + [ACTION_EDIT]: { href: this.project.editPath, }, - { - id: ACTION_DELETE, - text: __('Delete'), - extraAttrs: { - class: 'gl-text-red-500!', - }, - action: () => { - this.isDeleteModalVisible = true; - }, + [ACTION_DELETE]: { + action: this.onActionDelete, }, - ].filter(({ id }) => this.project.actions?.includes(id)); + }; }, hasActions() { - return this.actionsDropdownItems.length; + return this.project.availableActions?.length; }, - hasDeleteAction() { - return this.actionsDropdownItems.find((action) => action.id === ACTION_DELETE); + hasActionDelete() { + return this.project.availableActions?.includes(ACTION_DELETE); }, }, methods: { @@ -204,6 +195,9 @@ export default { return null; }, + onActionDelete() { + this.isDeleteModalVisible = true; + }, }, }; </script> @@ -336,20 +330,15 @@ export default { </div> </div> </div> - <gl-disclosure-dropdown + <list-actions v-if="hasActions" class="gl-ml-3 gl-md-align-self-center" - :items="actionsDropdownItems" - icon="ellipsis_v" - no-caret - :toggle-text="$options.i18n.actions" - text-sr-only - placement="right" - category="tertiary" + :actions="actions" + :available-actions="project.availableActions" /> <delete-modal - v-if="hasDeleteAction" + v-if="hasActionDelete" v-model="isDeleteModalVisible" :confirm-phrase="project.name" :is-fork="project.isForked" diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue index 7858e1d4e0e..fadd56fc697 100644 --- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue +++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue @@ -163,7 +163,7 @@ export default { <template> <div class="detail-page-header gl-flex-direction-column gl-sm-flex-direction-row"> <div class="detail-page-header-body gl-flex-wrap gl-gap-2"> - <gl-badge :variant="badgeVariant"> + <gl-badge :variant="badgeVariant" data-testid="issue-state-badge"> <gl-icon v-if="statusIcon" :name="statusIcon" :class="statusIconClass" /> <span class="gl-display-none gl-sm-display-block" :class="{ 'gl-ml-2': statusIcon }"> <slot name="status-badge">{{ badgeText }}</slot> |