diff options
Diffstat (limited to 'app/assets/javascripts/snippets')
8 files changed, 113 insertions, 24 deletions
diff --git a/app/assets/javascripts/snippets/components/edit.vue b/app/assets/javascripts/snippets/components/edit.vue index 2185b1d67e4..e8d6c005435 100644 --- a/app/assets/javascripts/snippets/components/edit.vue +++ b/app/assets/javascripts/snippets/components/edit.vue @@ -81,7 +81,10 @@ export default { return this.isUpdating ? __('Saving') : __('Save changes'); }, cancelButtonHref() { - return this.projectPath ? `/${this.projectPath}/snippets` : `/snippets`; + if (this.newSnippet) { + return this.projectPath ? `/${this.projectPath}/snippets` : `/snippets`; + } + return this.snippet.webUrl; }, titleFieldId() { return `${this.isProjectSnippet ? 'project' : 'personal'}_snippet_title`; @@ -173,7 +176,13 @@ export default { class="loading-animation prepend-top-20 append-bottom-20" /> <template v-else> - <title-field :id="titleFieldId" v-model="snippet.title" required :autofocus="true" /> + <title-field + :id="titleFieldId" + v-model="snippet.title" + data-qa-selector="snippet_title" + required + :autofocus="true" + /> <snippet-description-edit :id="descriptionFieldId" v-model="snippet.description" @@ -198,12 +207,15 @@ export default { category="primary" variant="success" :disabled="updatePrevented" + data-qa-selector="submit_button" @click="handleFormSubmit" >{{ saveButtonLabel }}</gl-button > </template> <template #append> - <gl-button :href="cancelButtonHref">{{ __('Cancel') }}</gl-button> + <gl-button data-testid="snippet-cancel-btn" :href="cancelButtonHref">{{ + __('Cancel') + }}</gl-button> </template> </form-footer-actions> </template> diff --git a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue index 44b4607e5a9..dd03902417d 100644 --- a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue +++ b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue @@ -33,7 +33,11 @@ export default { <div class="form-group file-editor"> <label>{{ s__('Snippets|File') }}</label> <div class="file-holder snippet"> - <blob-header-edit :value="fileName" @input="$emit('name-change', $event)" /> + <blob-header-edit + :value="fileName" + data-qa-selector="snippet_file_name" + @input="$emit('name-change', $event)" + /> <gl-loading-icon v-if="isLoading" :label="__('Loading snippet')" diff --git a/app/assets/javascripts/snippets/components/snippet_blob_view.vue b/app/assets/javascripts/snippets/components/snippet_blob_view.vue index 02a0fc7686d..6b218b21e56 100644 --- a/app/assets/javascripts/snippets/components/snippet_blob_view.vue +++ b/app/assets/javascripts/snippets/components/snippet_blob_view.vue @@ -7,7 +7,12 @@ import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue'; import GetBlobContent from '../queries/snippet.blob.content.query.graphql'; -import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants'; +import { + SIMPLE_BLOB_VIEWER, + RICH_BLOB_VIEWER, + BLOB_RENDER_EVENT_LOAD, + BLOB_RENDER_EVENT_SHOW_SOURCE, +} from '~/blob/components/constants'; export default { components: { @@ -27,6 +32,16 @@ export default { }, update: data => data.snippets.edges[0].node.blob.richData || data.snippets.edges[0].node.blob.plainData, + result() { + if (this.activeViewerType === RICH_BLOB_VIEWER) { + this.blob.richViewer.renderError = null; + } else { + this.blob.simpleViewer.renderError = null; + } + }, + skip() { + return this.viewer.renderError; + }, }, }, props: { @@ -62,9 +77,15 @@ export default { }, methods: { switchViewer(newViewer) { - this.activeViewerType = newViewer; + this.activeViewerType = newViewer || SIMPLE_BLOB_VIEWER; + }, + forceQuery() { + this.$apollo.queries.blobContent.skip = false; + this.$apollo.queries.blobContent.refetch(); }, }, + BLOB_RENDER_EVENT_LOAD, + BLOB_RENDER_EVENT_SHOW_SOURCE, }; </script> <template> @@ -75,12 +96,21 @@ export default { <template #actions> <clone-dropdown-button v-if="canBeCloned" + class="mr-2" :ssh-link="snippet.sshUrlToRepo" :http-link="snippet.httpUrlToRepo" + data-qa-selector="clone_button" /> </template> </blob-header> - <blob-content :loading="isContentLoading" :content="blobContent" :active-viewer="viewer" /> + <blob-content + :loading="isContentLoading" + :content="blobContent" + :active-viewer="viewer" + :blob="blob" + @[$options.BLOB_RENDER_EVENT_LOAD]="forceQuery" + @[$options.BLOB_RENDER_EVENT_SHOW_SOURCE]="switchViewer" + /> </article> </div> </template> diff --git a/app/assets/javascripts/snippets/components/snippet_description_edit.vue b/app/assets/javascripts/snippets/components/snippet_description_edit.vue index 6f3a86be8d7..0fe539a5de7 100644 --- a/app/assets/javascripts/snippets/components/snippet_description_edit.vue +++ b/app/assets/javascripts/snippets/components/snippet_description_edit.vue @@ -51,9 +51,9 @@ export default { > <textarea slot="textarea" - class="note-textarea js-gfm-input js-autosize markdown-area - qa-description-textarea" + class="note-textarea js-gfm-input js-autosize markdown-area" dir="auto" + data-qa-selector="snippet_description_field" data-supports-quick-actions="false" :value="value" :aria-label="__('Description')" diff --git a/app/assets/javascripts/snippets/components/snippet_description_view.vue b/app/assets/javascripts/snippets/components/snippet_description_view.vue new file mode 100644 index 00000000000..72afcc30be6 --- /dev/null +++ b/app/assets/javascripts/snippets/components/snippet_description_view.vue @@ -0,0 +1,21 @@ +<script> +import MarkdownFieldView from '~/vue_shared/components/markdown/field_view.vue'; + +export default { + components: { + MarkdownFieldView, + }, + props: { + description: { + type: String, + required: false, + default: '', + }, + }, +}; +</script> +<template> + <markdown-field-view class="snippet-description" data-qa-selector="snippet_description_field"> + <div class="md js-snippet-description" v-html="description"></div> + </markdown-field-view> +</template> diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue index 30a23b51bc4..c0967e9093c 100644 --- a/app/assets/javascripts/snippets/components/snippet_header.vue +++ b/app/assets/javascripts/snippets/components/snippet_header.vue @@ -10,6 +10,7 @@ import { GlDropdown, GlDropdownItem, GlButton, + GlTooltipDirective, } from '@gitlab/ui'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; @@ -30,6 +31,9 @@ export default { TimeAgoTooltip, GlButton, }, + directives: { + GlTooltip: GlTooltipDirective, + }, apollo: { canCreateSnippet: { query() { @@ -43,7 +47,7 @@ export default { update(data) { return this.snippet.project ? data.project.userPermissions.createSnippet - : data.currentUser.userPermissions.createSnippet; + : data.currentUser?.userPermissions.createSnippet; }, }, }, @@ -67,6 +71,10 @@ export default { condition: this.snippet.userPermissions.updateSnippet, text: __('Edit'), href: this.editLink, + disabled: this.snippet.blob.binary, + title: this.snippet.blob.binary + ? __('Snippets with non-text files can only be edited via Git.') + : undefined, }, { condition: this.snippet.userPermissions.adminSnippet, @@ -119,7 +127,7 @@ export default { }, methods: { redirectToSnippets() { - window.location.pathname = 'dashboard/snippets'; + window.location.pathname = `${this.snippet.project?.fullPath || 'dashboard'}/snippets`; }, closeDeleteModal() { this.$refs.deleteModal.hide(); @@ -186,18 +194,26 @@ export default { <div class="detail-page-header-actions"> <div class="d-none d-sm-flex"> <template v-for="(action, index) in personalSnippetActions"> - <gl-button + <div v-if="action.condition" :key="index" - :disabled="action.disabled" - :variant="action.variant" - :category="action.category" - :class="action.cssClass" - :href="action.href" - @click="action.click ? action.click() : undefined" + v-gl-tooltip + :title="action.title" + class="d-inline-block" > - {{ action.text }} - </gl-button> + <gl-button + :disabled="action.disabled" + :variant="action.variant" + :category="action.category" + :class="action.cssClass" + :href="action.href" + data-qa-selector="snippet_action_button" + :data-qa-action="action.text" + @click="action.click ? action.click() : undefined" + > + {{ action.text }} + </gl-button> + </div> </template> </div> <div class="d-block d-sm-none dropdown"> @@ -205,6 +221,8 @@ export default { <gl-dropdown-item v-for="(action, index) in personalSnippetActions" :key="index" + :disabled="action.disabled" + :title="action.title" :href="action.href" @click="action.click ? action.click() : undefined" >{{ action.text }}</gl-dropdown-item diff --git a/app/assets/javascripts/snippets/components/snippet_title.vue b/app/assets/javascripts/snippets/components/snippet_title.vue index 1fc0423a06c..5267c3748ca 100644 --- a/app/assets/javascripts/snippets/components/snippet_title.vue +++ b/app/assets/javascripts/snippets/components/snippet_title.vue @@ -1,11 +1,14 @@ <script> -import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import { GlSprintf } from '@gitlab/ui'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import SnippetDescription from './snippet_description_view.vue'; + export default { components: { TimeAgoTooltip, GlSprintf, + SnippetDescription, }, props: { snippet: { @@ -20,9 +23,8 @@ export default { <h2 class="snippet-title prepend-top-0 mb-3" data-qa-selector="snippet_title"> {{ snippet.title }} </h2> - <div v-if="snippet.description" class="description" data-qa-selector="snippet_description"> - <div class="md js-snippet-description" v-html="snippet.descriptionHtml"></div> - </div> + + <snippet-description v-if="snippet.description" :description="snippet.descriptionHtml" /> <small v-if="snippet.updatedAt !== snippet.createdAt" class="edited-text"> <gl-sprintf :message="__('Edited %{timeago}')"> diff --git a/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql index d793d0b6bb4..e7765dfd8ba 100644 --- a/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql +++ b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql @@ -17,6 +17,8 @@ fragment SnippetBase on Snippet { path rawPath size + externalStorage + renderedAsText simpleViewer { ...BlobViewer } |