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:
Diffstat (limited to 'app/assets/javascripts/issues/show')
-rw-r--r--app/assets/javascripts/issues/show/components/app.vue25
-rw-r--r--app/assets/javascripts/issues/show/components/description.vue36
-rw-r--r--app/assets/javascripts/issues/show/components/edited.vue78
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue2
4 files changed, 78 insertions, 63 deletions
diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue
index 15f97222971..bc32a15a420 100644
--- a/app/assets/javascripts/issues/show/components/app.vue
+++ b/app/assets/javascripts/issues/show/components/app.vue
@@ -14,6 +14,7 @@ import Poll from '~/lib/utils/poll';
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 { ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH, POLLING_DELAY } from '../constants';
import eventHub from '../event_hub';
import getIssueStateQuery from '../queries/get_issue_state.query.graphql';
@@ -95,10 +96,10 @@ export default {
required: false,
default: '',
},
- initialTaskStatus: {
- type: String,
+ initialTaskCompletionStatus: {
+ type: Object,
required: false,
- default: '',
+ default: () => ({}),
},
updatedAt: {
type: String,
@@ -197,7 +198,7 @@ export default {
updatedAt: this.updatedAt,
updatedByName: this.updatedByName,
updatedByPath: this.updatedByPath,
- taskStatus: this.initialTaskStatus,
+ taskCompletionStatus: this.initialTaskCompletionStatus,
lock_version: this.lockVersion,
});
@@ -222,9 +223,6 @@ export default {
formState() {
return this.store.formState;
},
- hasUpdated() {
- return Boolean(this.state.updatedAt);
- },
issueChanged() {
const {
store: {
@@ -379,7 +377,7 @@ export default {
this.showForm = false;
},
- updateIssuable() {
+ async updateIssuable() {
this.setFormState({ updateLoading: true });
const {
@@ -392,6 +390,14 @@ export default {
this.alert?.dismiss();
+ if (containsSensitiveToken(issuablePayload.description)) {
+ const confirmed = await confirmSensitiveAction(i18n.descriptionPrompt);
+ if (!confirmed) {
+ this.setFormState({ updateLoading: false });
+ return false;
+ }
+ }
+
return this.service
.updateIssuable(issuablePayload)
.then((res) => res.data)
@@ -557,7 +563,6 @@ export default {
:description-html="state.descriptionHtml"
:description-text="state.descriptionText"
:updated-at="state.updatedAt"
- :task-status="state.taskStatus"
:issuable-type="issuableType"
:update-url="updateEndpoint"
:lock-version="state.lock_version"
@@ -570,7 +575,7 @@ export default {
/>
<edited-component
- v-if="hasUpdated"
+ :task-completion-status="state.taskCompletionStatus"
:updated-at="state.updatedAt"
:updated-by-name="state.updatedByName"
:updated-by-path="state.updatedByPath"
diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue
index bdee6c5fe9a..3721f224d5e 100644
--- a/app/assets/javascripts/issues/show/components/description.vue
+++ b/app/assets/javascripts/issues/show/components/description.vue
@@ -1,6 +1,5 @@
<script>
import { GlToast } from '@gitlab/ui';
-import $ from 'jquery';
import Sortable from 'sortablejs';
import Vue from 'vue';
import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
@@ -59,11 +58,6 @@ export default {
required: false,
default: '',
},
- taskStatus: {
- type: String,
- required: false,
- default: '',
- },
issuableType: {
type: String,
required: false,
@@ -138,7 +132,10 @@ export default {
},
watch: {
descriptionHtml(newDescription, oldDescription) {
- if (!this.initialUpdate && newDescription !== oldDescription) {
+ if (
+ !this.initialUpdate &&
+ this.stripClientState(newDescription) !== this.stripClientState(oldDescription)
+ ) {
this.animateChange();
} else {
this.initialUpdate = false;
@@ -148,16 +145,12 @@ export default {
this.renderGFM();
});
},
- taskStatus() {
- this.updateTaskStatusText();
- },
},
mounted() {
eventHub.$on('convert-task-list-item', this.convertTaskListItem);
eventHub.$on('delete-task-list-item', this.deleteTaskListItem);
this.renderGFM();
- this.updateTaskStatusText();
},
beforeDestroy() {
eventHub.$off('convert-task-list-item', this.convertTaskListItem);
@@ -282,24 +275,6 @@ export default {
this.$emit('taskListUpdateFailed');
},
- updateTaskStatusText() {
- const taskRegexMatches = this.taskStatus.match(/(\d+) of ((?!0)\d+)/);
- const $issuableHeader = $('.issuable-meta');
- const $tasks = $('#task_status', $issuableHeader);
- const $tasksShort = $('#task_status_short', $issuableHeader);
-
- if (taskRegexMatches) {
- $tasks.text(this.taskStatus);
- $tasksShort.text(
- `${taskRegexMatches[1]}/${taskRegexMatches[2]} checklist item${
- taskRegexMatches[2] > 1 ? 's' : ''
- }`,
- );
- } else {
- $tasks.text('');
- $tasksShort.text('');
- }
- },
createTaskListItemActions(provide) {
const app = new Vue({
el: document.createElement('div'),
@@ -349,6 +324,9 @@ export default {
listItem.append(element);
}
},
+ stripClientState(description) {
+ return description.replaceAll('<details open="true">', '<details>');
+ },
async createTask({ taskTitle, taskDescription, oldDescription }) {
try {
const { title, description } = extractTaskTitleAndDescription(taskTitle, taskDescription);
diff --git a/app/assets/javascripts/issues/show/components/edited.vue b/app/assets/javascripts/issues/show/components/edited.vue
index 5138a4530e9..6a0edb59b65 100644
--- a/app/assets/javascripts/issues/show/components/edited.vue
+++ b/app/assets/javascripts/issues/show/components/edited.vue
@@ -1,13 +1,20 @@
<script>
-import { GlSprintf } from '@gitlab/ui';
+import { GlLink, GlSprintf } from '@gitlab/ui';
+import { n__, sprintf } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
components: {
TimeAgoTooltip,
+ GlLink,
GlSprintf,
},
props: {
+ taskCompletionStatus: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
updatedAt: {
type: String,
required: false,
@@ -25,36 +32,61 @@ export default {
},
},
computed: {
+ completedCount() {
+ return this.taskCompletionStatus.completed_count;
+ },
+ count() {
+ return this.taskCompletionStatus.count;
+ },
hasUpdatedBy() {
return this.updatedByName && this.updatedByPath;
},
+ showCheck() {
+ return this.completedCount === this.count;
+ },
+ taskStatus() {
+ const { completedCount, count } = this;
+ if (!count) {
+ return undefined;
+ }
+
+ return sprintf(
+ n__(
+ '%{completedCount} of %{count} checklist item completed',
+ '%{completedCount} of %{count} checklist items completed',
+ count,
+ ),
+ { completedCount, count },
+ );
+ },
},
};
</script>
<template>
<small class="edited-text js-issue-widgets">
- <gl-sprintf v-if="!hasUpdatedBy" :message="__('Edited %{timeago}')">
- <template #timeago>
- <time-ago-tooltip :time="updatedAt" tooltip-placement="bottom" />
- </template>
- </gl-sprintf>
- <gl-sprintf v-else-if="!updatedAt" :message="__('Edited by %{author}')">
- <template #author>
- <a :href="updatedByPath" class="author-link gl-hover-text-decoration-underline">
- <span>{{ updatedByName }}</span>
- </a>
- </template>
- </gl-sprintf>
- <gl-sprintf v-else :message="__('Edited %{timeago} by %{author}')">
- <template #timeago>
- <time-ago-tooltip :time="updatedAt" tooltip-placement="bottom" />
- </template>
- <template #author>
- <a :href="updatedByPath" class="author-link gl-hover-text-decoration-underline">
- <span>{{ updatedByName }}</span>
- </a>
- </template>
- </gl-sprintf>
+ <template v-if="taskStatus">
+ <template v-if="showCheck">&check;</template>
+ {{ taskStatus }}
+ <template v-if="updatedAt">&middot;</template>
+ </template>
+
+ <template v-if="updatedAt">
+ <gl-sprintf v-if="!hasUpdatedBy" :message="__('Edited %{timeago}')">
+ <template #timeago>
+ <time-ago-tooltip :time="updatedAt" tooltip-placement="bottom" />
+ </template>
+ </gl-sprintf>
+ <gl-sprintf v-else :message="__('Edited %{timeago} by %{author}')">
+ <template #timeago>
+ <time-ago-tooltip :time="updatedAt" tooltip-placement="bottom" />
+ </template>
+ <template #author>
+ <gl-link :href="updatedByPath" class="gl-font-sm gl-hover-text-gray-900 gl-text-gray-700">
+ {{ updatedByName }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
</small>
</template>
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
index 243666b2323..8267c0130a3 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue
@@ -199,7 +199,7 @@ export default {
<p class="gl-ml-3 gl-align-self-end gl-line-height-32">{{ __('UTC') }}</p>
</div>
</div>
- <gl-form-group v-if="glFeatures.incidentEventTags">
+ <gl-form-group>
<label class="gl-display-flex gl-align-items-center gl-gap-3" for="timeline-input-tags">
{{ $options.i18n.tagsLabel }}
<timeline-events-tags-popover />