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>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /app/assets/javascripts/issuable_show/components
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'app/assets/javascripts/issuable_show/components')
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_body.vue70
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_description.vue23
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_discussion.vue15
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_header.vue32
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_show_root.vue36
5 files changed, 169 insertions, 7 deletions
diff --git a/app/assets/javascripts/issuable_show/components/issuable_body.vue b/app/assets/javascripts/issuable_show/components/issuable_body.vue
index 02cf7a67727..fe102e942c9 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_body.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_body.vue
@@ -1,6 +1,8 @@
<script>
import { GlLink } from '@gitlab/ui';
+import TaskList from '~/task_list';
+
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import IssuableDescription from './issuable_description.vue';
@@ -40,6 +42,11 @@ export default {
type: Boolean,
required: true,
},
+ enableTaskList: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
editFormVisible: {
type: Boolean,
required: true,
@@ -56,6 +63,16 @@ export default {
type: String,
required: true,
},
+ taskListUpdatePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ taskListLockVersion: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
computed: {
isUpdated() {
@@ -65,7 +82,50 @@ export default {
return this.issuable.updatedBy;
},
},
+ watch: {
+ /**
+ * When user switches between view and edit modes,
+ * taskList instance becomes invalid so whenever
+ * view mode is rendered, we need to re-initialize
+ * taskList to ensure the behaviour functional.
+ */
+ editFormVisible(value) {
+ if (!value) {
+ this.$nextTick(() => {
+ this.initTaskList();
+ });
+ }
+ },
+ },
+ mounted() {
+ if (this.enableEdit && this.enableTaskList) {
+ this.initTaskList();
+ }
+ },
methods: {
+ initTaskList() {
+ this.taskList = new TaskList({
+ /**
+ * We have hard-coded dataType to `issue`
+ * as currently only `issue` types can handle
+ * task-lists, however, we can still use
+ * task lists in Issue, Test Cases and Incidents
+ * as all of those are derived from `issue`.
+ */
+ dataType: 'issue',
+ fieldName: 'description',
+ lockVersion: this.taskListLockVersion,
+ selector: '.js-detail-page-description',
+ onSuccess: this.handleTaskListUpdateSuccess.bind(this),
+ onError: this.handleTaskListUpdateFailure.bind(this),
+ });
+ },
+ handleTaskListUpdateSuccess(updatedIssuable) {
+ this.$emit('task-list-update-success', updatedIssuable);
+ },
+ handleTaskListUpdateFailure() {
+ this.$emit('task-list-update-failure');
+ },
handleKeydownTitle(e, issuableMeta) {
this.$emit('keydown-title', e, issuableMeta);
},
@@ -78,7 +138,7 @@ export default {
<template>
<div class="issue-details issuable-details">
- <div class="detail-page-description content-block">
+ <div class="detail-page-description js-detail-page-description content-block">
<issuable-edit-form
v-if="editFormVisible"
:issuable="issuable"
@@ -106,7 +166,13 @@ export default {
<slot name="status-badge"></slot>
</template>
</issuable-title>
- <issuable-description v-if="issuable.descriptionHtml" :issuable="issuable" />
+ <issuable-description
+ v-if="issuable.descriptionHtml"
+ :issuable="issuable"
+ :enable-task-list="enableTaskList"
+ :can-edit="enableEdit"
+ :task-list-update-path="taskListUpdatePath"
+ />
<small v-if="isUpdated" class="edited-text gl-font-sm!">
{{ __('Edited') }}
<time-ago-tooltip :time="issuable.updatedAt" tooltip-placement="bottom" />
diff --git a/app/assets/javascripts/issuable_show/components/issuable_description.vue b/app/assets/javascripts/issuable_show/components/issuable_description.vue
index aa7e530972f..f57b5b2deb4 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_description.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_description.vue
@@ -12,6 +12,18 @@ export default {
type: Object,
required: true,
},
+ enableTaskList: {
+ type: Boolean,
+ required: true,
+ },
+ canEdit: {
+ type: Boolean,
+ required: true,
+ },
+ taskListUpdatePath: {
+ type: String,
+ required: true,
+ },
},
mounted() {
this.renderGFM();
@@ -25,7 +37,16 @@ export default {
</script>
<template>
- <div class="description">
+ <div class="description" :class="{ 'js-task-list-container': canEdit && enableTaskList }">
<div ref="gfmContainer" v-safe-html="issuable.descriptionHtml" class="md"></div>
+ <textarea
+ v-if="issuable.description && enableTaskList"
+ ref="textarea"
+ :value="issuable.description"
+ :data-update-url="taskListUpdatePath"
+ class="gl-display-none js-task-list-field"
+ dir="auto"
+ >
+ </textarea>
</div>
</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_discussion.vue b/app/assets/javascripts/issuable_show/components/issuable_discussion.vue
new file mode 100644
index 00000000000..5858af6cc51
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_discussion.vue
@@ -0,0 +1,15 @@
+<script>
+export default {
+ name: 'IssuableDiscussion',
+};
+</script>
+
+<template>
+ <section class="issuable-discussion">
+ <div>
+ <ul class="notes main-notes-list timeline">
+ <slot name="discussion"></slot>
+ </ul>
+ </div>
+ </section>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_header.vue b/app/assets/javascripts/issuable_show/components/issuable_header.vue
index de17f7e7f6b..d7da533d055 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_header.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_header.vue
@@ -3,6 +3,7 @@ import { GlIcon, GlButton, GlTooltipDirective, GlAvatarLink, GlAvatarLabeled } f
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isExternal } from '~/lib/utils/url_utility';
+import { n__, sprintf } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
@@ -45,6 +46,11 @@ export default {
required: false,
default: false,
},
+ taskCompletionStatus: {
+ type: Object,
+ required: false,
+ default: null,
+ },
},
computed: {
authorId() {
@@ -53,6 +59,18 @@ export default {
isAuthorExternal() {
return isExternal(this.author.webUrl);
},
+ taskStatusString() {
+ const { count, completedCount } = this.taskCompletionStatus;
+
+ return sprintf(
+ n__(
+ '%{completedCount} of %{count} task completed',
+ '%{completedCount} of %{count} tasks completed',
+ count,
+ ),
+ { completedCount, count },
+ );
+ },
},
mounted() {
this.toggleSidebarButtonEl = document.querySelector('.js-toggle-right-sidebar-button');
@@ -74,8 +92,8 @@ export default {
<gl-icon v-if="statusIcon" :name="statusIcon" class="d-block d-sm-none" />
<span class="d-none d-sm-block"><slot name="status-badge"></slot></span>
</div>
- <div class="issuable-meta gl-display-flex gl-align-items-center">
- <div class="gl-display-inline-block">
+ <div class="issuable-meta gl-display-flex gl-align-items-center d-md-inline-block">
+ <div v-if="blocked || confidential" class="gl-display-inline-block">
<div v-if="blocked" data-testid="blocked" class="issuable-warning-icon inline">
<gl-icon name="lock" :aria-label="__('Blocked')" />
</div>
@@ -95,13 +113,13 @@ export default {
:data-name="author.name"
:href="author.webUrl"
target="_blank"
- class="js-user-link gl-ml-2"
+ class="js-user-link gl-vertical-align-middle gl-ml-2"
>
<gl-avatar-labeled
:size="24"
:src="author.avatarUrl"
:label="author.name"
- class="d-none d-sm-inline-flex gl-ml-1"
+ class="d-none d-sm-inline-flex gl-mx-1"
>
<template #meta>
<gl-icon v-if="isAuthorExternal" name="external-link" />
@@ -109,6 +127,12 @@ export default {
</gl-avatar-labeled>
<strong class="author d-sm-none d-inline">@{{ author.username }}</strong>
</gl-avatar-link>
+ <span
+ v-if="taskCompletionStatus"
+ data-testid="task-status"
+ class="gl-display-none gl-md-display-block gl-lg-display-inline-block"
+ >{{ taskStatusString }}</span
+ >
</div>
<gl-button
data-testid="sidebar-toggle"
diff --git a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
index 240f35b74c8..b514a6b01d8 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
@@ -2,6 +2,7 @@
import IssuableSidebar from '~/issuable_sidebar/components/issuable_sidebar_root.vue';
import IssuableBody from './issuable_body.vue';
+import IssuableDiscussion from './issuable_discussion.vue';
import IssuableHeader from './issuable_header.vue';
export default {
@@ -9,6 +10,7 @@ export default {
IssuableSidebar,
IssuableHeader,
IssuableBody,
+ IssuableDiscussion,
},
props: {
issuable: {
@@ -40,6 +42,11 @@ export default {
required: false,
default: true,
},
+ enableTaskList: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
editFormVisible: {
type: Boolean,
required: false,
@@ -60,6 +67,21 @@ export default {
required: false,
default: '',
},
+ taskCompletionStatus: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ taskListUpdatePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ taskListLockVersion: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
methods: {
handleKeydownTitle(e, issuableMeta) {
@@ -81,6 +103,7 @@ export default {
:confidential="issuable.confidential"
:created-at="issuable.createdAt"
:author="issuable.author"
+ :task-completion-status="taskCompletionStatus"
>
<template #status-badge>
<slot name="status-badge"></slot>
@@ -89,6 +112,7 @@ export default {
<slot name="header-actions"></slot>
</template>
</issuable-header>
+
<issuable-body
:issuable="issuable"
:status-badge-class="statusBadgeClass"
@@ -96,11 +120,16 @@ export default {
:enable-edit="enableEdit"
:enable-autocomplete="enableAutocomplete"
:enable-autosave="enableAutosave"
+ :enable-task-list="enableTaskList"
:edit-form-visible="editFormVisible"
:show-field-title="showFieldTitle"
:description-preview-path="descriptionPreviewPath"
:description-help-path="descriptionHelpPath"
+ :task-list-update-path="taskListUpdatePath"
+ :task-list-lock-version="taskListLockVersion"
@edit-issuable="$emit('edit-issuable', $event)"
+ @task-list-update-success="$emit('task-list-update-success', $event)"
+ @task-list-update-failure="$emit('task-list-update-failure')"
@keydown-title="handleKeydownTitle"
@keydown-description="handleKeydownDescription"
>
@@ -111,6 +140,13 @@ export default {
<slot name="edit-form-actions" v-bind="actionsProps"></slot>
</template>
</issuable-body>
+
+ <issuable-discussion>
+ <template #discussion>
+ <slot name="discussion"></slot>
+ </template>
+ </issuable-discussion>
+
<issuable-sidebar @sidebar-toggle="$emit('sidebar-toggle', $event)">
<template #right-sidebar-items="sidebarProps">
<slot name="right-sidebar-items" v-bind="sidebarProps"></slot>