Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-08-08 18:06:56 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-08 18:06:56 +0300
commitbfb24e1685fb574d3144865da29a21b38cb52883 (patch)
treed694d329da73d9a312a6f819edaebebc3b081491 /app/assets/javascripts/issues
parente44c3e4832e43c77e9c29fad6e49f8d6066d7f5c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/issues')
-rw-r--r--app/assets/javascripts/issues/index.js1
-rw-r--r--app/assets/javascripts/issues/show/components/app.vue73
-rw-r--r--app/assets/javascripts/issues/show/components/header_actions.vue4
-rw-r--r--app/assets/javascripts/issues/show/components/issue_header.vue126
-rw-r--r--app/assets/javascripts/issues/show/components/title.vue7
-rw-r--r--app/assets/javascripts/issues/show/index.js37
6 files changed, 239 insertions, 9 deletions
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index 4d2df9e3602..e266966c665 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -63,7 +63,6 @@ export function initShow({ notesParams } = {}) {
initRelatedIssues(TYPE_INCIDENT);
} else {
initIssueApp(issuableData, store);
- initHeaderActions(store);
}
new Issue(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue
index fcdf1f7741b..633f336b0c0 100644
--- a/app/assets/javascripts/issues/show/components/app.vue
+++ b/app/assets/javascripts/issues/show/components/app.vue
@@ -15,6 +15,7 @@ import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
import { containsSensitiveToken, confirmSensitiveAction, i18n } from '~/lib/utils/secret_detection';
+import { WORK_ITEM_TYPE_VALUE_ISSUE } from '~/work_items/constants';
import { ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH, POLLING_DELAY } from '../constants';
import eventHub from '../event_hub';
import getIssueStateQuery from '../queries/get_issue_state.query.graphql';
@@ -23,6 +24,8 @@ import Store from '../stores';
import DescriptionComponent from './description.vue';
import EditedComponent from './edited.vue';
import FormComponent from './form.vue';
+import HeaderActions from './header_actions.vue';
+import IssueHeader from './issue_header.vue';
import PinnedLinks from './pinned_links.vue';
import TitleComponent from './title.vue';
@@ -32,6 +35,8 @@ export default {
GlIcon,
GlBadge,
GlIntersectionObserver,
+ HeaderActions,
+ IssueHeader,
TitleComponent,
EditedComponent,
FormComponent,
@@ -42,6 +47,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
props: {
+ author: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
endpoint: {
required: true,
type: String,
@@ -54,6 +64,11 @@ export default {
required: true,
type: Boolean,
},
+ createdAt: {
+ type: String,
+ required: false,
+ default: '',
+ },
enableAutocomplete: {
type: Boolean,
required: false,
@@ -193,6 +208,36 @@ export default {
required: false,
default: null,
},
+ duplicatedToIssueUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ movedToIssueUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ promotedToEpicUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ isFirstContribution: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ serviceDeskReplyTo: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ workItemType: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
const store = new Store({
@@ -222,6 +267,9 @@ export default {
},
},
computed: {
+ isIssue() {
+ return this.workItemType === WORK_ITEM_TYPE_VALUE_ISSUE;
+ },
issuableTemplates() {
return this.store.formState.issuableTemplates;
},
@@ -509,7 +557,13 @@ export default {
:can-update="canUpdate"
:title-html="state.titleHtml"
:title-text="state.titleText"
- />
+ >
+ <template #actions>
+ <slot name="actions">
+ <header-actions v-if="isIssue" />
+ </slot>
+ </template>
+ </title-component>
<gl-intersection-observer
v-if="shouldShowStickyHeader"
@@ -567,6 +621,23 @@ export default {
</transition>
</gl-intersection-observer>
+ <slot name="header">
+ <issue-header
+ v-if="isIssue"
+ :author="author"
+ :confidential="isConfidential"
+ :created-at="createdAt"
+ :duplicated-to-issue-url="duplicatedToIssueUrl"
+ :is-first-contribution="isFirstContribution"
+ :is-hidden="isHidden"
+ :is-locked="isLocked"
+ :issuable-state="issuableStatus"
+ :moved-to-issue-url="movedToIssueUrl"
+ :promoted-to-epic-url="promotedToEpicUrl"
+ :service-desk-reply-to="serviceDeskReplyTo"
+ />
+ </slot>
+
<pinned-links
:zoom-meeting-url="zoomMeetingUrl"
:published-incident-url="publishedIncidentUrl"
diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue
index 321b12a0050..d05311cb1db 100644
--- a/app/assets/javascripts/issues/show/components/header_actions.vue
+++ b/app/assets/javascripts/issues/show/components/header_actions.vue
@@ -146,7 +146,7 @@ export default {
variables() {
return {
fullPath: this.fullPath,
- iid: this.iid,
+ iid: String(this.iid),
};
},
update(data) {
@@ -289,7 +289,7 @@ export default {
mutation: promoteToEpicMutation,
variables: {
input: {
- iid: this.iid,
+ iid: String(this.iid),
projectPath: this.projectPath,
},
},
diff --git a/app/assets/javascripts/issues/show/components/issue_header.vue b/app/assets/javascripts/issues/show/components/issue_header.vue
new file mode 100644
index 00000000000..771b438f0da
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/issue_header.vue
@@ -0,0 +1,126 @@
+<script>
+import { GlLink, GlSprintf } from '@gitlab/ui';
+import { STATUS_OPEN, STATUS_REOPENED, TYPE_ISSUE, WORKSPACE_PROJECT } from '~/issues/constants';
+import { __, s__ } from '~/locale';
+import IssuableHeader from '~/vue_shared/issuable/show/components/issuable_header.vue';
+
+export default {
+ TYPE_ISSUE,
+ WORKSPACE_PROJECT,
+ components: {
+ GlLink,
+ GlSprintf,
+ IssuableHeader,
+ },
+ props: {
+ author: {
+ type: Object,
+ required: true,
+ },
+ confidential: {
+ type: Boolean,
+ required: true,
+ },
+ createdAt: {
+ type: String,
+ required: true,
+ },
+ duplicatedToIssueUrl: {
+ type: String,
+ required: true,
+ },
+ isFirstContribution: {
+ type: Boolean,
+ required: true,
+ },
+ isHidden: {
+ type: Boolean,
+ required: true,
+ },
+ isLocked: {
+ type: Boolean,
+ required: true,
+ },
+ issuableState: {
+ type: String,
+ required: true,
+ },
+ movedToIssueUrl: {
+ type: String,
+ required: true,
+ },
+ promotedToEpicUrl: {
+ type: String,
+ required: true,
+ },
+ serviceDeskReplyTo: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ closedStatusLink() {
+ return this.duplicatedToIssueUrl || this.movedToIssueUrl || this.promotedToEpicUrl;
+ },
+ closedStatusText() {
+ if (this.duplicatedToIssueUrl) {
+ return s__('IssuableStatus|duplicated');
+ }
+ if (this.movedToIssueUrl) {
+ return s__('IssuableStatus|moved');
+ }
+ if (this.promotedToEpicUrl) {
+ return s__('IssuableStatus|promoted');
+ }
+ return '';
+ },
+ isOpen() {
+ return this.issuableState === STATUS_OPEN || this.issuableState === STATUS_REOPENED;
+ },
+ statusIcon() {
+ return this.isOpen ? 'issues' : 'issue-closed';
+ },
+ statusText() {
+ if (this.isOpen) {
+ return __('Open');
+ }
+ if (this.closedStatusLink) {
+ return s__('IssuableStatus|Closed (%{link})');
+ }
+ return s__('IssuableStatus|Closed');
+ },
+ },
+};
+</script>
+
+<template>
+ <issuable-header
+ class="gl-p-0 gl-mb-6 gl-mt-2 gl-sm-mt-0"
+ :author="author"
+ :blocked="isLocked"
+ :confidential="confidential"
+ :created-at="createdAt"
+ :is-first-contribution="isFirstContribution"
+ :is-hidden="isHidden"
+ :issuable-state="issuableState"
+ :issuable-type="$options.TYPE_ISSUE"
+ :service-desk-reply-to="serviceDeskReplyTo"
+ show-work-item-type-icon
+ :status-icon="statusIcon"
+ :workspace-type="$options.WORKSPACE_PROJECT"
+ >
+ <template #status-badge>
+ <gl-sprintf v-if="closedStatusLink" :message="statusText">
+ <template #link>
+ <gl-link
+ class="gl-reset-color! gl-reset-font-size gl-text-decoration-underline"
+ :href="closedStatusLink"
+ >{{ closedStatusText }}</gl-link
+ >
+ </template>
+ </gl-sprintf>
+ <template v-else>{{ statusText }}</template>
+ </template>
+ </issuable-header>
+</template>
diff --git a/app/assets/javascripts/issues/show/components/title.vue b/app/assets/javascripts/issues/show/components/title.vue
index 197a2594f4d..8c9e43b729b 100644
--- a/app/assets/javascripts/issues/show/components/title.vue
+++ b/app/assets/javascripts/issues/show/components/title.vue
@@ -53,16 +53,19 @@ export default {
</script>
<template>
- <div class="title-container">
+ <div
+ class="gl-display-flex gl-align-items-flex-start gl-flex-direction-column gl-sm-flex-direction-row gl-pt-3"
+ >
<h1
v-safe-html="titleHtml"
:class="{
'issue-realtime-pre-pulse': preAnimation,
'issue-realtime-trigger-pulse': pulseAnimation,
}"
- class="title gl-font-size-h-display"
+ class="title gl-font-size-h-display gl-m-0!"
data-testid="issue-title"
dir="auto"
></h1>
+ <slot name="actions"></slot>
</div>
</template>
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index bc4284457f6..41e6daea4c1 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -2,8 +2,8 @@ import Vue from 'vue';
import { mapGetters } from 'vuex';
import errorTrackingStore from '~/error_tracking/store';
import { apolloProvider } from '~/graphql_shared/issuable_client';
-import { TYPE_INCIDENT } from '~/issues/constants';
-import { parseBoolean } from '~/lib/utils/common_utils';
+import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
+import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
import IssueApp from './components/app.vue';
import HeaderActions from './components/header_actions.vue';
@@ -97,12 +97,17 @@ export function initIssueApp(issueData, store) {
}
const { fullPath, registerPath, signInPath } = el.dataset;
+ const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
scrollToTargetOnResize();
- bootstrapApollo({ ...issueState, issueType: el.dataset.issueType });
+ bootstrapApollo({ ...issueState, issueType: TYPE_ISSUE });
const {
+ authorId,
+ authorName,
+ authorUsername,
+ authorWebUrl,
canCreateIncident,
hasIssueWeightsFeature,
hasIterationsFeature,
@@ -121,6 +126,26 @@ export function initIssueApp(issueData, store) {
signInPath,
hasIssueWeightsFeature,
hasIterationsFeature,
+ // for HeaderActions component
+ canCreateIssue: parseBoolean(headerActionsData.canCreateIssue),
+ canDestroyIssue: parseBoolean(headerActionsData.canDestroyIssue),
+ canPromoteToEpic: parseBoolean(headerActionsData.canPromoteToEpic),
+ canReopenIssue: parseBoolean(headerActionsData.canReopenIssue),
+ canReportSpam: parseBoolean(headerActionsData.canReportSpam),
+ canUpdateIssue: parseBoolean(headerActionsData.canUpdateIssue),
+ iid: headerActionsData.iid,
+ issuableId: headerActionsData.issuableId,
+ isIssueAuthor: parseBoolean(headerActionsData.isIssueAuthor),
+ issuePath: headerActionsData.issuePath,
+ issueType: headerActionsData.issueType,
+ newIssuePath: headerActionsData.newIssuePath,
+ projectPath: headerActionsData.projectPath,
+ projectId: headerActionsData.projectId,
+ reportAbusePath: headerActionsData.reportAbusePath,
+ reportedUserId: headerActionsData.reportedUserId,
+ reportedFromUrl: headerActionsData.reportedFromUrl,
+ submitAsSpamPath: headerActionsData.submitAsSpamPath,
+ issuableEmailAddress: headerActionsData.issuableEmailAddress,
},
computed: {
...mapGetters(['getNoteableData']),
@@ -129,6 +154,12 @@ export function initIssueApp(issueData, store) {
return createElement(IssueApp, {
props: {
...issueProps,
+ author: {
+ id: authorId,
+ name: authorName,
+ username: authorUsername,
+ webUrl: authorWebUrl,
+ },
isConfidential: this.getNoteableData?.confidential,
isLocked: this.getNoteableData?.discussion_locked,
issuableStatus: this.getNoteableData?.state,