summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/design_management
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/design_management')
-rw-r--r--app/assets/javascripts/design_management/components/design_destroyer.vue2
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_discussion.vue6
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_note.vue4
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue2
-rw-r--r--app/assets/javascripts/design_management/components/design_overlay.vue4
-rw-r--r--app/assets/javascripts/design_management/components/design_scaler.vue23
-rw-r--r--app/assets/javascripts/design_management/components/design_sidebar.vue2
-rw-r--r--app/assets/javascripts/design_management/components/toolbar/design_navigation.vue7
-rw-r--r--app/assets/javascripts/design_management/components/toolbar/index.vue16
-rw-r--r--app/assets/javascripts/design_management/components/upload/button.vue5
-rw-r--r--app/assets/javascripts/design_management/components/upload/design_dropzone.vue147
-rw-r--r--app/assets/javascripts/design_management/constants.js3
-rw-r--r--app/assets/javascripts/design_management/graphql/fragments/note_permissions.fragment.graphql1
-rw-r--r--app/assets/javascripts/design_management/graphql/mutations/reposition_image_diff_note.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management/graphql/mutations/update_image_diff_note.mutation.graphql10
-rw-r--r--app/assets/javascripts/design_management/graphql/queries/design_permissions.query.graphql10
-rw-r--r--app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql7
-rw-r--r--app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql23
-rw-r--r--app/assets/javascripts/design_management/mixins/all_designs.js18
-rw-r--r--app/assets/javascripts/design_management/mixins/all_versions.js2
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue41
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue91
-rw-r--r--app/assets/javascripts/design_management/router/index.js17
-rw-r--r--app/assets/javascripts/design_management/utils/cache_update.js14
-rw-r--r--app/assets/javascripts/design_management/utils/design_management_utils.js6
25 files changed, 174 insertions, 297 deletions
diff --git a/app/assets/javascripts/design_management/components/design_destroyer.vue b/app/assets/javascripts/design_management/components/design_destroyer.vue
index 7ae569216f0..5d32bfd4a73 100644
--- a/app/assets/javascripts/design_management/components/design_destroyer.vue
+++ b/app/assets/javascripts/design_management/components/design_destroyer.vue
@@ -1,6 +1,6 @@
<script>
import { ApolloMutation } from 'vue-apollo';
-import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
import destroyDesignMutation from '../graphql/mutations/destroy_design.mutation.graphql';
import { updateStoreAfterDesignsDelete } from '../utils/cache_update';
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue b/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
index 845f1aec8cf..6aab4bf423e 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_discussion.vue
@@ -210,7 +210,7 @@ export default {
:class="{ 'gl-bg-blue-50': isDiscussionActive }"
@error="$emit('update-note-error', $event)"
>
- <template v-if="discussion.resolvable" #resolveDiscussion>
+ <template v-if="discussion.resolvable" #resolve-discussion>
<button
v-gl-tooltip
:class="{ 'is-active': discussion.resolved }"
@@ -224,7 +224,7 @@ export default {
<gl-loading-icon v-else inline />
</button>
</template>
- <template v-if="discussion.resolved" #resolvedStatus>
+ <template v-if="discussion.resolved" #resolved-status>
<p class="gl-text-gray-500 gl-font-sm gl-m-0 gl-mt-5" data-testid="resolved-message">
{{ __('Resolved by') }}
<gl-link
@@ -277,7 +277,7 @@ export default {
@submit-form="mutate"
@cancel-form="hideForm"
>
- <template v-if="discussion.resolvable" #resolveCheckbox>
+ <template v-if="discussion.resolvable" #resolve-checkbox>
<label data-testid="resolve-checkbox">
<input v-model="shouldChangeResolvedStatus" type="checkbox" />
{{ resolveCheckboxText }}
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_note.vue b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
index 7f4b3b31024..421a4dc274a 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_note.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
@@ -108,7 +108,7 @@ export default {
</span>
</div>
<div class="gl-display-flex gl-align-items-baseline">
- <slot name="resolveDiscussion"></slot>
+ <slot name="resolve-discussion"></slot>
<button
v-if="isEditButtonVisible"
v-gl-tooltip
@@ -127,7 +127,7 @@ export default {
class="note-text js-note-text md"
data-qa-selector="note_content"
></div>
- <slot name="resolvedStatus"></slot>
+ <slot name="resolved-status"></slot>
</template>
<apollo-mutation
v-else
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue b/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
index 3754e1dbbc1..7aaac58a1ce 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_reply_form.vue
@@ -110,7 +110,7 @@ export default {
</textarea>
</template>
</markdown-field>
- <slot name="resolveCheckbox"></slot>
+ <slot name="resolve-checkbox"></slot>
<div class="note-form-actions gl-display-flex gl-justify-content-space-between">
<gl-button
ref="submitButton"
diff --git a/app/assets/javascripts/design_management/components/design_overlay.vue b/app/assets/javascripts/design_management/components/design_overlay.vue
index 88f3ce0b8ea..3c2ce693bc0 100644
--- a/app/assets/javascripts/design_management/components/design_overlay.vue
+++ b/app/assets/javascripts/design_management/components/design_overlay.vue
@@ -112,9 +112,9 @@ export default {
},
canMoveNote(note) {
const { userPermissions } = note;
- const { adminNote } = userPermissions || {};
+ const { repositionNote } = userPermissions || {};
- return Boolean(adminNote);
+ return Boolean(repositionNote);
},
isPositionInOverlay(position) {
const { top, left } = this.getNoteRelativePosition(position);
diff --git a/app/assets/javascripts/design_management/components/design_scaler.vue b/app/assets/javascripts/design_management/components/design_scaler.vue
index 8d26f84641e..85c6bd4d79e 100644
--- a/app/assets/javascripts/design_management/components/design_scaler.vue
+++ b/app/assets/javascripts/design_management/components/design_scaler.vue
@@ -1,5 +1,5 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlButtonGroup, GlButton } from '@gitlab/ui';
const SCALE_STEP_SIZE = 0.2;
const DEFAULT_SCALE = 1;
@@ -8,7 +8,8 @@ const MAX_SCALE = 2;
export default {
components: {
- GlIcon,
+ GlButtonGroup,
+ GlButton,
},
data() {
return {
@@ -49,17 +50,9 @@ export default {
</script>
<template>
- <div class="design-scaler btn-group" role="group">
- <button class="btn" :disabled="disableDecrease" @click="decrementScale">
- <span class="gl-display-flex gl-justify-content-center gl-align-items-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>
+ <gl-button-group class="gl-z-index-1">
+ <gl-button icon="dash" :disabled="disableDecrease" @click="decrementScale" />
+ <gl-button icon="redo" :disabled="disableReset" @click="resetScale" />
+ <gl-button icon="plus" :disabled="disableIncrease" @click="incrementScale" />
+ </gl-button-group>
</template>
diff --git a/app/assets/javascripts/design_management/components/design_sidebar.vue b/app/assets/javascripts/design_management/components/design_sidebar.vue
index fb8e74c8c4c..41dcec38abe 100644
--- a/app/assets/javascripts/design_management/components/design_sidebar.vue
+++ b/app/assets/javascripts/design_management/components/design_sidebar.vue
@@ -207,6 +207,6 @@ export default {
/>
</gl-collapse>
</template>
- <slot name="replyForm"></slot>
+ <slot name="reply-form"></slot>
</div>
</template>
diff --git a/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue b/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
index 2719d701c12..4edc2e410c7 100644
--- a/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
+++ b/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
@@ -1,7 +1,7 @@
<script>
/* global Mousetrap */
import 'mousetrap';
-import { GlButton, GlButtonGroup } from '@gitlab/ui';
+import { GlButton, GlButtonGroup, GlTooltipDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import allDesignsMixin from '../../mixins/all_designs';
import { DESIGN_ROUTE_NAME } from '../../router/constants';
@@ -11,6 +11,9 @@ export default {
GlButton,
GlButtonGroup,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
mixins: [allDesignsMixin],
props: {
id: {
@@ -68,6 +71,7 @@ export default {
{{ paginationText }}
<gl-button-group class="gl-mx-5">
<gl-button
+ v-gl-tooltip.bottom
:disabled="!previousDesign"
:title="s__('DesignManagement|Go to previous design')"
icon="angle-left"
@@ -75,6 +79,7 @@ export default {
@click="navigateToDesign(previousDesign)"
/>
<gl-button
+ v-gl-tooltip.bottom
:disabled="!nextDesign"
:title="s__('DesignManagement|Go to next design')"
icon="angle-right"
diff --git a/app/assets/javascripts/design_management/components/toolbar/index.vue b/app/assets/javascripts/design_management/components/toolbar/index.vue
index 8d25d467d59..4caee863df8 100644
--- a/app/assets/javascripts/design_management/components/toolbar/index.vue
+++ b/app/assets/javascripts/design_management/components/toolbar/index.vue
@@ -1,10 +1,10 @@
<script>
-import { GlButton, GlIcon } from '@gitlab/ui';
+import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
import { __, sprintf } from '~/locale';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import DesignNavigation from './design_navigation.vue';
import DeleteButton from '../delete_button.vue';
-import permissionsQuery from '../../graphql/queries/design_permissions.query.graphql';
import { DESIGNS_ROUTE_NAME } from '../../router/constants';
export default {
@@ -14,6 +14,9 @@ export default {
DesignNavigation,
DeleteButton,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
mixins: [timeagoMixin],
props: {
id: {
@@ -112,14 +115,21 @@ export default {
</div>
</div>
<design-navigation :id="id" class="gl-ml-auto gl-flex-shrink-0" />
- <gl-button :href="image" icon="download" />
+ <gl-button
+ v-gl-tooltip.bottom
+ :href="image"
+ icon="download"
+ :title="s__('DesignManagement|Download design')"
+ />
<delete-button
v-if="isLatestVersion && canDeleteDesign"
+ v-gl-tooltip.bottom
class="gl-ml-3"
:is-deleting="isDeleting"
button-variant="warning"
button-icon="archive"
button-category="secondary"
+ :title="s__('DesignManagement|Archive design')"
@deleteSelectedDesigns="$emit('delete')"
/>
</header>
diff --git a/app/assets/javascripts/design_management/components/upload/button.vue b/app/assets/javascripts/design_management/components/upload/button.vue
index c76041c74a8..d7b287f663b 100644
--- a/app/assets/javascripts/design_management/components/upload/button.vue
+++ b/app/assets/javascripts/design_management/components/upload/button.vue
@@ -1,11 +1,10 @@
<script>
-import { GlButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
export default {
components: {
GlButton,
- GlLoadingIcon,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -38,12 +37,12 @@ export default {
)
"
:disabled="isSaving"
+ :loading="isSaving"
variant="default"
size="small"
@click="openFileUpload"
>
{{ s__('DesignManagement|Upload designs') }}
- <gl-loading-icon v-if="isSaving" inline class="ml-1" />
</gl-button>
<input
diff --git a/app/assets/javascripts/design_management/components/upload/design_dropzone.vue b/app/assets/javascripts/design_management/components/upload/design_dropzone.vue
deleted file mode 100644
index 6694b0dab8d..00000000000
--- a/app/assets/javascripts/design_management/components/upload/design_dropzone.vue
+++ /dev/null
@@ -1,147 +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,
- },
- props: {
- hasDesigns: {
- type: Boolean,
- required: true,
- },
- isDraggingDesign: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- dragCounter: 0,
- isDragDataValid: false,
- };
- },
- computed: {
- dragging() {
- return this.dragCounter !== 0;
- },
- iconStyles() {
- return {
- size: this.hasDesigns ? 24 : 16,
- class: this.hasDesigns ? 'gl-mb-2' : 'gl-mr-3 gl-text-gray-500',
- };
- },
- },
- 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="gl-w-full gl-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 gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
- @click="openFileUpload"
- >
- <div
- :class="{ 'gl-flex-direction-column': hasDesigns }"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center"
- data-testid="dropzone-area"
- >
- <gl-icon name="upload" :size="iconStyles.size" :class="iconStyles.class" />
- <p class="gl-mb-0">
- <gl-sprintf :message="__('Drop or %{linkStart}upload%{linkEnd} designs to attach')">
- <template #link="{ content }">
- <gl-link @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 && !isDraggingDesign"
- class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
- >
- <div v-show="!isDragDataValid" class="mw-50 gl-text-center">
- <h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('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 gl-text-center">
- <h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('Incoming!') }}</h3>
- <span>{{ __('Drop your designs to start your upload.') }}</span>
- </div>
- </div>
- </transition>
- </div>
-</template>
diff --git a/app/assets/javascripts/design_management/constants.js b/app/assets/javascripts/design_management/constants.js
index 63a92ef5ec0..92928ca429f 100644
--- a/app/assets/javascripts/design_management/constants.js
+++ b/app/assets/javascripts/design_management/constants.js
@@ -5,9 +5,6 @@ export const VALID_DESIGN_FILE_MIMETYPE = {
regex: /image\/.+/,
};
-// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
-export const VALID_DATA_TRANSFER_TYPE = 'Files';
-
export const ACTIVE_DISCUSSION_SOURCE_TYPES = {
pin: 'pin',
discussion: 'discussion',
diff --git a/app/assets/javascripts/design_management/graphql/fragments/note_permissions.fragment.graphql b/app/assets/javascripts/design_management/graphql/fragments/note_permissions.fragment.graphql
index c243e39f3d3..e599ab19c2d 100644
--- a/app/assets/javascripts/design_management/graphql/fragments/note_permissions.fragment.graphql
+++ b/app/assets/javascripts/design_management/graphql/fragments/note_permissions.fragment.graphql
@@ -1,3 +1,4 @@
fragment DesignNotePermissions on NotePermissions {
adminNote
+ repositionNote
}
diff --git a/app/assets/javascripts/design_management/graphql/mutations/reposition_image_diff_note.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/reposition_image_diff_note.mutation.graphql
new file mode 100644
index 00000000000..78fbcf1c3c7
--- /dev/null
+++ b/app/assets/javascripts/design_management/graphql/mutations/reposition_image_diff_note.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/design_note.fragment.graphql"
+
+mutation repositionImageDiffNote($input: RepositionImageDiffNoteInput!) {
+ repositionImageDiffNote(input: $input) {
+ errors
+ note {
+ ...DesignNote
+ }
+ }
+}
diff --git a/app/assets/javascripts/design_management/graphql/mutations/update_image_diff_note.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/update_image_diff_note.mutation.graphql
deleted file mode 100644
index 5562ca9d89f..00000000000
--- a/app/assets/javascripts/design_management/graphql/mutations/update_image_diff_note.mutation.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "../fragments/design_note.fragment.graphql"
-
-mutation updateImageDiffNote($input: UpdateImageDiffNoteInput!) {
- updateImageDiffNote(input: $input) {
- errors
- note {
- ...DesignNote
- }
- }
-}
diff --git a/app/assets/javascripts/design_management/graphql/queries/design_permissions.query.graphql b/app/assets/javascripts/design_management/graphql/queries/design_permissions.query.graphql
deleted file mode 100644
index a87b256dc95..00000000000
--- a/app/assets/javascripts/design_management/graphql/queries/design_permissions.query.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-query permissions($fullPath: ID!, $iid: String!) {
- project(fullPath: $fullPath) {
- id
- issue(iid: $iid) {
- userPermissions {
- createDesign
- }
- }
- }
-}
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 96869a404b1..99a61191c6e 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
@@ -1,7 +1,12 @@
#import "../fragments/design.fragment.graphql"
#import "~/graphql_shared/fragments/author.fragment.graphql"
-query getDesign($fullPath: ID!, $iid: String!, $atVersion: ID, $filenames: [String!]) {
+query getDesign(
+ $fullPath: ID!
+ $iid: String!
+ $atVersion: DesignManagementVersionID
+ $filenames: [String!]
+) {
project(fullPath: $fullPath) {
id
issue(iid: $iid) {
diff --git a/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql b/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql
deleted file mode 100644
index efa61edf51a..00000000000
--- a/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql
+++ /dev/null
@@ -1,23 +0,0 @@
-#import "../fragments/design_list.fragment.graphql"
-#import "../fragments/version.fragment.graphql"
-
-query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) {
- project(fullPath: $fullPath) {
- id
- issue(iid: $iid) {
- designCollection {
- copyState
- designs(atVersion: $atVersion) {
- nodes {
- ...DesignListItem
- }
- }
- versions {
- nodes {
- ...VersionListItem
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/design_management/mixins/all_designs.js b/app/assets/javascripts/design_management/mixins/all_designs.js
index 62bcf216add..466f61e21fa 100644
--- a/app/assets/javascripts/design_management/mixins/all_designs.js
+++ b/app/assets/javascripts/design_management/mixins/all_designs.js
@@ -1,7 +1,7 @@
import { propertyOf } from 'lodash';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
+import createFlash, { FLASH_TYPES } from '~/flash';
import { s__ } from '~/locale';
-import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
import allVersionsMixin from './all_versions';
import { DESIGNS_ROUTE_NAME } from '../router/constants';
@@ -36,20 +36,20 @@ export default {
},
result() {
if (this.$route.query.version && !this.hasValidVersion) {
- createFlash(
- s__(
+ createFlash({
+ message: s__(
'DesignManagement|Requested design version does not exist. Showing latest version instead',
),
- );
+ });
this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
}
if (this.designCollection.copyState === 'ERROR') {
- createFlash(
- s__(
+ createFlash({
+ message: s__(
'DesignManagement|There was an error moving your designs. Please upload your designs below.',
),
- 'warning',
- );
+ type: FLASH_TYPES.WARNING,
+ });
}
},
},
diff --git a/app/assets/javascripts/design_management/mixins/all_versions.js b/app/assets/javascripts/design_management/mixins/all_versions.js
index 7a094f23378..07cd0fc92bd 100644
--- a/app/assets/javascripts/design_management/mixins/all_versions.js
+++ b/app/assets/javascripts/design_management/mixins/all_versions.js
@@ -1,4 +1,4 @@
-import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
+import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
import { findVersionId } from '../utils/design_management_utils';
export default {
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index 6a96b06dcd8..e07279ba39d 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -2,7 +2,7 @@
import Mousetrap from 'mousetrap';
import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { ApolloMutation } from 'vue-apollo';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { fetchPolicies } from '~/lib/graphql';
import allVersionsMixin from '../../mixins/all_versions';
import Toolbar from '../../components/toolbar/index.vue';
@@ -13,18 +13,19 @@ import DesignReplyForm from '../../components/design_notes/design_reply_form.vue
import DesignSidebar from '../../components/design_sidebar.vue';
import getDesignQuery from '../../graphql/queries/get_design.query.graphql';
import createImageDiffNoteMutation from '../../graphql/mutations/create_image_diff_note.mutation.graphql';
-import updateImageDiffNoteMutation from '../../graphql/mutations/update_image_diff_note.mutation.graphql';
+import repositionImageDiffNoteMutation from '../../graphql/mutations/reposition_image_diff_note.mutation.graphql';
import updateActiveDiscussionMutation from '../../graphql/mutations/update_active_discussion.mutation.graphql';
import {
extractDiscussions,
extractDesign,
- updateImageDiffNoteOptimisticResponse,
+ repositionImageDiffNoteOptimisticResponse,
toDiffNoteGid,
extractDesignNoteId,
+ getPageLayoutElement,
} from '../../utils/design_management_utils';
import {
updateStoreAfterAddImageDiffNote,
- updateStoreAfterUpdateImageDiffNote,
+ updateStoreAfterRepositionImageDiffNote,
} from '../../utils/cache_update';
import {
ADD_DISCUSSION_COMMENT_ERROR,
@@ -38,7 +39,7 @@ import {
} from '../../utils/error_messages';
import { trackDesignDetailView } from '../../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../../router/constants';
-import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+import { ACTIVE_DISCUSSION_SOURCE_TYPES, DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../../constants';
const DEFAULT_SCALE = 1;
@@ -181,12 +182,12 @@ export default {
updateImageDiffNoteInStore(
store,
{
- data: { updateImageDiffNote },
+ data: { repositionImageDiffNote },
},
) {
- return updateStoreAfterUpdateImageDiffNote(
+ return updateStoreAfterRepositionImageDiffNote(
store,
- updateImageDiffNote,
+ repositionImageDiffNote,
getDesignQuery,
this.designVariables,
);
@@ -198,7 +199,7 @@ export default {
);
const mutationPayload = {
- optimisticResponse: updateImageDiffNoteOptimisticResponse(note, {
+ optimisticResponse: repositionImageDiffNoteOptimisticResponse(note, {
position,
}),
variables: {
@@ -207,7 +208,7 @@ export default {
position,
},
},
- mutation: updateImageDiffNoteMutation,
+ mutation: repositionImageDiffNoteMutation,
update: this.updateImageDiffNoteInStore,
};
@@ -229,7 +230,7 @@ export default {
onQueryError(message) {
// because we redirect user to /designs (the issue page),
// we want to create these flashes on the issue page
- createFlash(message);
+ createFlash({ message });
this.$router.push({ name: this.$options.DESIGNS_ROUTE_NAME });
},
onError(message, e) {
@@ -300,6 +301,22 @@ export default {
this.resolvedDiscussionsExpanded = !this.resolvedDiscussionsExpanded;
},
},
+ beforeRouteEnter(to, from, next) {
+ const pageEl = getPageLayoutElement();
+ if (pageEl) {
+ pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ }
+
+ next();
+ },
+ beforeRouteLeave(to, from, next) {
+ const pageEl = getPageLayoutElement();
+ if (pageEl) {
+ pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
+ }
+
+ next();
+ },
createImageDiffNoteMutation,
DESIGNS_ROUTE_NAME,
};
@@ -366,7 +383,7 @@ export default {
@toggleResolvedComments="toggleResolvedComments"
@todoError="onTodoError"
>
- <template #replyForm>
+ <template #reply-form>
<apollo-mutation
v-if="isAnnotating"
#default="{ mutate, loading }"
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index 6e71dca41e9..ea404692840 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -1,25 +1,26 @@
<script>
-import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import VueDraggable from 'vuedraggable';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
-import { s__, sprintf } from '~/locale';
+import getDesignListQuery from 'shared_queries/design_management/get_design_list.query.graphql';
+import permissionsQuery from 'shared_queries/design_management/design_permissions.query.graphql';
+import createFlash, { FLASH_TYPES } from '~/flash';
+import { __, s__, sprintf } from '~/locale';
import { getFilename } from '~/lib/utils/file_upload';
import UploadButton from '../components/upload/button.vue';
import DeleteButton from '../components/delete_button.vue';
import Design from '../components/list/item.vue';
import DesignDestroyer from '../components/design_destroyer.vue';
import DesignVersionDropdown from '../components/upload/design_version_dropdown.vue';
-import DesignDropzone from '../components/upload/design_dropzone.vue';
+import DesignDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
import uploadDesignMutation from '../graphql/mutations/upload_design.mutation.graphql';
import moveDesignMutation from '../graphql/mutations/move_design.mutation.graphql';
-import permissionsQuery from '../graphql/queries/design_permissions.query.graphql';
-import getDesignListQuery from '../graphql/queries/get_design_list.query.graphql';
import allDesignsMixin from '../mixins/all_designs';
import {
UPLOAD_DESIGN_ERROR,
EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE,
EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
MOVE_DESIGN_ERROR,
+ UPLOAD_DESIGN_INVALID_FILETYPE_ERROR,
designUploadSkippedWarning,
designDeletionError,
} from '../utils/error_messages';
@@ -34,6 +35,7 @@ import {
} from '../utils/design_management_utils';
import { trackDesignCreate, trackDesignUpdate } from '../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../router/constants';
+import { VALID_DESIGN_FILE_MIMETYPE } from '../constants';
const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
@@ -42,6 +44,8 @@ export default {
GlLoadingIcon,
GlAlert,
GlButton,
+ GlSprintf,
+ GlLink,
UploadButton,
Design,
DesignDestroyer,
@@ -50,6 +54,11 @@ export default {
DesignDropzone,
VueDraggable,
},
+ dropzoneProps: {
+ dropToStartMessage: __('Drop your designs to start your upload.'),
+ isFileValid: isValidDesignFile,
+ validFileMimetypes: [VALID_DESIGN_FILE_MIMETYPE.mimetype],
+ },
mixins: [allDesignsMixin],
apollo: {
permissions: {
@@ -139,8 +148,8 @@ export default {
if (!this.canCreateDesign) return false;
if (files.length > MAXIMUM_FILE_UPLOAD_LIMIT) {
- createFlash(
- sprintf(
+ createFlash({
+ message: sprintf(
s__(
'DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again.',
),
@@ -148,7 +157,7 @@ export default {
upload_limit: MAXIMUM_FILE_UPLOAD_LIMIT,
},
),
- );
+ });
return false;
}
@@ -191,7 +200,7 @@ export default {
const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || [];
const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles);
if (skippedWarningMessage) {
- createFlash(skippedWarningMessage, 'warning');
+ createFlash({ message: skippedWarningMessage, types: FLASH_TYPES.WARNING });
}
// if this upload resulted in a new version being created, redirect user to the latest version
@@ -214,7 +223,7 @@ export default {
},
onUploadDesignError() {
this.resetFilesToBeSaved();
- createFlash(UPLOAD_DESIGN_ERROR);
+ createFlash({ message: UPLOAD_DESIGN_ERROR });
},
changeSelectedDesigns(filename) {
if (this.isDesignSelected(filename)) {
@@ -245,18 +254,21 @@ export default {
},
onDesignDeleteError() {
const errorMessage = designDeletionError({ singular: this.selectedDesigns.length === 1 });
- createFlash(errorMessage);
+ createFlash({ message: errorMessage });
+ },
+ onDesignDropzoneError() {
+ createFlash({ message: UPLOAD_DESIGN_INVALID_FILETYPE_ERROR });
},
onExistingDesignDropzoneChange(files, existingDesignFilename) {
const filesArr = Array.from(files);
if (filesArr.length > 1) {
- createFlash(EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE);
+ createFlash({ message: EXISTING_DESIGN_DROP_MANY_FILES_MESSAGE });
return;
}
if (!filesArr.some(({ name }) => existingDesignFilename === name)) {
- createFlash(EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE);
+ createFlash({ message: EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE });
return;
}
@@ -307,7 +319,7 @@ export default {
optimisticResponse: moveDesignOptimisticResponse(this.reorderedDesigns),
})
.catch(() => {
- createFlash(MOVE_DESIGN_ERROR);
+ createFlash({ message: MOVE_DESIGN_ERROR });
})
.finally(() => {
this.isReorderingInProgress = false;
@@ -325,6 +337,9 @@ export default {
animation: 200,
ghostClass: 'gl-visibility-hidden',
},
+ i18n: {
+ dropzoneDescriptionText: __('Drop or %{linkStart}upload%{linkEnd} designs to attach'),
+ },
};
</script>
@@ -335,7 +350,11 @@ export default {
@mouseenter="toggleOnPasteListener"
@mouseleave="toggleOffPasteListener"
>
- <header v-if="showToolbar" class="row-content-block gl-border-t-0 gl-p-3 gl-display-flex">
+ <header
+ v-if="showToolbar"
+ class="row-content-block gl-border-t-0 gl-p-3 gl-display-flex"
+ data-testid="design-toolbar-wrapper"
+ >
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full">
<div>
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
@@ -371,7 +390,12 @@ export default {
{{ s__('DesignManagement|Archive selected') }}
</delete-button>
</design-destroyer>
- <upload-button v-if="canCreateDesign" :is-saving="isSaving" @upload="onUploadDesign" />
+ <upload-button
+ v-if="canCreateDesign"
+ :is-saving="isSaving"
+ data-testid="design-upload-button"
+ @upload="onUploadDesign"
+ />
</div>
</div>
</header>
@@ -414,15 +438,26 @@ export default {
class="col-md-6 col-lg-3 gl-mb-3 gl-bg-transparent gl-shadow-none js-design-tile"
>
<design-dropzone
- :has-designs="hasDesigns"
- :is-dragging-design="isDraggingDesign"
+ :display-as-card="hasDesigns"
+ :enable-drag-behavior="isDraggingDesign"
+ v-bind="$options.dropzoneProps"
@change="onExistingDesignDropzoneChange($event, design.filename)"
+ @error="onDesignDropzoneError"
>
<design
v-bind="design"
:is-uploading="isDesignToBeSaved(design.filename)"
class="gl-bg-white"
/>
+ <template #upload-text="{ openFileUpload }">
+ <gl-sprintf :message="$options.i18n.dropzoneDescriptionText">
+ <template #link="{ content }">
+ <gl-link @click.stop="openFileUpload">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
</design-dropzone>
<input
@@ -438,12 +473,24 @@ export default {
<template #header>
<li :class="designDropzoneWrapperClass" data-testid="design-dropzone-wrapper">
<design-dropzone
- :is-dragging-design="isDraggingDesign"
+ :enable-drag-behavior="isDraggingDesign"
:class="{ 'design-list-item design-list-item-new': !isDesignListEmpty }"
- :has-designs="hasDesigns"
+ :display-as-card="hasDesigns"
+ v-bind="$options.dropzoneProps"
data-qa-selector="design_dropzone_content"
@change="onUploadDesign"
- />
+ @error="onDesignDropzoneError"
+ >
+ <template #upload-text="{ openFileUpload }">
+ <gl-sprintf :message="$options.i18n.dropzoneDescriptionText">
+ <template #link="{ content }">
+ <gl-link @click.stop="openFileUpload">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ </design-dropzone>
</li>
</template>
</vue-draggable>
diff --git a/app/assets/javascripts/design_management/router/index.js b/app/assets/javascripts/design_management/router/index.js
index cbeb2f7ce42..12692612bbc 100644
--- a/app/assets/javascripts/design_management/router/index.js
+++ b/app/assets/javascripts/design_management/router/index.js
@@ -1,9 +1,6 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from './routes';
-import { DESIGN_ROUTE_NAME } from './constants';
-import { getPageLayoutElement } from '~/design_management/utils/design_management_utils';
-import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../constants';
Vue.use(VueRouter);
@@ -13,20 +10,6 @@ export default function createRouter(base) {
mode: 'history',
routes,
});
- const pageEl = getPageLayoutElement();
-
- router.beforeEach(({ name }, _, next) => {
- // apply a fullscreen layout style in Design View (a.k.a design detail)
- if (pageEl) {
- if (name === DESIGN_ROUTE_NAME) {
- pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
- } else {
- pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
- }
- }
-
- next();
- });
return router;
}
diff --git a/app/assets/javascripts/design_management/utils/cache_update.js b/app/assets/javascripts/design_management/utils/cache_update.js
index fc0530ff977..5bd0288d037 100644
--- a/app/assets/javascripts/design_management/utils/cache_update.js
+++ b/app/assets/javascripts/design_management/utils/cache_update.js
@@ -2,7 +2,7 @@
import { differenceBy } from 'lodash';
import produce from 'immer';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
+import createFlash from '~/flash';
import { extractCurrentDiscussion, extractDesign, extractDesigns } from './design_management_utils';
import {
ADD_IMAGE_DIFF_NOTE_ERROR,
@@ -101,7 +101,7 @@ const addImageDiffNoteToStore = (store, createImageDiffNote, query, variables) =
});
};
-const updateImageDiffNoteInStore = (store, updateImageDiffNote, query, variables) => {
+const updateImageDiffNoteInStore = (store, repositionImageDiffNote, query, variables) => {
const sourceData = store.readQuery({
query,
variables,
@@ -111,12 +111,12 @@ const updateImageDiffNoteInStore = (store, updateImageDiffNote, query, variables
const design = extractDesign(draftData);
const discussion = extractCurrentDiscussion(
design.discussions,
- updateImageDiffNote.note.discussion.id,
+ repositionImageDiffNote.note.discussion.id,
);
discussion.notes = {
...discussion.notes,
- nodes: [updateImageDiffNote.note, ...discussion.notes.nodes.slice(1)],
+ nodes: [repositionImageDiffNote.note, ...discussion.notes.nodes.slice(1)],
};
});
@@ -237,7 +237,7 @@ export const deletePendingTodoFromStore = (store, todoMarkDone, query, queryVari
};
const onError = (data, message) => {
- createFlash(message);
+ createFlash({ message });
throw new Error(data.errors);
};
@@ -268,7 +268,7 @@ export const updateStoreAfterAddImageDiffNote = (store, data, query, queryVariab
}
};
-export const updateStoreAfterUpdateImageDiffNote = (store, data, query, queryVariables) => {
+export const updateStoreAfterRepositionImageDiffNote = (store, data, query, queryVariables) => {
if (hasErrors(data)) {
onError(data, UPDATE_IMAGE_DIFF_NOTE_ERROR);
} else {
@@ -286,7 +286,7 @@ export const updateStoreAfterUploadDesign = (store, data, query) => {
export const updateDesignsOnStoreAfterReorder = (store, data, query) => {
if (hasErrors(data)) {
- createFlash(data.errors[0]);
+ createFlash({ message: data.errors[0] });
} else {
moveDesignInStore(store, data, query);
}
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 687e793d3df..a905230811c 100644
--- a/app/assets/javascripts/design_management/utils/design_management_utils.js
+++ b/app/assets/javascripts/design_management/utils/design_management_utils.js
@@ -107,12 +107,12 @@ export const designUploadOptimisticResponse = files => {
* @param {Object} note
* @param {Object} position
*/
-export const updateImageDiffNoteOptimisticResponse = (note, { position }) => ({
+export const repositionImageDiffNoteOptimisticResponse = (note, { position }) => ({
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Mutation',
- updateImageDiffNote: {
- __typename: 'UpdateImageDiffNotePayload',
+ repositionImageDiffNote: {
+ __typename: 'RepositionImageDiffNotePayload',
note: {
...note,
position: {