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-06-06 00:09:04 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-06 00:09:04 +0300
commit96e23b2017cbe56969771960f6c274c5d3599397 (patch)
treeb8b17da1ab080dd41fc64fc0262de2cf16754559 /app/assets/javascripts/design_management
parent2f1a81fd16ff9968d6b986f8a407d963bc2218f9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/design_management')
-rw-r--r--app/assets/javascripts/design_management/components/design_description/description_form.vue234
-rw-r--r--app/assets/javascripts/design_management/components/design_sidebar.vue12
-rw-r--r--app/assets/javascripts/design_management/graphql/fragments/design_list.fragment.graphql2
-rw-r--r--app/assets/javascripts/design_management/graphql/mutations/update_design_description.mutation.graphql11
-rw-r--r--app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql4
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue1
-rw-r--r--app/assets/javascripts/design_management/utils/design_management_utils.js2
-rw-r--r--app/assets/javascripts/design_management/utils/error_messages.js4
8 files changed, 270 insertions, 0 deletions
diff --git a/app/assets/javascripts/design_management/components/design_description/description_form.vue b/app/assets/javascripts/design_management/components/design_description/description_form.vue
new file mode 100644
index 00000000000..890d7f80f8d
--- /dev/null
+++ b/app/assets/javascripts/design_management/components/design_description/description_form.vue
@@ -0,0 +1,234 @@
+<script>
+import { GlButton, GlFormGroup, GlAlert, GlTooltipDirective } from '@gitlab/ui';
+
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { __, s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
+import glFeaturesFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { renderGFM } from '~/behaviors/markdown/render_gfm';
+import { toggleMarkCheckboxes } from '~/behaviors/markdown/utils';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+
+import updateDesignDescriptionMutation from '../../graphql/mutations/update_design_description.mutation.graphql';
+import { UPDATE_DESCRIPTION_ERROR } from '../../utils/error_messages';
+
+const isCheckbox = (target) => target?.classList.contains('task-list-item-checkbox');
+
+export default {
+ components: {
+ MarkdownEditor,
+ GlAlert,
+ GlButton,
+ GlFormGroup,
+ },
+ directives: {
+ SafeHtml,
+ GlTooltip: GlTooltipDirective,
+ },
+ i18n: {
+ edit: __('Edit'),
+ editDescription: s__('DesignManagement|Edit description'),
+ descriptionLabel: s__('DesignManagement|Design description'),
+ },
+ formFieldProps: {
+ id: 'design-description',
+ name: 'design-description',
+ placeholder: s__('DesignManagement|Write a comment or drag your files hereā€¦'),
+ 'aria-label': s__('DesignManagement|Design description'),
+ },
+ mixins: [glFeaturesFlagMixin()],
+ markdownDocsPath: helpPagePath('user/markdown'),
+ quickActionsDocsPath: helpPagePath('user/project/quick_actions'),
+ props: {
+ design: {
+ type: Object,
+ required: true,
+ },
+ markdownPreviewPath: {
+ type: String,
+ required: true,
+ },
+ designVariables: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ descriptionText: this.design.description || '',
+ showEditor: false,
+ isSubmitting: false,
+ errorMessage: '',
+ autosaveKey: `Issue/${getIdFromGraphQLId(this.design.issue.id)}/Design/${getIdFromGraphQLId(
+ this.design.id,
+ )}`,
+ };
+ },
+ computed: {
+ canUpdate() {
+ return this.design.issue?.userPermissions?.updateDesign && !this.showEditor;
+ },
+ },
+ watch: {
+ 'design.descriptionHtml': {
+ handler(newDescriptionHtml, oldDescriptionHtml) {
+ if (newDescriptionHtml !== oldDescriptionHtml) {
+ this.renderGFM();
+ }
+ },
+ immediate: true,
+ },
+ },
+ methods: {
+ startEditing() {
+ this.showEditor = true;
+ },
+ closeForm() {
+ this.showEditor = false;
+ },
+ async renderGFM() {
+ await this.$nextTick();
+ renderGFM(this.$refs['gfm-content']);
+
+ if (this.canUpdate) {
+ const checkboxes = this.$el.querySelectorAll('.task-list-item-checkbox');
+
+ // enable boxes, disabled by default in markdown
+ checkboxes.forEach((checkbox) => {
+ // eslint-disable-next-line no-param-reassign
+ checkbox.disabled = false;
+ });
+ }
+ },
+ setDescriptionText(newText) {
+ // Do not update when cmd+enter is executed
+ if (!this.isSubmitting) {
+ this.descriptionText = newText;
+ }
+ },
+ async updateDesignDescription() {
+ this.isSubmitting = true;
+
+ try {
+ const designDescriptionInput = { description: this.descriptionText, id: this.design.id };
+
+ await this.$apollo.mutate({
+ mutation: updateDesignDescriptionMutation,
+ variables: {
+ input: designDescriptionInput,
+ },
+ });
+
+ this.closeForm();
+ } catch {
+ this.errorMessage = UPDATE_DESCRIPTION_ERROR;
+ } finally {
+ this.isSubmitting = false;
+ }
+ },
+ toggleCheckboxes(event) {
+ const { target } = event;
+
+ if (isCheckbox(target)) {
+ target.disabled = true;
+
+ const { sourcepos } = target.parentElement.dataset;
+
+ if (!sourcepos) return;
+
+ // Toggle checkboxes based on user input
+ this.descriptionText = toggleMarkCheckboxes({
+ rawMarkdown: this.descriptionText,
+ checkboxChecked: target.checked,
+ sourcepos,
+ });
+
+ // Update the desciption text using mutation
+ this.updateDesignDescription();
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="design-description-container">
+ <gl-form-group
+ v-if="showEditor"
+ class="design-description-form common-note-form"
+ :label="$options.i18n.descriptionLabel"
+ >
+ <div v-if="errorMessage" class="gl-pb-3">
+ <gl-alert variant="danger" @dismiss="errorMessage = null">
+ {{ errorMessage }}
+ </gl-alert>
+ </div>
+ <markdown-editor
+ :value="descriptionText"
+ :render-markdown-path="markdownPreviewPath"
+ :markdown-docs-path="$options.markdownDocsPath"
+ :form-field-props="$options.formFieldProps"
+ :enable-content-editor="Boolean(glFeatures.contentEditorOnIssues)"
+ :quick-actions-docs-path="$options.quickActionsDocsPath"
+ :autosave-key="autosaveKey"
+ enable-autocomplete
+ :supports-quick-actions="false"
+ autofocus
+ @input="setDescriptionText"
+ @keydown.meta.enter="updateDesignDescription"
+ @keydown.ctrl.enter="updateDesignDescription"
+ @keydown.exact.esc.stop="closeForm"
+ />
+ <div class="gl-display-flex gl-mt-3">
+ <gl-button
+ category="primary"
+ variant="confirm"
+ :loading="isSubmitting"
+ data-testid="save-description"
+ @click="updateDesignDescription"
+ >{{ s__('DesignManagement|Save') }}
+ </gl-button>
+ <gl-button category="tertiary" class="gl-ml-3" data-testid="cancel" @click="closeForm"
+ >{{ s__('DesignManagement|Cancel') }}
+ </gl-button>
+ </div>
+ </gl-form-group>
+ <div v-else class="design-description-view">
+ <div
+ class="design-description-header gl-display-flex gl-justify-content-space-between gl-mb-2"
+ >
+ <label class="gl-m-0">
+ {{ $options.i18n.descriptionLabel }}
+ </label>
+ <gl-button
+ v-if="canUpdate"
+ v-gl-tooltip
+ class="gl-ml-auto"
+ size="small"
+ data-testid="edit-description"
+ :aria-label="$options.i18n.editDescription"
+ @click="startEditing"
+ >
+ {{ $options.i18n.edit }}
+ </gl-button>
+ </div>
+ <div
+ v-if="!design.descriptionHtml"
+ data-testid="design-description-none"
+ class="gl-text-secondary gl-mb-5"
+ >
+ {{ s__('DesignManagement|None') }}
+ </div>
+ <div v-else class="design-description js-task-list-container">
+ <div
+ ref="gfm-content"
+ v-safe-html="design.descriptionHtml"
+ class="md gl-mb-4"
+ data-testid="design-description-content"
+ @change="toggleCheckboxes"
+ ></div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/design_management/components/design_sidebar.vue b/app/assets/javascripts/design_management/components/design_sidebar.vue
index c34d5cea0c2..9a8685f4c86 100644
--- a/app/assets/javascripts/design_management/components/design_sidebar.vue
+++ b/app/assets/javascripts/design_management/components/design_sidebar.vue
@@ -9,6 +9,7 @@ import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../constants';
import updateActiveDiscussionMutation from '../graphql/mutations/update_active_discussion.mutation.graphql';
import { extractDiscussions, extractParticipants } from '../utils/design_management_utils';
import DesignDiscussion from './design_notes/design_discussion.vue';
+import DescriptionForm from './design_description/description_form.vue';
import DesignNoteSignedOut from './design_notes/design_note_signed_out.vue';
import DesignTodoButton from './design_todo_button.vue';
@@ -21,6 +22,7 @@ export default {
GlAccordionItem,
GlSkeletonLoader,
DesignTodoButton,
+ DescriptionForm,
},
mixins: [glFeatureFlagsMixin()],
inject: {
@@ -54,6 +56,10 @@ export default {
type: Boolean,
required: true,
},
+ designVariables: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -143,6 +149,12 @@ export default {
:href="issue.webUrl"
>{{ issue.webPath }}</a
>
+ <description-form
+ v-if="!isLoading"
+ :design="design"
+ :design-variables="designVariables"
+ :markdown-preview-path="markdownPreviewPath"
+ />
<participants
:participants="discussionParticipants"
:show-participant-label="false"
diff --git a/app/assets/javascripts/design_management/graphql/fragments/design_list.fragment.graphql b/app/assets/javascripts/design_management/graphql/fragments/design_list.fragment.graphql
index 9bd70e7e886..575201a7635 100644
--- a/app/assets/javascripts/design_management/graphql/fragments/design_list.fragment.graphql
+++ b/app/assets/javascripts/design_management/graphql/fragments/design_list.fragment.graphql
@@ -5,6 +5,8 @@ fragment DesignListItem on Design {
notesCount
image
imageV432x230
+ description
+ descriptionHtml
currentUserTodos(state: pending) {
nodes {
id
diff --git a/app/assets/javascripts/design_management/graphql/mutations/update_design_description.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/update_design_description.mutation.graphql
new file mode 100644
index 00000000000..78b66477747
--- /dev/null
+++ b/app/assets/javascripts/design_management/graphql/mutations/update_design_description.mutation.graphql
@@ -0,0 +1,11 @@
+mutation updateDesignDescriptionMutation($input: DesignManagementUpdateInput!) {
+ designManagementUpdate(input: $input) {
+ errors
+ design {
+ id
+ image
+ description
+ descriptionHtml
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql
index 730467c33f6..c6eda2797d5 100644
--- a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql
+++ b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql
@@ -25,6 +25,10 @@ query getDesign(
...Author
}
}
+ userPermissions {
+ createDesign
+ updateDesign
+ }
}
}
}
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index eeb36e59b89..65e04b1ff98 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -385,6 +385,7 @@ export default {
</div>
<design-sidebar
:design="design"
+ :design-variables="designVariables"
:resolved-discussions-expanded="resolvedDiscussionsExpanded"
:markdown-preview-path="markdownPreviewPath"
:is-loading="isLoading"
diff --git a/app/assets/javascripts/design_management/utils/design_management_utils.js b/app/assets/javascripts/design_management/utils/design_management_utils.js
index 7470f3d259b..2db34ea7103 100644
--- a/app/assets/javascripts/design_management/utils/design_management_utils.js
+++ b/app/assets/javascripts/design_management/utils/design_management_utils.js
@@ -61,6 +61,8 @@ export const designUploadOptimisticResponse = (files) => {
id: -uniqueId(),
image: '',
imageV432x230: '',
+ description: '',
+ descriptionHtml: '',
filename: file.name,
fullPath: '',
notesCount: 0,
diff --git a/app/assets/javascripts/design_management/utils/error_messages.js b/app/assets/javascripts/design_management/utils/error_messages.js
index 1ed054abe22..2b5d04959b4 100644
--- a/app/assets/javascripts/design_management/utils/error_messages.js
+++ b/app/assets/javascripts/design_management/utils/error_messages.js
@@ -138,3 +138,7 @@ export const MAXIMUM_FILE_UPLOAD_LIMIT_REACHED = sprintf(
upload_limit: MAXIMUM_FILE_UPLOAD_LIMIT,
},
);
+
+export const UPDATE_DESCRIPTION_ERROR = s__(
+ 'DesignManagement|Could not update description. Please try again.',
+);