Skip to content
Snippets Groups Projects
Commit e7238677 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent c2b98d3d
No related branches found
No related tags found
No related merge requests found
Showing
with 375 additions and 38 deletions
Loading
Loading
@@ -2,6 +2,7 @@ extends:
- '@gitlab'
- plugin:promise/recommended
- plugin:no-jquery/slim
- plugin:no-jquery/deprecated-3.4
globals:
__webpack_public_path__: true
gl: false
Loading
Loading
@@ -48,8 +49,10 @@ rules:
no-jquery/no-animate: off
# all offenses of no-jquery/no-animate-toggle are false positives ( $toast.show() )
no-jquery/no-animate-toggle: off
no-jquery/no-event-shorthand: off
no-jquery/no-fade: off
no-jquery/no-serialize: error
no-jquery/no-sizzle: off
promise/always-return: off
promise/no-callback-in-promise: off
overrides:
Loading
Loading
Loading
Loading
@@ -220,9 +220,6 @@ export default {
this.assignedDiscussions = false;
this.fetchData(false);
},
isLatestVersion() {
return window.location.search.indexOf('diff_id') === -1;
},
startDiffRendering() {
requestIdleCallback(
() => {
Loading
Loading
@@ -232,7 +229,7 @@ export default {
);
},
fetchData(toggleTree = true) {
if (this.isLatestVersion() && this.glFeatures.diffsBatchLoad) {
if (this.glFeatures.diffsBatchLoad) {
this.fetchDiffFilesMeta()
.then(() => {
if (toggleTree) this.hideTreeListIfJustOneFile();
Loading
Loading
Loading
Loading
@@ -90,14 +90,13 @@ export const fetchDiffFiles = ({ state, commit }) => {
};
 
export const fetchDiffFilesBatch = ({ commit, state }) => {
const baseUrl = `${state.endpointBatch}?per_page=${DIFFS_PER_PAGE}`;
const url = page => (page ? `${baseUrl}&page=${page}` : baseUrl);
commit(types.SET_BATCH_LOADING, true);
 
const getBatch = page =>
axios
.get(url(page))
.get(state.endpointBatch, {
params: { page, per_page: DIFFS_PER_PAGE, w: state.showWhitespace ? '0' : '1' },
})
.then(({ data: { pagination, diff_files } }) => {
commit(types.SET_DIFF_DATA_BATCH, { diff_files });
commit(types.SET_BATCH_LOADING, false);
Loading
Loading
Loading
Loading
@@ -115,5 +115,30 @@ export const isOnDefaultBranch = (_state, getters) =>
export const canPushToBranch = (_state, getters) =>
getters.currentBranch && getters.currentBranch.can_push;
 
export const isFileDeletedAndReadded = (state, getters) => path => {
const stagedFile = getters.getStagedFile(path);
const file = state.entries[path];
return Boolean(stagedFile && stagedFile.deleted && file.tempFile);
};
// checks if any diff exists in the staged or unstaged changes for this path
export const getDiffInfo = (state, getters) => path => {
const stagedFile = getters.getStagedFile(path);
const file = state.entries[path];
const renamed = file.prevPath ? file.path !== file.prevPath : false;
const deletedAndReadded = getters.isFileDeletedAndReadded(path);
const deleted = deletedAndReadded ? false : file.deleted;
const tempFile = deletedAndReadded ? false : file.tempFile;
const changed = file.content !== (deletedAndReadded ? stagedFile.raw : file.raw);
return {
exists: changed || renamed || deleted || tempFile,
changed,
renamed,
deleted,
tempFile,
};
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
Loading
Loading
@@ -3,11 +3,16 @@ import ZenMode from '~/zen_mode';
import LineHighlighter from '~/line_highlighter';
import BlobViewer from '~/blob/viewer';
import snippetEmbed from '~/snippet/snippet_embed';
import initSnippetsApp from '~/snippets';
 
document.addEventListener('DOMContentLoaded', () => {
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
if (!gon.features.snippetsVue) {
new LineHighlighter(); // eslint-disable-line no-new
new BlobViewer(); // eslint-disable-line no-new
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
} else {
initSnippetsApp();
}
});
Loading
Loading
@@ -104,10 +104,10 @@ export default {
return acc.concat({
name,
path,
to: `/tree/${this.ref}${path}`,
to: `/-/tree/${this.ref}${path}`,
});
},
[{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}/` }],
[{ name: this.projectShortPath, path: '/', to: `/-/tree/${this.ref}/` }],
);
},
canCreateMrFromFork() {
Loading
Loading
Loading
Loading
@@ -15,7 +15,7 @@ export default {
const splitArray = this.path.split('/');
splitArray.pop();
 
return { path: `/tree/${this.commitRef}/${splitArray.join('/')}` };
return { path: `/-/tree/${this.commitRef}/${splitArray.join('/')}` };
},
},
methods: {
Loading
Loading
Loading
Loading
@@ -84,7 +84,7 @@ export default {
},
computed: {
routerLinkTo() {
return this.isFolder ? { path: `/tree/${this.ref}/${this.path}` } : null;
return this.isFolder ? { path: `/-/tree/${this.ref}/${this.path}` } : null;
},
iconName() {
return `fa-${getIconName(this.type, this.path)}`;
Loading
Loading
Loading
Loading
@@ -12,7 +12,7 @@ export default function createRouter(base, baseRef) {
base: joinPaths(gon.relative_url_root || '', base),
routes: [
{
path: `/tree/${baseRef}(/.*)?`,
path: `/-/tree/${baseRef}(/.*)?`,
name: 'treePath',
component: TreePage,
props: route => ({
Loading
Loading
<script>
import getSnippet from '../queries/getSnippet.query.graphql';
import GetSnippetQuery from '../queries/snippet.query.graphql';
import SnippetHeader from './snippet_header.vue';
import { GlLoadingIcon } from '@gitlab/ui';
 
export default {
components: {
SnippetHeader,
GlLoadingIcon,
},
apollo: {
snippetData: {
query: getSnippet,
snippet: {
query: GetSnippetQuery,
variables() {
return {
ids: this.snippetGid,
Loading
Loading
@@ -21,11 +27,24 @@ export default {
},
data() {
return {
snippetData: {},
snippet: {},
};
},
computed: {
isLoading() {
return this.$apollo.queries.snippet.loading;
},
},
};
</script>
<template>
<div class="js-snippet-view"></div>
<div class="js-snippet-view">
<gl-loading-icon
v-if="isLoading"
:label="__('Loading snippet')"
:size="2"
class="loading-animation prepend-top-20 append-bottom-20"
/>
<snippet-header v-else :snippet="snippet" />
</div>
</template>
<script>
import { __ } from '~/locale';
import {
GlAvatar,
GlIcon,
GlSprintf,
GlButton,
GlModal,
GlAlert,
GlLoadingIcon,
GlDropdown,
GlDropdownItem,
} from '@gitlab/ui';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import DeleteSnippetMutation from '../mutations/deleteSnippet.mutation.graphql';
import CanCreatePersonalSnippet from '../queries/userPermissions.query.graphql';
import CanCreateProjectSnippet from '../queries/projectPermissions.query.graphql';
export default {
components: {
GlAvatar,
GlIcon,
GlSprintf,
GlButton,
GlModal,
GlAlert,
GlLoadingIcon,
GlDropdown,
GlDropdownItem,
TimeAgoTooltip,
},
apollo: {
canCreateSnippet: {
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
: data.currentUser.userPermissions.createSnippet;
},
},
},
props: {
snippet: {
type: Object,
required: true,
},
},
data() {
return {
isDeleting: false,
errorMessage: '',
canCreateSnippet: false,
};
},
computed: {
personalSnippetActions() {
return [
{
condition: this.snippet.userPermissions.updateSnippet,
text: __('Edit'),
href: this.editLink,
click: undefined,
variant: 'outline-info',
cssClass: undefined,
},
{
condition: this.snippet.userPermissions.adminSnippet,
text: __('Delete'),
href: undefined,
click: this.showDeleteModal,
variant: 'outline-danger',
cssClass: 'btn-inverted btn-danger ml-2',
},
{
condition: this.canCreateSnippet,
text: __('New snippet'),
href: this.snippet.project
? `${this.snippet.project.webUrl}/snippets/new`
: '/snippets/new',
click: undefined,
variant: 'outline-success',
cssClass: 'btn-inverted btn-success ml-2',
},
];
},
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':
return __('The snippet is visible to any logged in user.');
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() {
window.location.pathname = 'dashboard/snippets';
},
closeDeleteModal() {
this.$refs.deleteModal.hide();
},
showDeleteModal() {
this.$refs.deleteModal.show();
},
deleteSnippet() {
this.isDeleting = true;
this.$apollo
.mutate({
mutation: DeleteSnippetMutation,
variables: { id: this.snippet.id },
})
.then(() => {
this.isDeleting = false;
this.errorMessage = undefined;
this.closeDeleteModal();
this.redirectToSnippets();
})
.catch(err => {
this.isDeleting = false;
this.errorMessage = err.message;
});
},
},
};
</script>
<template>
<div class="detail-page-header">
<div class="detail-page-header-body">
<div
class="snippet-box qa-snippet-box has-tooltip d-flex align-items-center append-right-5 mb-1"
:title="snippetVisibilityLevelDescription"
data-container="body"
>
<span class="sr-only">
{{ s__(`VisibilityLevel|${visibility}`) }}
</span>
<gl-icon :name="visibilityLevelIcon" :size="14" />
</div>
<div class="creator">
<gl-sprintf message="Authored %{timeago} by %{author}">
<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>
</template>
</gl-sprintf>
</div>
</div>
<div class="detail-page-header-actions">
<div class="d-none d-sm-block">
<template v-for="(action, index) in personalSnippetActions">
<gl-button
v-if="action.condition"
:key="index"
:variant="action.variant"
:class="action.cssClass"
:href="action.href || undefined"
@click="action.click ? action.click() : undefined"
>
{{ action.text }}
</gl-button>
</template>
</div>
<div class="d-block d-sm-none dropdown">
<gl-dropdown :text="__('Options')" class="w-100" toggle-class="text-center">
<gl-dropdown-item
v-for="(action, index) in personalSnippetActions"
:key="index"
:href="action.href || undefined"
@click="action.click ? action.click() : undefined"
>{{ action.text }}</gl-dropdown-item
>
</gl-dropdown>
</div>
</div>
<gl-modal ref="deleteModal" modal-id="delete-modal" title="Example title">
<template #modal-title>{{ __('Delete snippet?') }}</template>
<gl-alert v-if="errorMessage" variant="danger" class="mb-2" @dismiss="errorMessage = ''">{{
errorMessage
}}</gl-alert>
<gl-sprintf message="Are you sure you want to delete %{name}?">
<template #name
><strong>{{ snippet.title }}</strong></template
>
</gl-sprintf>
<template #modal-footer>
<gl-button @click="closeDeleteModal">{{ __('Cancel') }}</gl-button>
<gl-button
variant="danger"
:disabled="isDeleting"
data-qa-selector="delete_snippet_button"
@click="deleteSnippet"
>
<gl-loading-icon v-if="isDeleting" inline />
{{ __('Delete snippet') }}
</gl-button>
</template>
</gl-modal>
</div>
</template>
fragment Author on Snippet {
author {
name,
avatarUrl,
username,
webUrl
}
}
\ No newline at end of file
fragment Project on Snippet {
project {
fullPath
webUrl
}
}
\ No newline at end of file
fragment SnippetBase on Snippet {
id
title
description
createdAt
updatedAt
visibilityLevel
webUrl
userPermissions {
adminSnippet
updateSnippet
}
}
\ No newline at end of file
mutation DeleteSnippet($id: ID!) {
destroySnippet(input: {id: $id}) {
errors
}
}
\ No newline at end of file
query getSnippet($ids: [ID!]) {
snippets(ids: $ids) {
edges {
node {
title
description
createdAt
updatedAt
visibility
}
}
}
}
query CanCreateProjectSnippet($fullPath: ID!) {
project(fullPath: $fullPath) {
userPermissions {
createSnippet
}
}
}
\ No newline at end of file
#import '../fragments/snippetBase.fragment.graphql'
#import '../fragments/project.fragment.graphql'
#import '../fragments/author.fragment.graphql'
query GetSnippetQuery($ids: [ID!]) {
snippets(ids: $ids) {
edges {
node {
...SnippetBase
...Project
...Author
}
}
}
}
query CanCreatePersonalSnippet {
currentUser {
userPermissions {
createSnippet
}
}
}
\ No newline at end of file
Loading
Loading
@@ -79,10 +79,10 @@ export default {
return this.projectPath.indexOf('/') === 0 ? '' : `${gon.relative_url_root}/`;
},
fullOldPath() {
return `${this.basePath}${this.projectPath}/raw/${this.oldSha}/${this.oldPath}`;
return `${this.basePath}${this.projectPath}/-/raw/${this.oldSha}/${this.oldPath}`;
},
fullNewPath() {
return `${this.basePath}${this.projectPath}/raw/${this.newSha}/${this.newPath}`;
return `${this.basePath}${this.projectPath}/-/raw/${this.newSha}/${this.newPath}`;
},
},
};
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment