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/design_management_legacy/components')
-rw-r--r--app/assets/javascripts/design_management_legacy/components/app.vue3
-rw-r--r--app/assets/javascripts/design_management_legacy/components/delete_button.vue64
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_destroyer.vue66
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_note_pin.vue61
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_notes/design_discussion.vue297
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_notes/design_note.vue156
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_notes/design_reply_form.vue141
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_notes/toggle_replies_widget.vue70
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_overlay.vue287
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_presentation.vue322
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_scaler.vue65
-rw-r--r--app/assets/javascripts/design_management_legacy/components/design_sidebar.vue178
-rw-r--r--app/assets/javascripts/design_management_legacy/components/image.vue110
-rw-r--r--app/assets/javascripts/design_management_legacy/components/list/item.vue174
-rw-r--r--app/assets/javascripts/design_management_legacy/components/toolbar/index.vue126
-rw-r--r--app/assets/javascripts/design_management_legacy/components/toolbar/pagination.vue83
-rw-r--r--app/assets/javascripts/design_management_legacy/components/toolbar/pagination_button.vue48
-rw-r--r--app/assets/javascripts/design_management_legacy/components/upload/button.vue58
-rw-r--r--app/assets/javascripts/design_management_legacy/components/upload/design_dropzone.vue134
-rw-r--r--app/assets/javascripts/design_management_legacy/components/upload/design_version_dropdown.vue76
20 files changed, 0 insertions, 2519 deletions
diff --git a/app/assets/javascripts/design_management_legacy/components/app.vue b/app/assets/javascripts/design_management_legacy/components/app.vue
deleted file mode 100644
index 98240aef810..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/app.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-<template>
- <router-view />
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/delete_button.vue b/app/assets/javascripts/design_management_legacy/components/delete_button.vue
deleted file mode 100644
index 1fd902c9ed7..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/delete_button.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
-import { uniqueId } from 'lodash';
-
-export default {
- name: 'DeleteButton',
- components: {
- GlDeprecatedButton,
- GlModal,
- },
- directives: {
- GlModalDirective,
- },
- props: {
- isDeleting: {
- type: Boolean,
- required: false,
- default: false,
- },
- buttonClass: {
- type: String,
- required: false,
- default: '',
- },
- buttonVariant: {
- type: String,
- required: false,
- default: '',
- },
- hasSelectedDesigns: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
- data() {
- return {
- modalId: uniqueId('design-deletion-confirmation-'),
- };
- },
-};
-</script>
-
-<template>
- <div>
- <gl-modal
- :modal-id="modalId"
- :title="s__('DesignManagement|Delete designs confirmation')"
- :ok-title="s__('DesignManagement|Delete')"
- ok-variant="danger"
- @ok="$emit('deleteSelectedDesigns')"
- >
- <p>{{ s__('DesignManagement|Are you sure you want to delete the selected designs?') }}</p>
- </gl-modal>
- <gl-deprecated-button
- v-gl-modal-directive="modalId"
- :variant="buttonVariant"
- :disabled="isDeleting || !hasSelectedDesigns"
- :class="buttonClass"
- >
- <slot></slot>
- </gl-deprecated-button>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_destroyer.vue b/app/assets/javascripts/design_management_legacy/components/design_destroyer.vue
deleted file mode 100644
index 62460ca551c..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_destroyer.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { ApolloMutation } from 'vue-apollo';
-import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
-import destroyDesignMutation from '../graphql/mutations/destroy_design.mutation.graphql';
-import { updateStoreAfterDesignsDelete } from '../utils/cache_update';
-
-export default {
- components: {
- ApolloMutation,
- },
- props: {
- filenames: {
- type: Array,
- required: true,
- },
- projectPath: {
- type: String,
- required: true,
- },
- iid: {
- type: String,
- required: true,
- },
- },
- computed: {
- projectQueryBody() {
- return {
- query: getDesignListQuery,
- variables: { fullPath: this.projectPath, iid: this.iid, atVersion: null },
- };
- },
- },
- methods: {
- updateStoreAfterDelete(
- store,
- {
- data: { designManagementDelete },
- },
- ) {
- updateStoreAfterDesignsDelete(
- store,
- designManagementDelete,
- this.projectQueryBody,
- this.filenames,
- );
- },
- },
- destroyDesignMutation,
-};
-</script>
-
-<template>
- <apollo-mutation
- #default="{ mutate, loading, error }"
- :mutation="$options.destroyDesignMutation"
- :variables="{
- filenames,
- projectPath,
- iid,
- }"
- :update="updateStoreAfterDelete"
- v-on="$listeners"
- >
- <slot v-bind="{ mutate, loading, error }"></slot>
- </apollo-mutation>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_note_pin.vue b/app/assets/javascripts/design_management_legacy/components/design_note_pin.vue
deleted file mode 100644
index 2b5e62c2870..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_note_pin.vue
+++ /dev/null
@@ -1,61 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-
-export default {
- name: 'DesignNotePin',
- components: {
- GlIcon,
- },
- props: {
- position: {
- type: Object,
- required: true,
- },
- label: {
- type: Number,
- required: false,
- default: null,
- },
- repositioning: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- computed: {
- isNewNote() {
- return this.label === null;
- },
- pinStyle() {
- return this.repositioning ? { ...this.position, cursor: 'move' } : this.position;
- },
- pinLabel() {
- return this.isNewNote
- ? __('Comment form position')
- : sprintf(__("Comment '%{label}' position"), { label: this.label });
- },
- },
-};
-</script>
-
-<template>
- <button
- :style="pinStyle"
- :aria-label="pinLabel"
- :class="{
- 'btn-transparent comment-indicator': isNewNote,
- 'js-image-badge badge badge-pill': !isNewNote,
- }"
- class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0"
- type="button"
- @mousedown="$emit('mousedown', $event)"
- @mouseup="$emit('mouseup', $event)"
- @click="$emit('click', $event)"
- >
- <gl-icon v-if="isNewNote" name="image-comment-dark" :size="24" />
- <template v-else>
- {{ label }}
- </template>
- </button>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_notes/design_discussion.vue b/app/assets/javascripts/design_management_legacy/components/design_notes/design_discussion.vue
deleted file mode 100644
index 6a20517eed7..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_notes/design_discussion.vue
+++ /dev/null
@@ -1,297 +0,0 @@
-<script>
-import { ApolloMutation } from 'vue-apollo';
-import { GlTooltipDirective, GlIcon, GlLoadingIcon, GlLink } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import allVersionsMixin from '../../mixins/all_versions';
-import createNoteMutation from '../../graphql/mutations/create_note.mutation.graphql';
-import toggleResolveDiscussionMutation from '../../graphql/mutations/toggle_resolve_discussion.mutation.graphql';
-import getDesignQuery from '../../graphql/queries/get_design.query.graphql';
-import activeDiscussionQuery from '../../graphql/queries/active_discussion.query.graphql';
-import DesignNote from './design_note.vue';
-import DesignReplyForm from './design_reply_form.vue';
-import { updateStoreAfterAddDiscussionComment } from '../../utils/cache_update';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
-import ToggleRepliesWidget from './toggle_replies_widget.vue';
-
-export default {
- components: {
- ApolloMutation,
- DesignNote,
- ReplyPlaceholder,
- DesignReplyForm,
- GlIcon,
- GlLoadingIcon,
- GlLink,
- ToggleRepliesWidget,
- TimeAgoTooltip,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [allVersionsMixin],
- props: {
- discussion: {
- type: Object,
- required: true,
- },
- noteableId: {
- type: String,
- required: true,
- },
- designId: {
- type: String,
- required: true,
- },
- markdownPreviewPath: {
- type: String,
- required: false,
- default: '',
- },
- resolvedDiscussionsExpanded: {
- type: Boolean,
- required: true,
- },
- discussionWithOpenForm: {
- type: String,
- required: true,
- },
- },
- apollo: {
- activeDiscussion: {
- query: activeDiscussionQuery,
- result({ data }) {
- const discussionId = data.activeDiscussion.id;
- if (this.discussion.resolved && !this.resolvedDiscussionsExpanded) {
- return;
- }
- // We watch any changes to the active discussion from the design pins and scroll to this discussion if it exists
- // We don't want scrollIntoView to be triggered from the discussion click itself
- if (
- discussionId &&
- data.activeDiscussion.source === ACTIVE_DISCUSSION_SOURCE_TYPES.pin &&
- discussionId === this.discussion.notes[0].id
- ) {
- this.$el.scrollIntoView({
- behavior: 'smooth',
- inline: 'start',
- });
- }
- },
- },
- },
- data() {
- return {
- discussionComment: '',
- isFormRendered: false,
- activeDiscussion: {},
- isResolving: false,
- shouldChangeResolvedStatus: false,
- areRepliesCollapsed: this.discussion.resolved,
- };
- },
- computed: {
- mutationPayload() {
- return {
- noteableId: this.noteableId,
- body: this.discussionComment,
- discussionId: this.discussion.id,
- };
- },
- designVariables() {
- return {
- fullPath: this.projectPath,
- iid: this.issueIid,
- filenames: [this.$route.params.id],
- atVersion: this.designsVersion,
- };
- },
- isDiscussionHighlighted() {
- return this.discussion.notes[0].id === this.activeDiscussion.id;
- },
- resolveCheckboxText() {
- return this.discussion.resolved
- ? s__('DesignManagement|Unresolve thread')
- : s__('DesignManagement|Resolve thread');
- },
- firstNote() {
- return this.discussion.notes[0];
- },
- discussionReplies() {
- return this.discussion.notes.slice(1);
- },
- areRepliesShown() {
- return !this.discussion.resolved || !this.areRepliesCollapsed;
- },
- resolveIconName() {
- return this.discussion.resolved ? 'check-circle-filled' : 'check-circle';
- },
- isRepliesWidgetVisible() {
- return this.discussion.resolved && this.discussionReplies.length > 0;
- },
- isReplyPlaceholderVisible() {
- return this.areRepliesShown || !this.discussionReplies.length;
- },
- isFormVisible() {
- return this.isFormRendered && this.discussionWithOpenForm === this.discussion.id;
- },
- },
- methods: {
- addDiscussionComment(
- store,
- {
- data: { createNote },
- },
- ) {
- updateStoreAfterAddDiscussionComment(
- store,
- createNote,
- getDesignQuery,
- this.designVariables,
- this.discussion.id,
- );
- },
- onDone() {
- this.discussionComment = '';
- this.hideForm();
- if (this.shouldChangeResolvedStatus) {
- this.toggleResolvedStatus();
- }
- },
- onCreateNoteError(err) {
- this.$emit('createNoteError', err);
- },
- hideForm() {
- this.isFormRendered = false;
- this.discussionComment = '';
- },
- showForm() {
- this.$emit('openForm', this.discussion.id);
- this.isFormRendered = true;
- },
- toggleResolvedStatus() {
- this.isResolving = true;
- this.$apollo
- .mutate({
- mutation: toggleResolveDiscussionMutation,
- variables: { id: this.discussion.id, resolve: !this.discussion.resolved },
- })
- .then(({ data }) => {
- if (data.errors?.length > 0) {
- this.$emit('resolveDiscussionError', data.errors[0]);
- }
- })
- .catch(err => {
- this.$emit('resolveDiscussionError', err);
- })
- .finally(() => {
- this.isResolving = false;
- });
- },
- },
- createNoteMutation,
-};
-</script>
-
-<template>
- <div class="design-discussion-wrapper">
- <div
- class="badge badge-pill gl-display-flex gl-align-items-center gl-justify-content-center"
- :class="{ resolved: discussion.resolved }"
- type="button"
- >
- {{ discussion.index }}
- </div>
- <ul
- class="design-discussion bordered-box gl-relative gl-p-0 gl-list-style-none"
- data-qa-selector="design_discussion_content"
- >
- <design-note
- :note="firstNote"
- :markdown-preview-path="markdownPreviewPath"
- :is-resolving="isResolving"
- :class="{ 'gl-bg-blue-50': isDiscussionHighlighted }"
- @error="$emit('updateNoteError', $event)"
- >
- <template v-if="discussion.resolvable" #resolveDiscussion>
- <button
- v-gl-tooltip
- :class="{ 'is-active': discussion.resolved }"
- :title="resolveCheckboxText"
- :aria-label="resolveCheckboxText"
- type="button"
- class="line-resolve-btn note-action-button gl-mr-3"
- data-testid="resolve-button"
- @click.stop="toggleResolvedStatus"
- >
- <gl-icon v-if="!isResolving" :name="resolveIconName" data-testid="resolve-icon" />
- <gl-loading-icon v-else inline />
- </button>
- </template>
- <template v-if="discussion.resolved" #resolvedStatus>
- <p class="gl-text-gray-500 gl-font-sm gl-m-0 gl-mt-5" data-testid="resolved-message">
- {{ __('Resolved by') }}
- <gl-link
- class="gl-text-gray-500 gl-text-decoration-none gl-font-sm link-inherit-color"
- :href="discussion.resolvedBy.webUrl"
- target="_blank"
- >{{ discussion.resolvedBy.name }}</gl-link
- >
- <time-ago-tooltip :time="discussion.resolvedAt" tooltip-placement="bottom" />
- </p>
- </template>
- </design-note>
- <toggle-replies-widget
- v-if="isRepliesWidgetVisible"
- :collapsed="areRepliesCollapsed"
- :replies="discussionReplies"
- @toggle="areRepliesCollapsed = !areRepliesCollapsed"
- />
- <design-note
- v-for="note in discussionReplies"
- v-show="areRepliesShown"
- :key="note.id"
- :note="note"
- :markdown-preview-path="markdownPreviewPath"
- :is-resolving="isResolving"
- :class="{ 'gl-bg-blue-50': isDiscussionHighlighted }"
- @error="$emit('updateNoteError', $event)"
- />
- <li v-show="isReplyPlaceholderVisible" class="reply-wrapper">
- <reply-placeholder
- v-if="!isFormVisible"
- class="qa-discussion-reply"
- :button-text="__('Reply...')"
- @onClick="showForm"
- />
- <apollo-mutation
- v-else
- #default="{ mutate, loading }"
- :mutation="$options.createNoteMutation"
- :variables="{
- input: mutationPayload,
- }"
- :update="addDiscussionComment"
- @done="onDone"
- @error="onCreateNoteError"
- >
- <design-reply-form
- v-model="discussionComment"
- :is-saving="loading"
- :markdown-preview-path="markdownPreviewPath"
- @submitForm="mutate"
- @cancelForm="hideForm"
- >
- <template v-if="discussion.resolvable" #resolveCheckbox>
- <label data-testid="resolve-checkbox">
- <input v-model="shouldChangeResolvedStatus" type="checkbox" />
- {{ resolveCheckboxText }}
- </label>
- </template>
- </design-reply-form>
- </apollo-mutation>
- </li>
- </ul>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_notes/design_note.vue b/app/assets/javascripts/design_management_legacy/components/design_notes/design_note.vue
deleted file mode 100644
index b1f3a43a66d..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_notes/design_note.vue
+++ /dev/null
@@ -1,156 +0,0 @@
-<script>
-import { ApolloMutation } from 'vue-apollo';
-import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
-import updateNoteMutation from '../../graphql/mutations/update_note.mutation.graphql';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import DesignReplyForm from './design_reply_form.vue';
-import { findNoteId } from '../../utils/design_management_utils';
-import { hasErrors } from '../../utils/cache_update';
-
-export default {
- components: {
- UserAvatarLink,
- TimelineEntryItem,
- TimeAgoTooltip,
- DesignReplyForm,
- ApolloMutation,
- GlIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- note: {
- type: Object,
- required: true,
- },
- markdownPreviewPath: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- noteText: this.note.body,
- isEditing: false,
- };
- },
- computed: {
- author() {
- return this.note.author;
- },
- noteAnchorId() {
- return findNoteId(this.note.id);
- },
- isNoteLinked() {
- return this.$route.hash === `#note_${this.noteAnchorId}`;
- },
- mutationPayload() {
- return {
- id: this.note.id,
- body: this.noteText,
- };
- },
- isEditButtonVisible() {
- return !this.isEditing && this.note.userPermissions.adminNote;
- },
- },
- mounted() {
- if (this.isNoteLinked) {
- this.$refs.anchor.$el.scrollIntoView({ behavior: 'smooth', inline: 'start' });
- }
- },
- methods: {
- hideForm() {
- this.isEditing = false;
- this.noteText = this.note.body;
- },
- onDone({ data }) {
- this.hideForm();
- if (hasErrors(data.updateNote)) {
- this.$emit('error', data.errors[0]);
- }
- },
- },
- updateNoteMutation,
-};
-</script>
-
-<template>
- <timeline-entry-item :id="`note_${noteAnchorId}`" ref="anchor" class="design-note note-form">
- <user-avatar-link
- :link-href="author.webUrl"
- :img-src="author.avatarUrl"
- :img-alt="author.username"
- :img-size="40"
- />
- <div class="d-flex justify-content-between">
- <div>
- <a
- v-once
- :href="author.webUrl"
- class="js-user-link"
- :data-user-id="author.id"
- :data-username="author.username"
- >
- <span class="note-header-author-name bold">{{ author.name }}</span>
- <span v-if="author.status_tooltip_html" v-html="author.status_tooltip_html"></span>
- <span class="note-headline-light">@{{ author.username }}</span>
- </a>
- <span class="note-headline-light note-headline-meta">
- <span class="system-note-message"> <slot></slot> </span>
- <template v-if="note.createdAt">
- <span class="system-note-separator"></span>
- <a class="note-timestamp system-note-separator" :href="`#note_${noteAnchorId}`">
- <time-ago-tooltip :time="note.createdAt" tooltip-placement="bottom" />
- </a>
- </template>
- </span>
- </div>
- <div class="gl-display-flex">
- <slot name="resolveDiscussion"></slot>
- <button
- v-if="isEditButtonVisible"
- v-gl-tooltip
- type="button"
- :title="__('Edit comment')"
- class="note-action-button js-note-edit btn btn-transparent qa-note-edit-button"
- @click="isEditing = true"
- >
- <gl-icon name="pencil" class="link-highlight" />
- </button>
- </div>
- </div>
- <template v-if="!isEditing">
- <div
- class="note-text js-note-text md"
- data-qa-selector="note_content"
- v-html="note.bodyHtml"
- ></div>
- <slot name="resolvedStatus"></slot>
- </template>
- <apollo-mutation
- v-else
- #default="{ mutate, loading }"
- :mutation="$options.updateNoteMutation"
- :variables="{
- input: mutationPayload,
- }"
- @error="$emit('error', $event)"
- @done="onDone"
- >
- <design-reply-form
- v-model="noteText"
- :is-saving="loading"
- :markdown-preview-path="markdownPreviewPath"
- :is-new-comment="false"
- class="mt-5"
- @submitForm="mutate"
- @cancelForm="hideForm"
- />
- </apollo-mutation>
- </timeline-entry-item>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_notes/design_reply_form.vue b/app/assets/javascripts/design_management_legacy/components/design_notes/design_reply_form.vue
deleted file mode 100644
index 969034909f2..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_notes/design_reply_form.vue
+++ /dev/null
@@ -1,141 +0,0 @@
-<script>
-import { GlDeprecatedButton, GlModal } from '@gitlab/ui';
-import MarkdownField from '~/vue_shared/components/markdown/field.vue';
-import { s__ } from '~/locale';
-
-export default {
- name: 'DesignReplyForm',
- components: {
- MarkdownField,
- GlDeprecatedButton,
- GlModal,
- },
- props: {
- markdownPreviewPath: {
- type: String,
- required: false,
- default: '',
- },
- value: {
- type: String,
- required: true,
- },
- isSaving: {
- type: Boolean,
- required: true,
- },
- isNewComment: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
- data() {
- return {
- formText: this.value,
- };
- },
- computed: {
- hasValue() {
- return this.value.trim().length > 0;
- },
- modalSettings() {
- if (this.isNewComment) {
- return {
- title: s__('DesignManagement|Cancel comment confirmation'),
- okTitle: s__('DesignManagement|Discard comment'),
- cancelTitle: s__('DesignManagement|Keep comment'),
- content: s__('DesignManagement|Are you sure you want to cancel creating this comment?'),
- };
- }
- return {
- title: s__('DesignManagement|Cancel comment update confirmation'),
- okTitle: s__('DesignManagement|Cancel changes'),
- cancelTitle: s__('DesignManagement|Keep changes'),
- content: s__('DesignManagement|Are you sure you want to cancel changes to this comment?'),
- };
- },
- buttonText() {
- return this.isNewComment
- ? s__('DesignManagement|Comment')
- : s__('DesignManagement|Save comment');
- },
- },
- mounted() {
- this.focusInput();
- },
- methods: {
- submitForm() {
- if (this.hasValue) this.$emit('submitForm');
- },
- cancelComment() {
- if (this.hasValue && this.formText !== this.value) {
- this.$refs.cancelCommentModal.show();
- } else {
- this.$emit('cancelForm');
- }
- },
- focusInput() {
- this.$refs.textarea.focus();
- },
- },
-};
-</script>
-
-<template>
- <form class="new-note common-note-form" @submit.prevent>
- <markdown-field
- :markdown-preview-path="markdownPreviewPath"
- :can-attach-file="false"
- :enable-autocomplete="true"
- :textarea-value="value"
- markdown-docs-path="/help/user/markdown"
- class="bordered-box"
- >
- <template #textarea>
- <textarea
- ref="textarea"
- :value="value"
- class="note-textarea js-gfm-input js-autosize markdown-area"
- dir="auto"
- data-supports-quick-actions="false"
- data-qa-selector="note_textarea"
- :aria-label="__('Description')"
- :placeholder="__('Write a comment…')"
- @input="$emit('input', $event.target.value)"
- @keydown.meta.enter="submitForm"
- @keydown.ctrl.enter="submitForm"
- @keyup.esc.stop="cancelComment"
- >
- </textarea>
- </template>
- </markdown-field>
- <slot name="resolveCheckbox"></slot>
- <div class="note-form-actions gl-display-flex gl-justify-content-space-between">
- <gl-deprecated-button
- ref="submitButton"
- :disabled="!hasValue || isSaving"
- variant="success"
- type="submit"
- data-track-event="click_button"
- data-qa-selector="save_comment_button"
- @click="$emit('submitForm')"
- >
- {{ buttonText }}
- </gl-deprecated-button>
- <gl-deprecated-button ref="cancelButton" @click="cancelComment">{{
- __('Cancel')
- }}</gl-deprecated-button>
- </div>
- <gl-modal
- ref="cancelCommentModal"
- ok-variant="danger"
- :title="modalSettings.title"
- :ok-title="modalSettings.okTitle"
- :cancel-title="modalSettings.cancelTitle"
- modal-id="cancel-comment-modal"
- @ok="$emit('cancelForm')"
- >{{ modalSettings.content }}
- </gl-modal>
- </form>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_notes/toggle_replies_widget.vue b/app/assets/javascripts/design_management_legacy/components/design_notes/toggle_replies_widget.vue
deleted file mode 100644
index 2e366282de3..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_notes/toggle_replies_widget.vue
+++ /dev/null
@@ -1,70 +0,0 @@
-<script>
-import { GlIcon, GlButton, GlLink } from '@gitlab/ui';
-import { __, n__ } from '~/locale';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-
-export default {
- name: 'ToggleNotesWidget',
- components: {
- GlIcon,
- GlButton,
- GlLink,
- TimeAgoTooltip,
- },
- props: {
- collapsed: {
- type: Boolean,
- required: true,
- },
- replies: {
- type: Array,
- required: true,
- },
- },
- computed: {
- lastReply() {
- return this.replies[this.replies.length - 1];
- },
- iconName() {
- return this.collapsed ? 'chevron-right' : 'chevron-down';
- },
- toggleText() {
- return this.collapsed
- ? `${this.replies.length} ${n__('reply', 'replies', this.replies.length)}`
- : __('Collapse replies');
- },
- },
-};
-</script>
-
-<template>
- <li
- class="toggle-comments gl-bg-gray-50 gl-display-flex gl-align-items-center gl-py-3"
- :class="{ expanded: !collapsed }"
- data-testid="toggle-comments-wrapper"
- >
- <gl-icon :name="iconName" class="gl-ml-3" @click.stop="$emit('toggle')" />
- <gl-button
- variant="link"
- class="toggle-comments-button gl-ml-2 gl-mr-2"
- @click.stop="$emit('toggle')"
- >
- {{ toggleText }}
- </gl-button>
- <template v-if="collapsed">
- <span class="gl-text-gray-500">{{ __('Last reply by') }}</span>
- <gl-link
- :href="lastReply.author.webUrl"
- target="_blank"
- class="link-inherit-color gl-text-body gl-text-decoration-none gl-font-weight-bold gl-ml-2 gl-mr-2"
- >
- {{ lastReply.author.name }}
- </gl-link>
- <time-ago-tooltip
- :time="lastReply.createdAt"
- tooltip-placement="bottom"
- class="gl-text-gray-500"
- />
- </template>
- </li>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_overlay.vue b/app/assets/javascripts/design_management_legacy/components/design_overlay.vue
deleted file mode 100644
index 926e7c74802..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_overlay.vue
+++ /dev/null
@@ -1,287 +0,0 @@
-<script>
-import activeDiscussionQuery from '../graphql/queries/active_discussion.query.graphql';
-import updateActiveDiscussionMutation from '../graphql/mutations/update_active_discussion.mutation.graphql';
-import DesignNotePin from './design_note_pin.vue';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../constants';
-
-export default {
- name: 'DesignOverlay',
- components: {
- DesignNotePin,
- },
- props: {
- dimensions: {
- type: Object,
- required: true,
- },
- position: {
- type: Object,
- required: true,
- },
- notes: {
- type: Array,
- required: false,
- default: () => [],
- },
- currentCommentForm: {
- type: Object,
- required: false,
- default: null,
- },
- disableCommenting: {
- type: Boolean,
- required: false,
- default: false,
- },
- resolvedDiscussionsExpanded: {
- type: Boolean,
- required: true,
- },
- },
- apollo: {
- activeDiscussion: {
- query: activeDiscussionQuery,
- },
- },
- data() {
- return {
- movingNoteNewPosition: null,
- movingNoteStartPosition: null,
- activeDiscussion: {},
- };
- },
- computed: {
- overlayStyle() {
- const cursor = this.disableCommenting ? 'unset' : undefined;
-
- return {
- cursor,
- width: `${this.dimensions.width}px`,
- height: `${this.dimensions.height}px`,
- ...this.position,
- };
- },
- isMovingCurrentComment() {
- return Boolean(this.movingNoteStartPosition && !this.movingNoteStartPosition.noteId);
- },
- currentCommentPositionStyle() {
- return this.isMovingCurrentComment && this.movingNoteNewPosition
- ? this.getNotePositionStyle(this.movingNoteNewPosition)
- : this.getNotePositionStyle(this.currentCommentForm);
- },
- },
- methods: {
- setNewNoteCoordinates({ x, y }) {
- this.$emit('openCommentForm', { x, y });
- },
- getNoteRelativePosition(position) {
- const { x, y, width, height } = position;
- const widthRatio = this.dimensions.width / width;
- const heightRatio = this.dimensions.height / height;
- return {
- left: Math.round(x * widthRatio),
- top: Math.round(y * heightRatio),
- };
- },
- getNotePositionStyle(position) {
- const { left, top } = this.getNoteRelativePosition(position);
- return {
- left: `${left}px`,
- top: `${top}px`,
- };
- },
- getMovingNotePositionDelta(e) {
- let deltaX = 0;
- let deltaY = 0;
-
- if (this.movingNoteStartPosition) {
- const { clientX, clientY } = this.movingNoteStartPosition;
- deltaX = e.clientX - clientX;
- deltaY = e.clientY - clientY;
- }
-
- return {
- deltaX,
- deltaY,
- };
- },
- isMovingNote(noteId) {
- const movingNoteId = this.movingNoteStartPosition?.noteId;
- return Boolean(movingNoteId && movingNoteId === noteId);
- },
- canMoveNote(note) {
- const { userPermissions } = note;
- const { adminNote } = userPermissions || {};
-
- return Boolean(adminNote);
- },
- isPositionInOverlay(position) {
- const { top, left } = this.getNoteRelativePosition(position);
- const { height, width } = this.dimensions;
-
- return top >= 0 && top <= height && left >= 0 && left <= width;
- },
- onNewNoteMove(e) {
- if (!this.isMovingCurrentComment) return;
-
- const { deltaX, deltaY } = this.getMovingNotePositionDelta(e);
- const x = this.currentCommentForm.x + deltaX;
- const y = this.currentCommentForm.y + deltaY;
-
- const movingNoteNewPosition = {
- x,
- y,
- width: this.dimensions.width,
- height: this.dimensions.height,
- };
-
- if (!this.isPositionInOverlay(movingNoteNewPosition)) {
- this.onNewNoteMouseup();
- return;
- }
-
- this.movingNoteNewPosition = movingNoteNewPosition;
- },
- onExistingNoteMove(e) {
- const note = this.notes.find(({ id }) => id === this.movingNoteStartPosition.noteId);
- if (!note || !this.canMoveNote(note)) return;
-
- const { position } = note;
- const { width, height } = position;
- const widthRatio = this.dimensions.width / width;
- const heightRatio = this.dimensions.height / height;
-
- const { deltaX, deltaY } = this.getMovingNotePositionDelta(e);
- const x = position.x * widthRatio + deltaX;
- const y = position.y * heightRatio + deltaY;
-
- const movingNoteNewPosition = {
- x,
- y,
- width: this.dimensions.width,
- height: this.dimensions.height,
- };
-
- if (!this.isPositionInOverlay(movingNoteNewPosition)) {
- this.onExistingNoteMouseup();
- return;
- }
-
- this.movingNoteNewPosition = movingNoteNewPosition;
- },
- onNewNoteMouseup() {
- if (!this.movingNoteNewPosition) return;
-
- const { x, y } = this.movingNoteNewPosition;
- this.setNewNoteCoordinates({ x, y });
- },
- onExistingNoteMouseup(note) {
- if (!this.movingNoteStartPosition || !this.movingNoteNewPosition) {
- this.updateActiveDiscussion(note.id);
- this.$emit('closeCommentForm');
- return;
- }
-
- const { x, y } = this.movingNoteNewPosition;
- this.$emit('moveNote', {
- noteId: this.movingNoteStartPosition.noteId,
- discussionId: this.movingNoteStartPosition.discussionId,
- coordinates: { x, y },
- });
- },
- onNoteMousedown({ clientX, clientY }, note) {
- this.movingNoteStartPosition = {
- noteId: note?.id,
- discussionId: note?.discussion.id,
- clientX,
- clientY,
- };
- },
- onOverlayMousemove(e) {
- if (!this.movingNoteStartPosition) return;
-
- if (this.isMovingCurrentComment) {
- this.onNewNoteMove(e);
- } else {
- this.onExistingNoteMove(e);
- }
- },
- onNoteMouseup(note) {
- if (!this.movingNoteStartPosition) return;
-
- if (this.isMovingCurrentComment) {
- this.onNewNoteMouseup();
- } else {
- this.onExistingNoteMouseup(note);
- }
-
- this.movingNoteStartPosition = null;
- this.movingNoteNewPosition = null;
- },
- onAddCommentMouseup({ offsetX, offsetY }) {
- if (this.disableCommenting) return;
- if (this.activeDiscussion.id) {
- this.updateActiveDiscussion();
- }
-
- this.setNewNoteCoordinates({ x: offsetX, y: offsetY });
- },
- updateActiveDiscussion(id) {
- this.$apollo.mutate({
- mutation: updateActiveDiscussionMutation,
- variables: {
- id,
- source: ACTIVE_DISCUSSION_SOURCE_TYPES.pin,
- },
- });
- },
- isNoteInactive(note) {
- return this.activeDiscussion.id && this.activeDiscussion.id !== note.id;
- },
- designPinClass(note) {
- return { inactive: this.isNoteInactive(note), resolved: note.resolved };
- },
- },
-};
-</script>
-
-<template>
- <div
- class="position-absolute image-diff-overlay frame"
- :style="overlayStyle"
- @mousemove="onOverlayMousemove"
- @mouseleave="onNoteMouseup"
- >
- <button
- v-show="!disableCommenting"
- type="button"
- class="btn-transparent position-absolute image-diff-overlay-add-comment w-100 h-100 js-add-image-diff-note-button"
- data-qa-selector="design_image_button"
- @mouseup="onAddCommentMouseup"
- ></button>
- <template v-for="note in notes">
- <design-note-pin
- v-if="resolvedDiscussionsExpanded || !note.resolved"
- :key="note.id"
- :label="note.index"
- :repositioning="isMovingNote(note.id)"
- :position="
- isMovingNote(note.id) && movingNoteNewPosition
- ? getNotePositionStyle(movingNoteNewPosition)
- : getNotePositionStyle(note.position)
- "
- :class="designPinClass(note)"
- @mousedown.stop="onNoteMousedown($event, note)"
- @mouseup.stop="onNoteMouseup(note)"
- />
- </template>
-
- <design-note-pin
- v-if="currentCommentForm"
- :position="currentCommentPositionStyle"
- :repositioning="isMovingCurrentComment"
- @mousedown.stop="onNoteMousedown"
- @mouseup.stop="onNoteMouseup"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_presentation.vue b/app/assets/javascripts/design_management_legacy/components/design_presentation.vue
deleted file mode 100644
index 84dbb2809d9..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_presentation.vue
+++ /dev/null
@@ -1,322 +0,0 @@
-<script>
-import { throttle } from 'lodash';
-import DesignImage from './image.vue';
-import DesignOverlay from './design_overlay.vue';
-
-const CLICK_DRAG_BUFFER_PX = 2;
-
-export default {
- components: {
- DesignImage,
- DesignOverlay,
- },
- props: {
- image: {
- type: String,
- required: false,
- default: '',
- },
- imageName: {
- type: String,
- required: false,
- default: '',
- },
- discussions: {
- type: Array,
- required: true,
- },
- isAnnotating: {
- type: Boolean,
- required: false,
- default: false,
- },
- scale: {
- type: Number,
- required: false,
- default: 1,
- },
- resolvedDiscussionsExpanded: {
- type: Boolean,
- required: true,
- },
- },
- data() {
- return {
- overlayDimensions: null,
- overlayPosition: null,
- currentAnnotationPosition: null,
- zoomFocalPoint: {
- x: 0,
- y: 0,
- width: 0,
- height: 0,
- },
- initialLoad: true,
- lastDragPosition: null,
- isDraggingDesign: false,
- };
- },
- computed: {
- discussionStartingNotes() {
- return this.discussions.map(discussion => ({
- ...discussion.notes[0],
- index: discussion.index,
- }));
- },
- currentCommentForm() {
- return (this.isAnnotating && this.currentAnnotationPosition) || null;
- },
- presentationStyle() {
- return {
- cursor: this.isDraggingDesign ? 'grabbing' : undefined,
- };
- },
- },
- beforeDestroy() {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return;
-
- presentationViewport.removeEventListener('scroll', this.scrollThrottled, false);
- },
- mounted() {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return;
-
- this.scrollThrottled = throttle(() => {
- this.shiftZoomFocalPoint();
- }, 400);
-
- presentationViewport.addEventListener('scroll', this.scrollThrottled, false);
- },
- methods: {
- syncCurrentAnnotationPosition() {
- if (!this.currentAnnotationPosition) return;
-
- const widthRatio = this.overlayDimensions.width / this.currentAnnotationPosition.width;
- const heightRatio = this.overlayDimensions.height / this.currentAnnotationPosition.height;
- const x = this.currentAnnotationPosition.x * widthRatio;
- const y = this.currentAnnotationPosition.y * heightRatio;
-
- this.currentAnnotationPosition = this.getAnnotationPositon({ x, y });
- },
- setOverlayDimensions(overlayDimensions) {
- this.overlayDimensions = overlayDimensions;
-
- // every time we set overlay dimensions, we need to
- // update the current annotation as well
- this.syncCurrentAnnotationPosition();
- },
- setOverlayPosition() {
- if (!this.overlayDimensions) {
- this.overlayPosition = {};
- }
-
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return;
-
- // default to center
- this.overlayPosition = {
- left: `calc(50% - ${this.overlayDimensions.width / 2}px)`,
- top: `calc(50% - ${this.overlayDimensions.height / 2}px)`,
- };
-
- // if the overlay overflows, then don't center
- if (this.overlayDimensions.width > presentationViewport.offsetWidth) {
- this.overlayPosition.left = '0';
- }
- if (this.overlayDimensions.height > presentationViewport.offsetHeight) {
- this.overlayPosition.top = '0';
- }
- },
- /**
- * Return a point that represents the center of an
- * overflowing child element w.r.t it's parent
- */
- getViewportCenter() {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return {};
-
- // get height of scroll bars (i.e. the max values for scrollTop, scrollLeft)
- const scrollBarWidth = presentationViewport.scrollWidth - presentationViewport.offsetWidth;
- const scrollBarHeight = presentationViewport.scrollHeight - presentationViewport.offsetHeight;
-
- // determine how many child pixels have been scrolled
- const xScrollRatio =
- presentationViewport.scrollLeft > 0 ? presentationViewport.scrollLeft / scrollBarWidth : 0;
- const yScrollRatio =
- presentationViewport.scrollTop > 0 ? presentationViewport.scrollTop / scrollBarHeight : 0;
- const xScrollOffset =
- (presentationViewport.scrollWidth - presentationViewport.offsetWidth - 0) * xScrollRatio;
- const yScrollOffset =
- (presentationViewport.scrollHeight - presentationViewport.offsetHeight - 0) * yScrollRatio;
-
- const viewportCenterX = presentationViewport.offsetWidth / 2;
- const viewportCenterY = presentationViewport.offsetHeight / 2;
- const focalPointX = viewportCenterX + xScrollOffset;
- const focalPointY = viewportCenterY + yScrollOffset;
-
- return {
- x: focalPointX,
- y: focalPointY,
- };
- },
- /**
- * Scroll the viewport such that the focal point is positioned centrally
- */
- scrollToFocalPoint() {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return;
-
- const scrollX = this.zoomFocalPoint.x - presentationViewport.offsetWidth / 2;
- const scrollY = this.zoomFocalPoint.y - presentationViewport.offsetHeight / 2;
-
- presentationViewport.scrollTo(scrollX, scrollY);
- },
- scaleZoomFocalPoint() {
- const { x, y, width, height } = this.zoomFocalPoint;
- const widthRatio = this.overlayDimensions.width / width;
- const heightRatio = this.overlayDimensions.height / height;
-
- this.zoomFocalPoint = {
- x: Math.round(x * widthRatio * 100) / 100,
- y: Math.round(y * heightRatio * 100) / 100,
- ...this.overlayDimensions,
- };
- },
- shiftZoomFocalPoint() {
- this.zoomFocalPoint = {
- ...this.getViewportCenter(),
- ...this.overlayDimensions,
- };
- },
- onImageResize(imageDimensions) {
- this.setOverlayDimensions(imageDimensions);
- this.setOverlayPosition();
-
- this.$nextTick(() => {
- if (this.initialLoad) {
- // set focal point on initial load
- this.shiftZoomFocalPoint();
- this.initialLoad = false;
- } else {
- this.scaleZoomFocalPoint();
- this.scrollToFocalPoint();
- }
- });
- },
- getAnnotationPositon(coordinates) {
- const { x, y } = coordinates;
- const { width, height } = this.overlayDimensions;
- return {
- x: Math.round(x),
- y: Math.round(y),
- width: Math.round(width),
- height: Math.round(height),
- };
- },
- openCommentForm(coordinates) {
- this.currentAnnotationPosition = this.getAnnotationPositon(coordinates);
- this.$emit('openCommentForm', this.currentAnnotationPosition);
- },
- closeCommentForm() {
- this.currentAnnotationPosition = null;
- this.$emit('closeCommentForm');
- },
- moveNote({ noteId, discussionId, coordinates }) {
- const position = this.getAnnotationPositon(coordinates);
- this.$emit('moveNote', { noteId, discussionId, position });
- },
- onPresentationMousedown({ clientX, clientY }) {
- if (!this.isDesignOverflowing()) return;
-
- this.lastDragPosition = {
- x: clientX,
- y: clientY,
- };
- },
- getDragDelta(clientX, clientY) {
- return {
- deltaX: this.lastDragPosition.x - clientX,
- deltaY: this.lastDragPosition.y - clientY,
- };
- },
- exceedsDragThreshold(clientX, clientY) {
- const { deltaX, deltaY } = this.getDragDelta(clientX, clientY);
-
- return Math.abs(deltaX) > CLICK_DRAG_BUFFER_PX || Math.abs(deltaY) > CLICK_DRAG_BUFFER_PX;
- },
- shouldDragDesign(clientX, clientY) {
- return (
- this.lastDragPosition &&
- (this.isDraggingDesign || this.exceedsDragThreshold(clientX, clientY))
- );
- },
- onPresentationMousemove({ clientX, clientY }) {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport || !this.shouldDragDesign(clientX, clientY)) return;
-
- this.isDraggingDesign = true;
-
- const { scrollLeft, scrollTop } = presentationViewport;
- const { deltaX, deltaY } = this.getDragDelta(clientX, clientY);
- presentationViewport.scrollTo(scrollLeft + deltaX, scrollTop + deltaY);
-
- this.lastDragPosition = {
- x: clientX,
- y: clientY,
- };
- },
- onPresentationMouseup() {
- this.lastDragPosition = null;
- this.isDraggingDesign = false;
- },
- isDesignOverflowing() {
- const { presentationViewport } = this.$refs;
- if (!presentationViewport) return false;
-
- return (
- presentationViewport.scrollWidth > presentationViewport.offsetWidth ||
- presentationViewport.scrollHeight > presentationViewport.offsetHeight
- );
- },
- },
-};
-</script>
-
-<template>
- <div
- ref="presentationViewport"
- class="h-100 w-100 p-3 overflow-auto position-relative"
- :style="presentationStyle"
- @mousedown="onPresentationMousedown"
- @mousemove="onPresentationMousemove"
- @mouseup="onPresentationMouseup"
- @mouseleave="onPresentationMouseup"
- @touchstart="onPresentationMousedown"
- @touchmove="onPresentationMousemove"
- @touchend="onPresentationMouseup"
- @touchcancel="onPresentationMouseup"
- >
- <div class="h-100 w-100 d-flex align-items-center position-relative">
- <design-image
- v-if="image"
- :image="image"
- :name="imageName"
- :scale="scale"
- @resize="onImageResize"
- />
- <design-overlay
- v-if="overlayDimensions && overlayPosition"
- :dimensions="overlayDimensions"
- :position="overlayPosition"
- :notes="discussionStartingNotes"
- :current-comment-form="currentCommentForm"
- :disable-commenting="isDraggingDesign"
- :resolved-discussions-expanded="resolvedDiscussionsExpanded"
- @openCommentForm="openCommentForm"
- @closeCommentForm="closeCommentForm"
- @moveNote="moveNote"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_scaler.vue b/app/assets/javascripts/design_management_legacy/components/design_scaler.vue
deleted file mode 100644
index 55dee74bef5..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_scaler.vue
+++ /dev/null
@@ -1,65 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-
-const SCALE_STEP_SIZE = 0.2;
-const DEFAULT_SCALE = 1;
-const MIN_SCALE = 1;
-const MAX_SCALE = 2;
-
-export default {
- components: {
- GlIcon,
- },
- data() {
- return {
- scale: DEFAULT_SCALE,
- };
- },
- computed: {
- disableReset() {
- return this.scale <= MIN_SCALE;
- },
- disableDecrease() {
- return this.scale === DEFAULT_SCALE;
- },
- disableIncrease() {
- return this.scale >= MAX_SCALE;
- },
- },
- methods: {
- setScale(scale) {
- if (scale < MIN_SCALE) {
- return;
- }
-
- this.scale = Math.round(scale * 100) / 100;
- this.$emit('scale', this.scale);
- },
- incrementScale() {
- this.setScale(this.scale + SCALE_STEP_SIZE);
- },
- decrementScale() {
- this.setScale(this.scale - SCALE_STEP_SIZE);
- },
- resetScale() {
- this.setScale(DEFAULT_SCALE);
- },
- },
-};
-</script>
-
-<template>
- <div class="design-scaler btn-group" role="group">
- <button class="btn" :disabled="disableDecrease" @click="decrementScale">
- <span class="d-flex-center gl-icon s16">
- –
- </span>
- </button>
- <button class="btn" :disabled="disableReset" @click="resetScale">
- <gl-icon name="redo" />
- </button>
- <button class="btn" :disabled="disableIncrease" @click="incrementScale">
- <gl-icon name="plus" />
- </button>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/design_sidebar.vue b/app/assets/javascripts/design_management_legacy/components/design_sidebar.vue
deleted file mode 100644
index 622120e2008..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/design_sidebar.vue
+++ /dev/null
@@ -1,178 +0,0 @@
-<script>
-import Cookies from 'js-cookie';
-import { GlCollapse, GlButton, GlPopover } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import updateActiveDiscussionMutation from '../graphql/mutations/update_active_discussion.mutation.graphql';
-import { extractDiscussions, extractParticipants } from '../utils/design_management_utils';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../constants';
-import DesignDiscussion from './design_notes/design_discussion.vue';
-import Participants from '~/sidebar/components/participants/participants.vue';
-
-export default {
- components: {
- DesignDiscussion,
- Participants,
- GlCollapse,
- GlButton,
- GlPopover,
- },
- props: {
- design: {
- type: Object,
- required: true,
- },
- resolvedDiscussionsExpanded: {
- type: Boolean,
- required: true,
- },
- markdownPreviewPath: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- isResolvedCommentsPopoverHidden: parseBoolean(Cookies.get(this.$options.cookieKey)),
- discussionWithOpenForm: '',
- };
- },
- computed: {
- discussions() {
- return extractDiscussions(this.design.discussions);
- },
- issue() {
- return {
- ...this.design.issue,
- webPath: this.design.issue.webPath.substr(1),
- };
- },
- discussionParticipants() {
- return extractParticipants(this.issue.participants);
- },
- resolvedDiscussions() {
- return this.discussions.filter(discussion => discussion.resolved);
- },
- unresolvedDiscussions() {
- return this.discussions.filter(discussion => !discussion.resolved);
- },
- resolvedCommentsToggleIcon() {
- return this.resolvedDiscussionsExpanded ? 'chevron-down' : 'chevron-right';
- },
- },
- methods: {
- handleSidebarClick() {
- this.isResolvedCommentsPopoverHidden = true;
- Cookies.set(this.$options.cookieKey, 'true', { expires: 365 * 10 });
- this.updateActiveDiscussion();
- },
- updateActiveDiscussion(id) {
- this.$apollo.mutate({
- mutation: updateActiveDiscussionMutation,
- variables: {
- id,
- source: ACTIVE_DISCUSSION_SOURCE_TYPES.discussion,
- },
- });
- },
- closeCommentForm() {
- this.comment = '';
- this.$emit('closeCommentForm');
- },
- updateDiscussionWithOpenForm(id) {
- this.discussionWithOpenForm = id;
- },
- },
- resolveCommentsToggleText: s__('DesignManagement|Resolved Comments'),
- cookieKey: 'hide_design_resolved_comments_popover',
-};
-</script>
-
-<template>
- <div class="image-notes" @click="handleSidebarClick">
- <h2 class="gl-font-weight-bold gl-mt-0">
- {{ issue.title }}
- </h2>
- <a
- class="gl-text-gray-400 gl-text-decoration-none gl-mb-6 gl-display-block"
- :href="issue.webUrl"
- >{{ issue.webPath }}</a
- >
- <participants
- :participants="discussionParticipants"
- :show-participant-label="false"
- class="gl-mb-4"
- />
- <h2
- v-if="unresolvedDiscussions.length === 0"
- class="new-discussion-disclaimer gl-font-base gl-m-0 gl-mb-4"
- data-testid="new-discussion-disclaimer"
- >
- {{ s__("DesignManagement|Click the image where you'd like to start a new discussion") }}
- </h2>
- <design-discussion
- v-for="discussion in unresolvedDiscussions"
- :key="discussion.id"
- :discussion="discussion"
- :design-id="$route.params.id"
- :noteable-id="design.id"
- :markdown-preview-path="markdownPreviewPath"
- :resolved-discussions-expanded="resolvedDiscussionsExpanded"
- :discussion-with-open-form="discussionWithOpenForm"
- data-testid="unresolved-discussion"
- @createNoteError="$emit('onDesignDiscussionError', $event)"
- @updateNoteError="$emit('updateNoteError', $event)"
- @resolveDiscussionError="$emit('resolveDiscussionError', $event)"
- @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
- @openForm="updateDiscussionWithOpenForm"
- />
- <template v-if="resolvedDiscussions.length > 0">
- <gl-button
- id="resolved-comments"
- data-testid="resolved-comments"
- :icon="resolvedCommentsToggleIcon"
- variant="link"
- class="link-inherit-color gl-text-body gl-text-decoration-none gl-font-weight-bold gl-mb-4"
- @click="$emit('toggleResolvedComments')"
- >{{ $options.resolveCommentsToggleText }} ({{ resolvedDiscussions.length }})
- </gl-button>
- <gl-popover
- v-if="!isResolvedCommentsPopoverHidden"
- :show="!isResolvedCommentsPopoverHidden"
- target="resolved-comments"
- container="popovercontainer"
- placement="top"
- :title="s__('DesignManagement|Resolved Comments')"
- >
- <p>
- {{
- s__(
- 'DesignManagement|Comments you resolve can be viewed and unresolved by going to the "Resolved Comments" section below',
- )
- }}
- </p>
- <a href="#" rel="noopener noreferrer" target="_blank">{{
- s__('DesignManagement|Learn more about resolving comments')
- }}</a>
- </gl-popover>
- <gl-collapse :visible="resolvedDiscussionsExpanded" class="gl-mt-3">
- <design-discussion
- v-for="discussion in resolvedDiscussions"
- :key="discussion.id"
- :discussion="discussion"
- :design-id="$route.params.id"
- :noteable-id="design.id"
- :markdown-preview-path="markdownPreviewPath"
- :resolved-discussions-expanded="resolvedDiscussionsExpanded"
- :discussion-with-open-form="discussionWithOpenForm"
- data-testid="resolved-discussion"
- @error="$emit('onDesignDiscussionError', $event)"
- @updateNoteError="$emit('updateNoteError', $event)"
- @openForm="updateDiscussionWithOpenForm"
- @click.native.stop="updateActiveDiscussion(discussion.notes[0].id)"
- />
- </gl-collapse>
- </template>
- <slot name="replyForm"></slot>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/image.vue b/app/assets/javascripts/design_management_legacy/components/image.vue
deleted file mode 100644
index 91b7b576e0c..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/image.vue
+++ /dev/null
@@ -1,110 +0,0 @@
-<script>
-import { throttle } from 'lodash';
-import { GlIcon } from '@gitlab/ui';
-
-export default {
- components: {
- GlIcon,
- },
- props: {
- image: {
- type: String,
- required: false,
- default: '',
- },
- name: {
- type: String,
- required: false,
- default: '',
- },
- scale: {
- type: Number,
- required: false,
- default: 1,
- },
- },
- data() {
- return {
- baseImageSize: null,
- imageStyle: null,
- imageError: false,
- };
- },
- watch: {
- scale(val) {
- this.zoom(val);
- },
- },
- beforeDestroy() {
- window.removeEventListener('resize', this.resizeThrottled, false);
- },
- mounted() {
- this.onImgLoad();
-
- this.resizeThrottled = throttle(() => {
- // NOTE: if imageStyle is set, then baseImageSize
- // won't change due to resize. We must still emit a
- // `resize` event so that the parent can handle
- // resizes appropriately (e.g. for design_overlay)
- this.setBaseImageSize();
- }, 400);
- window.addEventListener('resize', this.resizeThrottled, false);
- },
- methods: {
- onImgLoad() {
- requestIdleCallback(this.setBaseImageSize, { timeout: 1000 });
- },
- onImgError() {
- this.imageError = true;
- },
- setBaseImageSize() {
- const { contentImg } = this.$refs;
- if (!contentImg || contentImg.offsetHeight === 0 || contentImg.offsetWidth === 0) return;
-
- this.baseImageSize = {
- height: contentImg.offsetHeight,
- width: contentImg.offsetWidth,
- };
- this.onResize({ width: this.baseImageSize.width, height: this.baseImageSize.height });
- },
- onResize({ width, height }) {
- this.$emit('resize', { width, height });
- },
- zoom(amount) {
- if (amount === 1) {
- this.imageStyle = null;
- this.$nextTick(() => {
- this.setBaseImageSize();
- });
- return;
- }
- const width = this.baseImageSize.width * amount;
- const height = this.baseImageSize.height * amount;
-
- this.imageStyle = {
- width: `${width}px`,
- height: `${height}px`,
- };
-
- this.onResize({ width, height });
- },
- },
-};
-</script>
-
-<template>
- <div class="m-auto js-design-image">
- <gl-icon v-if="imageError" class="text-secondary-100" name="media-broken" :size="48" />
- <img
- v-show="!imageError"
- ref="contentImg"
- class="mh-100"
- :src="image"
- :alt="name"
- :style="imageStyle"
- :class="{ 'img-fluid': !imageStyle }"
- @error="onImgError"
- @load="onImgLoad"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/list/item.vue b/app/assets/javascripts/design_management_legacy/components/list/item.vue
deleted file mode 100644
index 13c703b8a88..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/list/item.vue
+++ /dev/null
@@ -1,174 +0,0 @@
-<script>
-import { GlLoadingIcon, GlIcon, GlIntersectionObserver } from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
-import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
-import { n__, __ } from '~/locale';
-import { DESIGN_ROUTE_NAME } from '../../router/constants';
-
-export default {
- components: {
- GlLoadingIcon,
- GlIntersectionObserver,
- GlIcon,
- Icon,
- Timeago,
- },
- props: {
- id: {
- type: [Number, String],
- required: true,
- },
- event: {
- type: String,
- required: true,
- },
- notesCount: {
- type: Number,
- required: true,
- },
- image: {
- type: String,
- required: true,
- },
- filename: {
- type: String,
- required: true,
- },
- updatedAt: {
- type: String,
- required: false,
- default: null,
- },
- isUploading: {
- type: Boolean,
- required: false,
- default: true,
- },
- imageV432x230: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- imageLoading: true,
- imageError: false,
- wasInView: false,
- };
- },
- computed: {
- icon() {
- const normalizedEvent = this.event.toLowerCase();
- const icons = {
- creation: {
- name: 'file-addition-solid',
- classes: 'text-success-500',
- tooltip: __('Added in this version'),
- },
- modification: {
- name: 'file-modified-solid',
- classes: 'text-primary-500',
- tooltip: __('Modified in this version'),
- },
- deletion: {
- name: 'file-deletion-solid',
- classes: 'text-danger-500',
- tooltip: __('Deleted in this version'),
- },
- };
-
- return icons[normalizedEvent] ? icons[normalizedEvent] : {};
- },
- notesLabel() {
- return n__('%d comment', '%d comments', this.notesCount);
- },
- imageLink() {
- return this.wasInView ? this.imageV432x230 || this.image : '';
- },
- showLoadingSpinner() {
- return this.imageLoading || this.isUploading;
- },
- showImageErrorIcon() {
- return this.wasInView && this.imageError;
- },
- showImage() {
- return !this.showLoadingSpinner && !this.showImageErrorIcon;
- },
- },
- methods: {
- onImageLoad() {
- this.imageLoading = false;
- this.imageError = false;
- },
- onImageError() {
- this.imageLoading = false;
- this.imageError = true;
- },
- onAppear() {
- // do nothing if image has previously
- // been in view
- if (this.wasInView) {
- return;
- }
-
- this.wasInView = true;
- this.imageLoading = true;
- },
- },
- DESIGN_ROUTE_NAME,
-};
-</script>
-
-<template>
- <router-link
- :to="{
- name: $options.DESIGN_ROUTE_NAME,
- params: { id: filename },
- query: $route.query,
- }"
- class="card cursor-pointer text-plain js-design-list-item design-list-item"
- >
- <div class="card-body p-0 d-flex-center overflow-hidden position-relative">
- <div v-if="icon.name" data-testid="designEvent" class="design-event position-absolute">
- <span :title="icon.tooltip" :aria-label="icon.tooltip">
- <icon :name="icon.name" :size="18" :class="icon.classes" />
- </span>
- </div>
- <gl-intersection-observer @appear="onAppear">
- <gl-loading-icon v-if="showLoadingSpinner" size="md" />
- <gl-icon
- v-else-if="showImageErrorIcon"
- name="media-broken"
- class="text-secondary"
- :size="32"
- />
- <img
- v-show="showImage"
- :src="imageLink"
- :alt="filename"
- class="block mx-auto mw-100 mh-100 design-img"
- data-qa-selector="design_image"
- @load="onImageLoad"
- @error="onImageError"
- />
- </gl-intersection-observer>
- </div>
- <div class="card-footer d-flex w-100">
- <div class="d-flex flex-column str-truncated-100">
- <span class="bold str-truncated-100" data-qa-selector="design_file_name">{{
- filename
- }}</span>
- <span v-if="updatedAt" class="str-truncated-100">
- {{ __('Updated') }} <timeago :time="updatedAt" tooltip-placement="bottom" />
- </span>
- </div>
- <div v-if="notesCount" class="ml-auto d-flex align-items-center text-secondary">
- <icon name="comments" class="ml-1" />
- <span :aria-label="notesLabel" class="ml-1">
- {{ notesCount }}
- </span>
- </div>
- </div>
- </router-link>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/toolbar/index.vue b/app/assets/javascripts/design_management_legacy/components/toolbar/index.vue
deleted file mode 100644
index b998dfc47b8..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/toolbar/index.vue
+++ /dev/null
@@ -1,126 +0,0 @@
-<script>
-import { GlDeprecatedButton } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-import Icon from '~/vue_shared/components/icon.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import Pagination from './pagination.vue';
-import DeleteButton from '../delete_button.vue';
-import permissionsQuery from '../../graphql/queries/design_permissions.query.graphql';
-import appDataQuery from '../../graphql/queries/app_data.query.graphql';
-import { DESIGNS_ROUTE_NAME } from '../../router/constants';
-
-export default {
- components: {
- Icon,
- Pagination,
- DeleteButton,
- GlDeprecatedButton,
- },
- mixins: [timeagoMixin],
- props: {
- id: {
- type: String,
- required: true,
- },
- isDeleting: {
- type: Boolean,
- required: true,
- },
- filename: {
- type: String,
- required: false,
- default: '',
- },
- updatedAt: {
- type: String,
- required: false,
- default: null,
- },
- updatedBy: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- isLatestVersion: {
- type: Boolean,
- required: true,
- },
- image: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- permissions: {
- createDesign: false,
- },
- projectPath: '',
- issueIid: null,
- };
- },
- apollo: {
- appData: {
- query: appDataQuery,
- manual: true,
- result({ data: { projectPath, issueIid } }) {
- this.projectPath = projectPath;
- this.issueIid = issueIid;
- },
- },
- permissions: {
- query: permissionsQuery,
- variables() {
- return {
- fullPath: this.projectPath,
- iid: this.issueIid,
- };
- },
- update: data => data.project.issue.userPermissions,
- },
- },
- computed: {
- updatedText() {
- return sprintf(__('Updated %{updated_at} by %{updated_by}'), {
- updated_at: this.timeFormatted(this.updatedAt),
- updated_by: this.updatedBy.name,
- });
- },
- canDeleteDesign() {
- return this.permissions.createDesign;
- },
- },
- DESIGNS_ROUTE_NAME,
-};
-</script>
-
-<template>
- <header class="d-flex p-2 bg-white align-items-center js-design-header">
- <router-link
- :to="{
- name: $options.DESIGNS_ROUTE_NAME,
- query: $route.query,
- }"
- :aria-label="s__('DesignManagement|Go back to designs')"
- class="mr-3 text-plain d-flex justify-content-center align-items-center"
- >
- <icon :size="18" name="close" />
- </router-link>
- <div class="overflow-hidden d-flex align-items-center">
- <h2 class="m-0 str-truncated-100 gl-font-base">{{ filename }}</h2>
- <small v-if="updatedAt" class="text-secondary">{{ updatedText }}</small>
- </div>
- <pagination :id="id" class="ml-auto flex-shrink-0" />
- <gl-deprecated-button :href="image" class="mr-2">
- <icon :size="18" name="download" />
- </gl-deprecated-button>
- <delete-button
- v-if="isLatestVersion && canDeleteDesign"
- :is-deleting="isDeleting"
- button-variant="danger"
- @deleteSelectedDesigns="$emit('delete')"
- >
- <icon :size="18" name="remove" />
- </delete-button>
- </header>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/toolbar/pagination.vue b/app/assets/javascripts/design_management_legacy/components/toolbar/pagination.vue
deleted file mode 100644
index bf62a8f66a6..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/toolbar/pagination.vue
+++ /dev/null
@@ -1,83 +0,0 @@
-<script>
-/* global Mousetrap */
-import 'mousetrap';
-import { s__, sprintf } from '~/locale';
-import PaginationButton from './pagination_button.vue';
-import allDesignsMixin from '../../mixins/all_designs';
-import { DESIGN_ROUTE_NAME } from '../../router/constants';
-
-export default {
- components: {
- PaginationButton,
- },
- mixins: [allDesignsMixin],
- props: {
- id: {
- type: String,
- required: true,
- },
- },
- computed: {
- designsCount() {
- return this.designs.length;
- },
- currentIndex() {
- return this.designs.findIndex(design => design.filename === this.id);
- },
- paginationText() {
- return sprintf(s__('DesignManagement|%{current_design} of %{designs_count}'), {
- current_design: this.currentIndex + 1,
- designs_count: this.designsCount,
- });
- },
- previousDesign() {
- if (!this.designsCount) return null;
-
- return this.designs[this.currentIndex - 1];
- },
- nextDesign() {
- if (!this.designsCount) return null;
-
- return this.designs[this.currentIndex + 1];
- },
- },
- mounted() {
- Mousetrap.bind('left', () => this.navigateToDesign(this.previousDesign));
- Mousetrap.bind('right', () => this.navigateToDesign(this.nextDesign));
- },
- beforeDestroy() {
- Mousetrap.unbind(['left', 'right'], this.navigateToDesign);
- },
- methods: {
- navigateToDesign(design) {
- if (design) {
- this.$router.push({
- name: DESIGN_ROUTE_NAME,
- params: { id: design.filename },
- query: this.$route.query,
- });
- }
- },
- },
-};
-</script>
-
-<template>
- <div v-if="designsCount" class="d-flex align-items-center">
- {{ paginationText }}
- <div class="btn-group ml-3 mr-3">
- <pagination-button
- :design="previousDesign"
- :title="s__('DesignManagement|Go to previous design')"
- icon-name="angle-left"
- class="js-previous-design"
- />
- <pagination-button
- :design="nextDesign"
- :title="s__('DesignManagement|Go to next design')"
- icon-name="angle-right"
- class="js-next-design"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/toolbar/pagination_button.vue b/app/assets/javascripts/design_management_legacy/components/toolbar/pagination_button.vue
deleted file mode 100644
index f00ecefca01..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/toolbar/pagination_button.vue
+++ /dev/null
@@ -1,48 +0,0 @@
-<script>
-import Icon from '~/vue_shared/components/icon.vue';
-import { DESIGN_ROUTE_NAME } from '../../router/constants';
-
-export default {
- components: {
- Icon,
- },
- props: {
- design: {
- type: Object,
- required: false,
- default: null,
- },
- title: {
- type: String,
- required: true,
- },
- iconName: {
- type: String,
- required: true,
- },
- },
- computed: {
- designLink() {
- if (!this.design) return {};
-
- return {
- name: DESIGN_ROUTE_NAME,
- params: { id: this.design.filename },
- query: this.$route.query,
- };
- },
- },
-};
-</script>
-
-<template>
- <router-link
- :to="designLink"
- :disabled="!design"
- :class="{ disabled: !design }"
- :aria-label="title"
- class="btn btn-default"
- >
- <icon :name="iconName" />
- </router-link>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/upload/button.vue b/app/assets/javascripts/design_management_legacy/components/upload/button.vue
deleted file mode 100644
index 68555104a3c..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/upload/button.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import { GlDeprecatedButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
-import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
-
-export default {
- components: {
- GlDeprecatedButton,
- GlLoadingIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- isSaving: {
- type: Boolean,
- required: true,
- },
- },
- methods: {
- openFileUpload() {
- this.$refs.fileUpload.click();
- },
- onFileUploadChange(e) {
- this.$emit('upload', e.target.files);
- },
- },
- VALID_DESIGN_FILE_MIMETYPE,
-};
-</script>
-
-<template>
- <div>
- <gl-deprecated-button
- v-gl-tooltip.hover
- :title="
- s__(
- 'DesignManagement|Adding a design with the same filename replaces the file in a new version.',
- )
- "
- :disabled="isSaving"
- variant="success"
- @click="openFileUpload"
- >
- {{ s__('DesignManagement|Upload designs') }}
- <gl-loading-icon v-if="isSaving" inline class="ml-1" />
- </gl-deprecated-button>
-
- <input
- ref="fileUpload"
- type="file"
- name="design_file"
- :accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
- class="hide"
- multiple
- @change="onFileUploadChange"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/upload/design_dropzone.vue b/app/assets/javascripts/design_management_legacy/components/upload/design_dropzone.vue
deleted file mode 100644
index e435c84c959..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/upload/design_dropzone.vue
+++ /dev/null
@@ -1,134 +0,0 @@
-<script>
-import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
-import uploadDesignMutation from '../../graphql/mutations/upload_design.mutation.graphql';
-import { UPLOAD_DESIGN_INVALID_FILETYPE_ERROR } from '../../utils/error_messages';
-import { isValidDesignFile } from '../../utils/design_management_utils';
-import { VALID_DATA_TRANSFER_TYPE, VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
-
-export default {
- components: {
- GlIcon,
- GlLink,
- GlSprintf,
- },
- data() {
- return {
- dragCounter: 0,
- isDragDataValid: false,
- };
- },
- computed: {
- dragging() {
- return this.dragCounter !== 0;
- },
- },
- methods: {
- isValidUpload(files) {
- return files.every(isValidDesignFile);
- },
- isValidDragDataType({ dataTransfer }) {
- return Boolean(dataTransfer && dataTransfer.types.some(t => t === VALID_DATA_TRANSFER_TYPE));
- },
- ondrop({ dataTransfer = {} }) {
- this.dragCounter = 0;
- // User already had feedback when dropzone was active, so bail here
- if (!this.isDragDataValid) {
- return;
- }
-
- const { files } = dataTransfer;
- if (!this.isValidUpload(Array.from(files))) {
- createFlash(UPLOAD_DESIGN_INVALID_FILETYPE_ERROR);
- return;
- }
-
- this.$emit('change', files);
- },
- ondragenter(e) {
- this.dragCounter += 1;
- this.isDragDataValid = this.isValidDragDataType(e);
- },
- ondragleave() {
- this.dragCounter -= 1;
- },
- openFileUpload() {
- this.$refs.fileUpload.click();
- },
- onDesignInputChange(e) {
- this.$emit('change', e.target.files);
- },
- },
- uploadDesignMutation,
- VALID_DESIGN_FILE_MIMETYPE,
-};
-</script>
-
-<template>
- <div
- class="w-100 position-relative"
- @dragstart.prevent.stop
- @dragend.prevent.stop
- @dragover.prevent.stop
- @dragenter.prevent.stop="ondragenter"
- @dragleave.prevent.stop="ondragleave"
- @drop.prevent.stop="ondrop"
- >
- <slot>
- <button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
- @click="openFileUpload"
- >
- <div class="d-flex-center flex-column text-center">
- <gl-icon name="doc-new" :size="48" class="mb-4" />
- <p>
- <gl-sprintf
- :message="
- __(
- '%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}.',
- )
- "
- >
- <template #lineOne="{ content }"
- ><span class="d-block">{{ content }}</span>
- </template>
-
- <template #link="{ content }">
- <gl-link class="h-100 w-100" @click.stop="openFileUpload">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </div>
- </button>
-
- <input
- ref="fileUpload"
- type="file"
- name="design_file"
- :accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
- class="hide"
- multiple
- @change="onDesignInputChange"
- />
- </slot>
- <transition name="design-dropzone-fade">
- <div
- v-show="dragging"
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
- >
- <div v-show="!isDragDataValid" class="mw-50 text-center">
- <h3>{{ __('Oh no!') }}</h3>
- <span>{{
- __(
- 'You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.',
- )
- }}</span>
- </div>
- <div v-show="isDragDataValid" class="mw-50 text-center">
- <h3>{{ __('Incoming!') }}</h3>
- <span>{{ __('Drop your designs to start your upload.') }}</span>
- </div>
- </div>
- </transition>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management_legacy/components/upload/design_version_dropdown.vue b/app/assets/javascripts/design_management_legacy/components/upload/design_version_dropdown.vue
deleted file mode 100644
index 879d2523848..00000000000
--- a/app/assets/javascripts/design_management_legacy/components/upload/design_version_dropdown.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-<script>
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-import allVersionsMixin from '../../mixins/all_versions';
-import { findVersionId } from '../../utils/design_management_utils';
-
-export default {
- components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- },
- mixins: [allVersionsMixin],
- computed: {
- queryVersion() {
- return this.$route.query.version;
- },
- currentVersionIdx() {
- if (!this.queryVersion) return 0;
-
- const idx = this.allVersions.findIndex(
- version => this.findVersionId(version.node.id) === this.queryVersion,
- );
-
- // if the currentVersionId isn't a valid version (i.e. not in allVersions)
- // then return the latest version (index 0)
- return idx !== -1 ? idx : 0;
- },
- currentVersionId() {
- if (this.queryVersion) return this.queryVersion;
-
- const currentVersion = this.allVersions[this.currentVersionIdx];
- return this.findVersionId(currentVersion.node.id);
- },
- dropdownText() {
- if (this.isLatestVersion) {
- return __('Showing Latest Version');
- }
- // allVersions is sorted in reverse chronological order (latest first)
- const currentVersionNumber = this.allVersions.length - this.currentVersionIdx;
-
- return sprintf(__('Showing Version #%{versionNumber}'), {
- versionNumber: currentVersionNumber,
- });
- },
- },
- methods: {
- findVersionId,
- },
-};
-</script>
-
-<template>
- <gl-deprecated-dropdown :text="dropdownText" variant="link" class="design-version-dropdown">
- <gl-deprecated-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
- <router-link
- class="d-flex js-version-link"
- :to="{ path: $route.path, query: { version: findVersionId(version.node.id) } }"
- >
- <div class="flex-grow-1 ml-2">
- <div>
- <strong
- >{{ __('Version') }} {{ allVersions.length - index }}
- <span v-if="findVersionId(version.node.id) === latestVersionId"
- >({{ __('latest') }})</span
- >
- </strong>
- </div>
- </div>
- <i
- v-if="findVersionId(version.node.id) === currentVersionId"
- class="fa fa-check float-right gl-mr-2"
- ></i>
- </router-link>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
-</template>