debian-mirror-gitlab/app/assets/javascripts/snippets/components/snippet_header.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

323 lines
9.8 KiB
Vue
Raw Normal View History

2020-01-01 13:55:28 +05:30
<script>
import {
GlAvatar,
GlIcon,
GlSprintf,
GlModal,
GlAlert,
GlLoadingIcon,
2021-01-29 00:20:46 +05:30
GlDropdown,
GlDropdownItem,
2020-04-22 19:07:51 +05:30
GlButton,
2020-05-24 23:13:21 +05:30
GlTooltipDirective,
2020-01-01 13:55:28 +05:30
} from '@gitlab/ui';
2021-11-18 22:05:49 +05:30
import { isEmpty } from 'lodash';
2021-01-29 00:20:46 +05:30
import CanCreateProjectSnippet from 'shared_queries/snippet/project_permissions.query.graphql';
2021-03-11 19:13:27 +05:30
import CanCreatePersonalSnippet from 'shared_queries/snippet/user_permissions.query.graphql';
import { fetchPolicies } from '~/lib/graphql';
2021-11-18 22:05:49 +05:30
import axios from '~/lib/utils/axios_utils';
2021-03-11 19:13:27 +05:30
import { joinPaths } from '~/lib/utils/url_utility';
2021-11-18 22:05:49 +05:30
import { __, s__, sprintf } from '~/locale';
2020-01-01 13:55:28 +05:30
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
2022-11-25 23:54:43 +05:30
import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/flash';
2020-01-01 13:55:28 +05:30
2022-06-21 17:19:12 +05:30
import DeleteSnippetMutation from '../mutations/delete_snippet.mutation.graphql';
2020-01-01 13:55:28 +05:30
2021-11-18 22:05:49 +05:30
export const i18n = {
snippetSpamSuccess: sprintf(
s__('Snippets|%{spammable_titlecase} was submitted to Akismet successfully.'),
{ spammable_titlecase: __('Snippet') },
),
snippetSpamFailure: s__('Snippets|Error with Akismet. Please check the logs for more info.'),
};
2020-01-01 13:55:28 +05:30
export default {
components: {
GlAvatar,
GlIcon,
GlSprintf,
GlModal,
GlAlert,
GlLoadingIcon,
2021-01-29 00:20:46 +05:30
GlDropdown,
GlDropdownItem,
2020-01-01 13:55:28 +05:30
TimeAgoTooltip,
2020-04-22 19:07:51 +05:30
GlButton,
2020-01-01 13:55:28 +05:30
},
2020-05-24 23:13:21 +05:30
directives: {
GlTooltip: GlTooltipDirective,
},
2020-01-01 13:55:28 +05:30
apollo: {
canCreateSnippet: {
2021-01-03 14:25:43 +05:30
fetchPolicy: fetchPolicies.NO_CACHE,
2020-01-01 13:55:28 +05:30
query() {
return this.snippet.project ? CanCreateProjectSnippet : CanCreatePersonalSnippet;
},
variables() {
return {
fullPath: this.snippet.project ? this.snippet.project.fullPath : undefined,
};
},
update(data) {
return this.snippet.project
? data.project.userPermissions.createSnippet
2020-05-24 23:13:21 +05:30
: data.currentUser?.userPermissions.createSnippet;
2020-01-01 13:55:28 +05:30
},
},
},
2021-11-18 22:05:49 +05:30
inject: ['reportAbusePath', 'canReportSpam'],
2020-01-01 13:55:28 +05:30
props: {
snippet: {
type: Object,
required: true,
},
},
data() {
return {
2021-11-18 22:05:49 +05:30
isLoading: false,
isSubmittingSpam: false,
2020-01-01 13:55:28 +05:30
errorMessage: '',
canCreateSnippet: false,
};
},
computed: {
2020-07-28 23:09:34 +05:30
snippetHasBinary() {
2021-03-08 18:12:59 +05:30
return Boolean(this.snippet.blobs.find((blob) => blob.binary));
2020-07-28 23:09:34 +05:30
},
2020-10-24 23:57:45 +05:30
authoredMessage() {
return this.snippet.author
? __('Authored %{timeago} by %{author}')
: __('Authored %{timeago}');
},
2020-01-01 13:55:28 +05:30
personalSnippetActions() {
return [
{
condition: this.snippet.userPermissions.updateSnippet,
text: __('Edit'),
href: this.editLink,
2020-07-28 23:09:34 +05:30
disabled: this.snippetHasBinary,
title: this.snippetHasBinary
2020-05-24 23:13:21 +05:30
? __('Snippets with non-text files can only be edited via Git.')
: undefined,
2020-01-01 13:55:28 +05:30
},
{
condition: this.snippet.userPermissions.adminSnippet,
text: __('Delete'),
click: this.showDeleteModal,
2020-04-22 19:07:51 +05:30
variant: 'danger',
category: 'secondary',
2020-01-01 13:55:28 +05:30
},
{
condition: this.canCreateSnippet,
text: __('New snippet'),
href: this.snippet.project
2020-11-24 15:15:51 +05:30
? joinPaths(this.snippet.project.webUrl, '-/snippets/new')
: joinPaths('/', gon.relative_url_root, '/-/snippets/new'),
2022-01-26 12:08:38 +05:30
variant: 'confirm',
2020-04-22 19:07:51 +05:30
category: 'secondary',
2021-10-27 15:23:28 +05:30
},
{
2021-11-18 22:05:49 +05:30
condition: this.canReportSpam && !isEmpty(this.reportAbusePath),
2021-10-27 15:23:28 +05:30
text: __('Submit as spam'),
2021-11-18 22:05:49 +05:30
click: this.submitAsSpam,
2021-10-27 15:23:28 +05:30
title: __('Submit as spam'),
2021-11-18 22:05:49 +05:30
loading: this.isSubmittingSpam,
2020-01-01 13:55:28 +05:30
},
];
},
2021-10-27 15:23:28 +05:30
hasPersonalSnippetActions() {
return Boolean(this.personalSnippetActions.filter(({ condition }) => condition).length);
},
2020-01-01 13:55:28 +05:30
editLink() {
return `${this.snippet.webUrl}/edit`;
},
visibility() {
return this.snippet.visibilityLevel;
},
snippetVisibilityLevelDescription() {
switch (this.visibility) {
case 'private':
return this.snippet.project !== null
? __('The snippet is visible only to project members.')
: __('The snippet is visible only to me.');
case 'internal':
2021-01-29 00:20:46 +05:30
return __('The snippet is visible to any logged in user except external users.');
2020-01-01 13:55:28 +05:30
default:
return __('The snippet can be accessed without any authentication.');
}
},
visibilityLevelIcon() {
switch (this.visibility) {
case 'private':
return 'lock';
case 'internal':
return 'shield';
default:
return 'earth';
}
},
},
methods: {
redirectToSnippets() {
2020-10-24 23:57:45 +05:30
window.location.pathname = this.snippet.project
? `${this.snippet.project.fullPath}/-/snippets`
2020-11-24 15:15:51 +05:30
: `${gon.relative_url_root}dashboard/snippets`;
2020-01-01 13:55:28 +05:30
},
closeDeleteModal() {
this.$refs.deleteModal.hide();
},
showDeleteModal() {
this.$refs.deleteModal.show();
},
deleteSnippet() {
2021-11-18 22:05:49 +05:30
this.isLoading = true;
2020-01-01 13:55:28 +05:30
this.$apollo
.mutate({
mutation: DeleteSnippetMutation,
variables: { id: this.snippet.id },
})
2020-04-22 19:07:51 +05:30
.then(({ data }) => {
if (data?.destroySnippet?.errors.length) {
throw new Error(data?.destroySnippet?.errors[0]);
}
2020-01-01 13:55:28 +05:30
this.errorMessage = undefined;
this.closeDeleteModal();
this.redirectToSnippets();
})
2021-03-08 18:12:59 +05:30
.catch((err) => {
2021-11-18 22:05:49 +05:30
this.isLoading = false;
2020-01-01 13:55:28 +05:30
this.errorMessage = err.message;
2021-11-18 22:05:49 +05:30
})
.finally(() => {
this.isLoading = false;
});
},
async submitAsSpam() {
try {
this.isSubmittingSpam = true;
await axios.post(this.reportAbusePath);
2022-11-25 23:54:43 +05:30
createAlert({
2021-11-18 22:05:49 +05:30
message: this.$options.i18n.snippetSpamSuccess,
2022-11-25 23:54:43 +05:30
variant: VARIANT_SUCCESS,
2020-01-01 13:55:28 +05:30
});
2021-11-18 22:05:49 +05:30
} catch (error) {
2022-11-25 23:54:43 +05:30
createAlert({ message: this.$options.i18n.snippetSpamFailure, variant: VARIANT_DANGER });
2021-11-18 22:05:49 +05:30
} finally {
this.isSubmittingSpam = false;
}
2020-01-01 13:55:28 +05:30
},
},
2021-11-18 22:05:49 +05:30
i18n,
2020-01-01 13:55:28 +05:30
};
</script>
<template>
<div class="detail-page-header">
<div class="detail-page-header-body">
<div
2020-07-28 23:09:34 +05:30
class="snippet-box has-tooltip d-flex align-items-center gl-mr-2 mb-1"
2020-06-23 00:09:42 +05:30
data-qa-selector="snippet_container"
2020-01-01 13:55:28 +05:30
:title="snippetVisibilityLevelDescription"
data-container="body"
>
2021-11-18 22:05:49 +05:30
<span class="sr-only">{{ s__(`VisibilityLevel|${visibility}`) }}</span>
2020-01-01 13:55:28 +05:30
<gl-icon :name="visibilityLevelIcon" :size="14" />
</div>
2020-10-24 23:57:45 +05:30
<div class="creator" data-testid="authored-message">
<gl-sprintf :message="authoredMessage">
2020-01-01 13:55:28 +05:30
<template #timeago>
<time-ago-tooltip
:time="snippet.createdAt"
tooltip-placement="bottom"
css-class="snippet_updated_ago"
/>
</template>
<template #author>
<a :href="snippet.author.webUrl" class="d-inline">
<gl-avatar :size="24" :src="snippet.author.avatarUrl" />
<span class="bold">{{ snippet.author.name }}</span>
</a>
2021-03-08 18:12:59 +05:30
<gl-emoji
v-if="snippet.author.status"
v-gl-tooltip
class="gl-vertical-align-baseline font-size-inherit gl-mr-1"
:title="snippet.author.status.message"
:data-name="snippet.author.status.emoji"
/>
2020-01-01 13:55:28 +05:30
</template>
</gl-sprintf>
</div>
</div>
2021-10-27 15:23:28 +05:30
<div v-if="hasPersonalSnippetActions" class="detail-page-header-actions">
2020-04-22 19:07:51 +05:30
<div class="d-none d-sm-flex">
2020-01-01 13:55:28 +05:30
<template v-for="(action, index) in personalSnippetActions">
2020-05-24 23:13:21 +05:30
<div
2020-01-01 13:55:28 +05:30
v-if="action.condition"
:key="index"
2020-05-24 23:13:21 +05:30
v-gl-tooltip
:title="action.title"
class="d-inline-block"
2021-10-27 15:23:28 +05:30
:class="{ 'gl-ml-3': index > 0 }"
2020-01-01 13:55:28 +05:30
>
2020-05-24 23:13:21 +05:30
<gl-button
:disabled="action.disabled"
2021-11-18 22:05:49 +05:30
:loading="action.loading"
2020-05-24 23:13:21 +05:30
: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"
2021-11-18 22:05:49 +05:30
>{{ action.text }}</gl-button
2020-05-24 23:13:21 +05:30
>
</div>
2020-01-01 13:55:28 +05:30
</template>
</div>
<div class="d-block d-sm-none dropdown">
2021-01-29 00:20:46 +05:30
<gl-dropdown :text="__('Options')" block>
2021-10-27 15:23:28 +05:30
<template v-for="(action, index) in personalSnippetActions">
<gl-dropdown-item
v-if="action.condition"
:key="index"
:disabled="action.disabled"
:title="action.title"
:href="action.href"
@click="action.click ? action.click() : undefined"
>{{ action.text }}</gl-dropdown-item
>
</template>
2021-01-29 00:20:46 +05:30
</gl-dropdown>
2020-01-01 13:55:28 +05:30
</div>
</div>
<gl-modal ref="deleteModal" modal-id="delete-modal" title="Example title">
<template #modal-title>{{ __('Delete snippet?') }}</template>
2022-06-21 17:19:12 +05:30
<gl-alert v-if="errorMessage" variant="danger" class="mb-2" @dismiss="errorMessage = ''">{{
errorMessage
}}</gl-alert>
2020-01-01 13:55:28 +05:30
2020-03-13 15:44:24 +05:30
<gl-sprintf :message="__('Are you sure you want to delete %{name}?')">
2021-11-18 22:05:49 +05:30
<template #name>
<strong>{{ snippet.title }}</strong>
</template>
2020-01-01 13:55:28 +05:30
</gl-sprintf>
<template #modal-footer>
<gl-button @click="closeDeleteModal">{{ __('Cancel') }}</gl-button>
<gl-button
variant="danger"
2020-04-22 19:07:51 +05:30
category="primary"
2021-11-18 22:05:49 +05:30
:disabled="isLoading"
2020-01-01 13:55:28 +05:30
data-qa-selector="delete_snippet_button"
@click="deleteSnippet"
>
2021-11-18 22:05:49 +05:30
<gl-loading-icon v-if="isLoading" size="sm" inline />
2020-01-01 13:55:28 +05:30
{{ __('Delete snippet') }}
</gl-button>
</template>
</gl-modal>
</div>
</template>