diff options
Diffstat (limited to 'app/assets/javascripts/boards')
8 files changed, 22 insertions, 259 deletions
diff --git a/app/assets/javascripts/boards/components/board_blocked_icon.vue b/app/assets/javascripts/boards/components/board_blocked_icon.vue deleted file mode 100644 index 3f8a596abd8..00000000000 --- a/app/assets/javascripts/boards/components/board_blocked_icon.vue +++ /dev/null @@ -1,207 +0,0 @@ -<script> -import { GlIcon, GlLink, GlPopover, GlLoadingIcon } from '@gitlab/ui'; -import { blockingIssuablesQueries, issuableTypes } from '~/boards/constants'; -import { TYPE_ISSUE, TYPE_EPIC } from '~/graphql_shared/constants'; -import { convertToGraphQLId } from '~/graphql_shared/utils'; -import { truncate } from '~/lib/utils/text_utility'; -import { __, n__, s__, sprintf } from '~/locale'; - -export default { - i18n: { - issuableType: { - [issuableTypes.issue]: __('issue'), - [issuableTypes.epic]: __('epic'), - }, - }, - graphQLIdType: { - [issuableTypes.issue]: TYPE_ISSUE, - [issuableTypes.epic]: TYPE_EPIC, - }, - referenceFormatter: { - [issuableTypes.issue]: (r) => r.split('/')[1], - }, - defaultDisplayLimit: 3, - textTruncateWidth: 80, - components: { - GlIcon, - GlPopover, - GlLink, - GlLoadingIcon, - }, - blockingIssuablesQueries, - props: { - item: { - type: Object, - required: true, - }, - uniqueId: { - type: String, - required: true, - }, - issuableType: { - type: String, - required: true, - validator(value) { - return [issuableTypes.issue, issuableTypes.epic].includes(value); - }, - }, - }, - apollo: { - blockingIssuables: { - skip() { - return this.skip; - }, - query() { - return blockingIssuablesQueries[this.issuableType].query; - }, - variables() { - if (this.isEpic) { - return { - fullPath: this.item.group.fullPath, - iid: Number(this.item.iid), - }; - } - return { - id: convertToGraphQLId(this.$options.graphQLIdType[this.issuableType], this.item.id), - }; - }, - update(data) { - this.skip = true; - const issuable = this.isEpic ? data?.group?.issuable : data?.issuable; - - return issuable?.blockingIssuables?.nodes || []; - }, - error(error) { - const message = sprintf(s__('Boards|Failed to fetch blocking %{issuableType}s'), { - issuableType: this.issuableTypeText, - }); - this.$emit('blocking-issuables-error', { error, message }); - }, - }, - }, - data() { - return { - skip: true, - blockingIssuables: [], - }; - }, - computed: { - isEpic() { - return this.issuableType === issuableTypes.epic; - }, - displayedIssuables() { - const { defaultDisplayLimit, referenceFormatter } = this.$options; - return this.blockingIssuables.slice(0, defaultDisplayLimit).map((i) => { - return { - ...i, - title: truncate(i.title, this.$options.textTruncateWidth), - reference: this.isEpic ? i.reference : referenceFormatter[this.issuableType](i.reference), - }; - }); - }, - loading() { - return this.$apollo.queries.blockingIssuables.loading; - }, - issuableTypeText() { - return this.$options.i18n.issuableType[this.issuableType]; - }, - blockedLabel() { - return sprintf( - n__( - 'Boards|Blocked by %{blockedByCount} %{issuableType}', - 'Boards|Blocked by %{blockedByCount} %{issuableType}s', - this.item.blockedByCount, - ), - { - blockedByCount: this.item.blockedByCount, - issuableType: this.issuableTypeText, - }, - ); - }, - blockIcon() { - return this.issuableType === issuableTypes.issue ? 'issue-block' : 'entity-blocked'; - }, - glIconId() { - return `blocked-icon-${this.uniqueId}`; - }, - hasMoreIssuables() { - return this.item.blockedByCount > this.$options.defaultDisplayLimit; - }, - displayedIssuablesCount() { - return this.hasMoreIssuables - ? this.item.blockedByCount - this.$options.defaultDisplayLimit - : this.item.blockedByCount; - }, - moreIssuablesText() { - return sprintf( - n__( - 'Boards|+ %{displayedIssuablesCount} more %{issuableType}', - 'Boards|+ %{displayedIssuablesCount} more %{issuableType}s', - this.displayedIssuablesCount, - ), - { - displayedIssuablesCount: this.displayedIssuablesCount, - issuableType: this.issuableTypeText, - }, - ); - }, - viewAllIssuablesText() { - return sprintf(s__('Boards|View all blocking %{issuableType}s'), { - issuableType: this.issuableTypeText, - }); - }, - loadingMessage() { - return sprintf(s__('Boards|Retrieving blocking %{issuableType}s'), { - issuableType: this.issuableTypeText, - }); - }, - }, - methods: { - handleMouseEnter() { - this.skip = false; - }, - }, -}; -</script> -<template> - <div class="gl-display-inline"> - <gl-icon - :id="glIconId" - ref="icon" - :name="blockIcon" - class="issue-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500" - data-testid="issue-blocked-icon" - @mouseenter="handleMouseEnter" - /> - <gl-popover :target="glIconId" placement="top"> - <template #title - ><span data-testid="popover-title">{{ blockedLabel }}</span></template - > - <template v-if="loading"> - <gl-loading-icon size="sm" /> - <p class="gl-mt-4 gl-mb-0 gl-font-small">{{ loadingMessage }}</p> - </template> - <template v-else> - <ul class="gl-list-style-none gl-p-0"> - <li v-for="issuable in displayedIssuables" :key="issuable.id"> - <gl-link :href="issuable.webUrl" class="gl-text-blue-500! gl-font-sm">{{ - issuable.reference - }}</gl-link> - <p class="gl-mb-3 gl-display-block!" data-testid="issuable-title"> - {{ issuable.title }} - </p> - </li> - </ul> - <div v-if="hasMoreIssuables" class="gl-mt-4"> - <p class="gl-mb-3" data-testid="hidden-blocking-count">{{ moreIssuablesText }}</p> - <gl-link - data-testid="view-all-issues" - :href="`${item.webUrl}#related-issues`" - class="gl-text-blue-500! gl-font-sm" - >{{ viewAllIssuablesText }}</gl-link - > - </div> - </template> - </gl-popover> - </div> -</template> diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index 92a623d65d4..3a2b11a649d 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -17,9 +17,9 @@ import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/toolt import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue'; import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue'; +import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue'; import { ListType } from '../constants'; import eventHub from '../eventhub'; -import BoardBlockedIcon from './board_blocked_icon.vue'; import IssueDueDate from './issue_due_date.vue'; import IssueTimeEstimate from './issue_time_estimate.vue'; @@ -34,7 +34,7 @@ export default { IssueDueDate, IssueTimeEstimate, IssueCardWeight: () => import('ee_component/boards/components/issue_card_weight.vue'), - BoardBlockedIcon, + IssuableBlockedIcon, GlSprintf, BoardCardMoveToPosition, WorkItemTypeIcon, @@ -218,7 +218,7 @@ export default { <div> <div class="gl-display-flex" dir="auto"> <h4 class="board-card-title gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word"> - <board-blocked-icon + <issuable-blocked-icon v-if="item.blocked" :item="item" :unique-id="`${item.id}${list.id}`" @@ -250,7 +250,8 @@ export default { >{{ item.title }}</a > </h4> - <board-card-move-to-position :item="item" :list="list" :index="index" /> + <!-- TODO: remove the condition when https://gitlab.com/gitlab-org/gitlab/-/issues/377862 is resolved --> + <board-card-move-to-position v-if="!isEpicBoard" :item="item" :list="list" :index="index" /> </div> <div v-if="showLabelFooter" class="board-card-labels gl-mt-2 gl-display-flex gl-flex-wrap"> <template v-for="label in orderedLabels"> @@ -397,7 +398,6 @@ export default { :img-size="avatarSize" class="js-no-trigger user-avatar-link" tooltip-placement="bottom" - :enforce-gl-avatar="true" > <span class="js-assignee-tooltip"> <span class="gl-font-weight-bold gl-display-block">{{ __('Assignee') }}</span> diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index fa0c798ca9d..11a5d89cc8c 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -8,6 +8,7 @@ import { __ } from '~/locale'; import { FILTERED_SEARCH_TERM, FILTER_ANY, + TOKEN_TYPE_HEALTH, } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import { AssigneeFilterType } from '~/boards/constants'; @@ -55,6 +56,7 @@ export default { myReactionEmoji, releaseTag, confidential, + healthStatus, } = this.filterParams; const filteredSearchValue = []; @@ -154,6 +156,13 @@ export default { }); } + if (healthStatus) { + filteredSearchValue.push({ + type: TOKEN_TYPE_HEALTH, + value: { data: healthStatus, operator: '=' }, + }); + } + if (this.filterParams['not[authorUsername]']) { filteredSearchValue.push({ type: 'author', @@ -248,6 +257,7 @@ export default { iterationCadenceId, releaseTag, confidential, + healthStatus, } = this.filterParams; let iteration = iterationId; let cadence = iterationCadenceId; @@ -292,6 +302,7 @@ export default { my_reaction_emoji: myReactionEmoji, release_tag: releaseTag, confidential, + [TOKEN_TYPE_HEALTH]: healthStatus, }, (value) => { if (value || value === false) { @@ -390,6 +401,9 @@ export default { case 'filtered-search-term': if (filter.value.data) plainText.push(filter.value.data); break; + case TOKEN_TYPE_HEALTH: + filterParams.healthStatus = filter.value.data; + break; default: break; } diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index 9f359a25234..eb889344c1e 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -4,7 +4,6 @@ import { mapGetters, mapActions, mapState } from 'vuex'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { visitUrl, updateHistory, getParameterByName } from '~/lib/utils/url_utility'; import { __, s__ } from '~/locale'; -import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { formType } from '../constants'; import createBoardMutation from '../graphql/board_create.mutation.graphql'; @@ -45,7 +44,6 @@ export default { BoardConfigurationOptions, GlAlert, }, - mixins: [glFeatureFlagMixin()], inject: { fullPath: { default: '', @@ -233,9 +231,8 @@ export default { } }, setIteration(iteration) { - if (this.glFeatures.iterationCadences) { - this.board.iterationCadenceId = iteration.iterationCadenceId; - } + this.board.iterationCadenceId = iteration.iterationCadenceId; + this.$set(this.board, 'iteration', { id: iteration.id, }); diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js index ed22a375271..91b7f5004ad 100644 --- a/app/assets/javascripts/boards/constants.js +++ b/app/assets/javascripts/boards/constants.js @@ -2,8 +2,6 @@ import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql import { __ } from '~/locale'; import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscription.mutation.graphql'; import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql'; -import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql'; -import boardBlockingEpicsQuery from './graphql/board_blocking_epics.query.graphql'; import destroyBoardListMutation from './graphql/board_list_destroy.mutation.graphql'; import updateBoardListMutation from './graphql/board_list_update.mutation.graphql'; @@ -67,15 +65,6 @@ export const listsQuery = { }, }; -export const blockingIssuablesQueries = { - [issuableTypes.issue]: { - query: boardBlockingIssuesQuery, - }, - [issuableTypes.epic]: { - query: boardBlockingEpicsQuery, - }, -}; - export const updateListQueries = { [issuableTypes.issue]: { mutation: updateBoardListMutation, diff --git a/app/assets/javascripts/boards/graphql/board_blocking_epics.query.graphql b/app/assets/javascripts/boards/graphql/board_blocking_epics.query.graphql deleted file mode 100644 index 071a6d7410f..00000000000 --- a/app/assets/javascripts/boards/graphql/board_blocking_epics.query.graphql +++ /dev/null @@ -1,17 +0,0 @@ -query BoardBlockingEpics($fullPath: ID!, $iid: ID) { - group(fullPath: $fullPath) { - id - issuable: epic(iid: $iid) { - id - blockingIssuables: blockedByEpics { - nodes { - id - iid - title - reference(full: true) - webUrl - } - } - } - } -} diff --git a/app/assets/javascripts/boards/graphql/board_blocking_issues.query.graphql b/app/assets/javascripts/boards/graphql/board_blocking_issues.query.graphql deleted file mode 100644 index 01fab571733..00000000000 --- a/app/assets/javascripts/boards/graphql/board_blocking_issues.query.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query BoardBlockingIssues($id: IssueID!) { - issuable: issue(id: $id) { - id - blockingIssuables: blockedByIssues { - nodes { - id - iid - title - reference(full: true) - webUrl - } - } - } -} diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index 854717ed4c4..a7003edba47 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -86,6 +86,7 @@ function mountBoardApp(el) { milestoneListsAvailable: parseBoolean(el.dataset.milestoneListsAvailable), assigneeListsAvailable: parseBoolean(el.dataset.assigneeListsAvailable), iterationListsAvailable: parseBoolean(el.dataset.iterationListsAvailable), + healthStatusFeatureAvailable: parseBoolean(el.dataset.healthStatusFeatureAvailable), allowScopedLabels: parseBoolean(el.dataset.scopedLabels), swimlanesFeatureAvailable: gon.licensed_features?.swimlanes, multipleIssueBoardsAvailable: parseBoolean(el.dataset.multipleBoardsAvailable), |