Skip to content
Snippets Groups Projects
Commit a706b373 authored by Douwe Maan's avatar Douwe Maan
Browse files

Merge branch 'master' into 'dm-document-role-maintainer'

# Conflicts:
#   doc/development/code_review.md
parents 90056ed2 68eafa50
No related branches found
No related tags found
1 merge request!10495Merge Requests - Assignee
Showing
with 668 additions and 697 deletions
Loading
Loading
@@ -43,34 +43,25 @@ export default {
{
show: this.currentMergeRequestId,
title: __('Merge Request'),
views: [
rightSidebarViews.mergeRequestInfo,
],
views: [rightSidebarViews.mergeRequestInfo],
icon: 'text-description',
},
{
show: true,
title: __('Pipelines'),
views: [
rightSidebarViews.pipelines,
rightSidebarViews.jobsDetail,
],
views: [rightSidebarViews.pipelines, rightSidebarViews.jobsDetail],
icon: 'rocket',
},
{
show: this.showLivePreview,
title: __('Live preview'),
views: [
rightSidebarViews.clientSidePreview,
],
views: [rightSidebarViews.clientSidePreview],
icon: 'live-preview',
},
];
},
tabs() {
return this.defaultTabs
.concat(this.extensionTabs)
.filter(tab => tab.show);
return this.defaultTabs.concat(this.extensionTabs).filter(tab => tab.show);
},
tabViews() {
return _.flatten(this.tabs.map(tab => tab.views));
Loading
Loading
Loading
Loading
@@ -25,12 +25,7 @@ export default {
...mapState('rightPane', {
rightPaneIsOpen: 'isOpen',
}),
...mapState([
'rightPanelCollapsed',
'viewer',
'panelResizing',
'currentActivityView',
]),
...mapState(['rightPanelCollapsed', 'viewer', 'panelResizing', 'currentActivityView']),
...mapGetters([
'currentMergeRequest',
'getStagedFile',
Loading
Loading
Loading
Loading
@@ -30,9 +30,7 @@ export default {
},
computed: {
placeholderText() {
return this.tokens.length
? ''
: this.placeholder;
return this.tokens.length ? '' : this.placeholder;
},
},
watch: {
Loading
Loading
Loading
Loading
@@ -21,10 +21,7 @@ Vue.use(Translate);
export function initIde(el, options = {}) {
if (!el) return null;
 
const {
extraInitialData = () => ({}),
rootComponent = ide,
} = options;
const { extraInitialData = () => ({}), rootComponent = ide } = options;
 
return new Vue({
el,
Loading
Loading
Loading
Loading
@@ -11,14 +11,16 @@ export const computeDiff = (originalContent, newContent) => {
if (findOnLine) {
Object.assign(findOnLine, change, {
modified: true,
endLineNumber: (lineNumber + change.count) - 1,
endLineNumber: lineNumber + change.count - 1,
});
} else if ('added' in change || 'removed' in change) {
acc.push(Object.assign({}, change, {
lineNumber,
modified: undefined,
endLineNumber: (lineNumber + change.count) - 1,
}));
acc.push(
Object.assign({}, change, {
lineNumber,
modified: undefined,
endLineNumber: lineNumber + change.count - 1,
}),
);
}
 
if (!change.removed) {
Loading
Loading
import { computeDiff } from './diff';
 
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', (e) => {
self.addEventListener('message', e => {
const { data } = e;
 
// eslint-disable-next-line no-restricted-globals
Loading
Loading
Loading
Loading
@@ -116,57 +116,57 @@ export const openMergeRequest = (
targetProjectId,
mergeRequestId,
})
.then(mr => {
dispatch('setCurrentBranchId', mr.source_branch);
.then(mr => {
dispatch('setCurrentBranchId', mr.source_branch);
 
dispatch('getBranchData', {
projectId,
branchId: mr.source_branch,
});
dispatch('getBranchData', {
projectId,
branchId: mr.source_branch,
});
 
return dispatch('getFiles', {
projectId,
branchId: mr.source_branch,
});
})
.then(() =>
dispatch('getMergeRequestVersions', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(() =>
dispatch('getMergeRequestChanges', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(mrChanges => {
if (mrChanges.changes.length) {
dispatch('updateActivityBarView', activityBarViews.review);
}
return dispatch('getFiles', {
projectId,
branchId: mr.source_branch,
});
})
.then(() =>
dispatch('getMergeRequestVersions', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(() =>
dispatch('getMergeRequestChanges', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(mrChanges => {
if (mrChanges.changes.length) {
dispatch('updateActivityBarView', activityBarViews.review);
}
 
mrChanges.changes.forEach((change, ind) => {
const changeTreeEntry = state.entries[change.new_path];
mrChanges.changes.forEach((change, ind) => {
const changeTreeEntry = state.entries[change.new_path];
 
if (changeTreeEntry) {
dispatch('setFileMrChange', {
file: changeTreeEntry,
mrChange: change,
});
if (ind < 10) {
dispatch('getFileData', {
path: change.new_path,
makeFileActive: ind === 0,
if (changeTreeEntry) {
dispatch('setFileMrChange', {
file: changeTreeEntry,
mrChange: change,
});
if (ind < 10) {
dispatch('getFileData', {
path: change.new_path,
makeFileActive: ind === 0,
});
}
}
}
});
})
.catch(e => {
flash(__('Error while loading the merge request. Please try again.'));
throw e;
});
})
.catch(e => {
flash(__('Error while loading the merge request. Please try again.'));
throw e;
});
Loading
Loading
@@ -125,10 +125,7 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
});
};
 
export const openBranch = (
{ dispatch, state },
{ projectId, branchId, basePath },
) => {
export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath }) => {
dispatch('setCurrentBranchId', branchId);
 
dispatch('getBranchData', {
Loading
Loading
@@ -136,23 +133,20 @@ export const openBranch = (
branchId,
});
 
return (
dispatch('getFiles', {
projectId,
branchId,
})
.then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find(
key => key === path && !state.entries[key].pending,
);
const treeEntry = state.entries[treeEntryKey];
return dispatch('getFiles', {
projectId,
branchId,
}).then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find(
key => key === path && !state.entries[key].pending,
);
const treeEntry = state.entries[treeEntryKey];
 
if (treeEntry) {
dispatch('handleTreeEntryAction', treeEntry);
}
if (treeEntry) {
dispatch('handleTreeEntryAction', treeEntry);
}
})
);
}
});
};
Loading
Loading
@@ -13,6 +13,7 @@ export default {
},
[types.SET_SELECTED_TEMPLATE_TYPE](state, type) {
state.selectedTemplateType = type;
state.templates = [];
},
[types.SET_UPDATE_SUCCESS](state, success) {
state.updateSuccess = success;
Loading
Loading
Loading
Loading
@@ -3,8 +3,7 @@ import Api from '../../../../api';
import { scopes } from './constants';
import * as types from './mutation_types';
 
export const requestMergeRequests = ({ commit }) =>
commit(types.REQUEST_MERGE_REQUESTS);
export const requestMergeRequests = ({ commit }) => commit(types.REQUEST_MERGE_REQUESTS);
export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }) => {
dispatch(
'setErrorMessage',
Loading
Loading
<script>
import Visibility from 'visibilityjs';
import { visitUrl } from '../../lib/utils/url_utility';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
import Service from '../services/index';
import Store from '../stores';
import titleComponent from './title.vue';
import descriptionComponent from './description.vue';
import editedComponent from './edited.vue';
import formComponent from './form.vue';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
import Visibility from 'visibilityjs';
import { visitUrl } from '../../lib/utils/url_utility';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
import Service from '../services/index';
import Store from '../stores';
import titleComponent from './title.vue';
import descriptionComponent from './description.vue';
import editedComponent from './edited.vue';
import formComponent from './form.vue';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
 
export default {
components: {
descriptionComponent,
titleComponent,
editedComponent,
formComponent,
},
mixins: [
recaptchaModalImplementor,
],
props: {
endpoint: {
required: true,
type: String,
},
updateEndpoint: {
required: true,
type: String,
},
canUpdate: {
required: true,
type: Boolean,
},
canDestroy: {
required: true,
type: Boolean,
},
showInlineEditButton: {
type: Boolean,
required: false,
default: true,
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
issuableRef: {
type: String,
required: true,
},
initialTitleHtml: {
type: String,
required: true,
},
initialTitleText: {
type: String,
required: true,
},
initialDescriptionHtml: {
type: String,
required: false,
default: '',
},
initialDescriptionText: {
type: String,
required: false,
default: '',
},
initialTaskStatus: {
type: String,
required: false,
default: '',
},
updatedAt: {
type: String,
required: false,
default: '',
},
updatedByName: {
type: String,
required: false,
default: '',
},
updatedByPath: {
type: String,
required: false,
default: '',
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
markdownPreviewPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
issuableType: {
type: String,
required: false,
default: 'issue',
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
export default {
components: {
descriptionComponent,
titleComponent,
editedComponent,
formComponent,
},
mixins: [recaptchaModalImplementor],
props: {
endpoint: {
required: true,
type: String,
},
data() {
const store = new Store({
titleHtml: this.initialTitleHtml,
titleText: this.initialTitleText,
descriptionHtml: this.initialDescriptionHtml,
descriptionText: this.initialDescriptionText,
updatedAt: this.updatedAt,
updatedByName: this.updatedByName,
updatedByPath: this.updatedByPath,
taskStatus: this.initialTaskStatus,
});
updateEndpoint: {
required: true,
type: String,
},
canUpdate: {
required: true,
type: Boolean,
},
canDestroy: {
required: true,
type: Boolean,
},
showInlineEditButton: {
type: Boolean,
required: false,
default: true,
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
issuableRef: {
type: String,
required: true,
},
initialTitleHtml: {
type: String,
required: true,
},
initialTitleText: {
type: String,
required: true,
},
initialDescriptionHtml: {
type: String,
required: false,
default: '',
},
initialDescriptionText: {
type: String,
required: false,
default: '',
},
initialTaskStatus: {
type: String,
required: false,
default: '',
},
updatedAt: {
type: String,
required: false,
default: '',
},
updatedByName: {
type: String,
required: false,
default: '',
},
updatedByPath: {
type: String,
required: false,
default: '',
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
markdownPreviewPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
issuableType: {
type: String,
required: false,
default: 'issue',
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
},
data() {
const store = new Store({
titleHtml: this.initialTitleHtml,
titleText: this.initialTitleText,
descriptionHtml: this.initialDescriptionHtml,
descriptionText: this.initialDescriptionText,
updatedAt: this.updatedAt,
updatedByName: this.updatedByName,
updatedByPath: this.updatedByPath,
taskStatus: this.initialTaskStatus,
});
 
return {
store,
state: store.state,
showForm: false,
};
},
computed: {
formState() {
return this.store.formState;
},
hasUpdated() {
return !!this.state.updatedAt;
},
issueChanged() {
const descriptionChanged =
this.initialDescriptionText !== this.store.formState.description;
const titleChanged =
this.initialTitleText !== this.store.formState.title;
return descriptionChanged || titleChanged;
},
return {
store,
state: store.state,
showForm: false,
};
},
computed: {
formState() {
return this.store.formState;
},
created() {
this.service = new Service(this.endpoint);
this.poll = new Poll({
resource: this.service,
method: 'getData',
successCallback: res => this.store.updateState(res.data),
errorCallback(err) {
throw new Error(err);
},
});
hasUpdated() {
return !!this.state.updatedAt;
},
issueChanged() {
const descriptionChanged = this.initialDescriptionText !== this.store.formState.description;
const titleChanged = this.initialTitleText !== this.store.formState.title;
return descriptionChanged || titleChanged;
},
},
created() {
this.service = new Service(this.endpoint);
this.poll = new Poll({
resource: this.service,
method: 'getData',
successCallback: res => this.store.updateState(res.data),
errorCallback(err) {
throw new Error(err);
},
});
if (!Visibility.hidden()) {
this.poll.makeRequest();
}
 
Visibility.change(() => {
if (!Visibility.hidden()) {
this.poll.makeRequest();
this.poll.restart();
} else {
this.poll.stop();
}
});
 
Visibility.change(() => {
if (!Visibility.hidden()) {
this.poll.restart();
} else {
this.poll.stop();
}
});
window.addEventListener('beforeunload', this.handleBeforeUnloadEvent);
window.addEventListener('beforeunload', this.handleBeforeUnloadEvent);
 
eventHub.$on('delete.issuable', this.deleteIssuable);
eventHub.$on('update.issuable', this.updateIssuable);
eventHub.$on('close.form', this.closeForm);
eventHub.$on('open.form', this.openForm);
},
beforeDestroy() {
eventHub.$off('delete.issuable', this.deleteIssuable);
eventHub.$off('update.issuable', this.updateIssuable);
eventHub.$off('close.form', this.closeForm);
eventHub.$off('open.form', this.openForm);
window.removeEventListener('beforeunload', this.handleBeforeUnloadEvent);
},
methods: {
handleBeforeUnloadEvent(e) {
const event = e;
if (this.showForm && this.issueChanged) {
event.returnValue = 'Are you sure you want to lose your issue information?';
}
return undefined;
},
eventHub.$on('delete.issuable', this.deleteIssuable);
eventHub.$on('update.issuable', this.updateIssuable);
eventHub.$on('close.form', this.closeForm);
eventHub.$on('open.form', this.openForm);
},
beforeDestroy() {
eventHub.$off('delete.issuable', this.deleteIssuable);
eventHub.$off('update.issuable', this.updateIssuable);
eventHub.$off('close.form', this.closeForm);
eventHub.$off('open.form', this.openForm);
window.removeEventListener('beforeunload', this.handleBeforeUnloadEvent);
},
methods: {
handleBeforeUnloadEvent(e) {
const event = e;
if (this.showForm && this.issueChanged) {
event.returnValue = 'Are you sure you want to lose your issue information?';
}
return undefined;
},
 
openForm() {
if (!this.showForm) {
this.showForm = true;
this.store.setFormState({
title: this.state.titleText,
description: this.state.descriptionText,
lockedWarningVisible: false,
updateLoading: false,
});
}
},
closeForm() {
this.showForm = false;
},
openForm() {
if (!this.showForm) {
this.showForm = true;
this.store.setFormState({
title: this.state.titleText,
description: this.state.descriptionText,
lockedWarningVisible: false,
updateLoading: false,
});
}
},
closeForm() {
this.showForm = false;
},
 
updateIssuable() {
return this.service.updateIssuable(this.store.formState)
.then(res => res.data)
.then(data => this.checkForSpam(data))
.then((data) => {
if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url);
}
updateIssuable() {
return this.service
.updateIssuable(this.store.formState)
.then(res => res.data)
.then(data => this.checkForSpam(data))
.then(data => {
if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url);
}
 
return this.service.getData();
})
.then(res => res.data)
.then((data) => {
this.store.updateState(data);
return this.service.getData();
})
.then(res => res.data)
.then(data => {
this.store.updateState(data);
eventHub.$emit('close.form');
})
.catch(error => {
if (error && error.name === 'SpamError') {
this.openRecaptcha();
} else {
eventHub.$emit('close.form');
})
.catch((error) => {
if (error && error.name === 'SpamError') {
this.openRecaptcha();
} else {
eventHub.$emit('close.form');
window.Flash(`Error updating ${this.issuableType}`);
}
});
},
closeRecaptchaModal() {
this.store.setFormState({
updateLoading: false,
window.Flash(`Error updating ${this.issuableType}`);
}
});
},
 
this.closeRecaptcha();
},
closeRecaptchaModal() {
this.store.setFormState({
updateLoading: false,
});
 
deleteIssuable() {
this.service.deleteIssuable()
.then(res => res.data)
.then((data) => {
// Stop the poll so we don't get 404's with the issuable not existing
this.poll.stop();
this.closeRecaptcha();
},
 
visitUrl(data.web_url);
})
.catch(() => {
eventHub.$emit('close.form');
window.Flash(`Error deleting ${this.issuableType}`);
});
},
deleteIssuable() {
this.service
.deleteIssuable()
.then(res => res.data)
.then(data => {
// Stop the poll so we don't get 404's with the issuable not existing
this.poll.stop();
visitUrl(data.web_url);
})
.catch(() => {
eventHub.$emit('close.form');
window.Flash(`Error deleting ${this.issuableType}`);
});
},
};
},
};
</script>
 
<template>
Loading
Loading
<script>
import $ from 'jquery';
import animateMixin from '../mixins/animate';
import TaskList from '../../task_list';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
import $ from 'jquery';
import animateMixin from '../mixins/animate';
import TaskList from '../../task_list';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
 
export default {
mixins: [
animateMixin,
recaptchaModalImplementor,
],
export default {
mixins: [animateMixin, recaptchaModalImplementor],
 
props: {
canUpdate: {
type: Boolean,
required: true,
},
descriptionHtml: {
type: String,
required: true,
},
descriptionText: {
type: String,
required: true,
},
taskStatus: {
type: String,
required: false,
default: '',
},
issuableType: {
type: String,
required: false,
default: 'issue',
},
updateUrl: {
type: String,
required: false,
default: null,
},
props: {
canUpdate: {
type: Boolean,
required: true,
},
data() {
return {
preAnimation: false,
pulseAnimation: false,
};
descriptionHtml: {
type: String,
required: true,
},
watch: {
descriptionHtml() {
this.animateChange();
descriptionText: {
type: String,
required: true,
},
taskStatus: {
type: String,
required: false,
default: '',
},
issuableType: {
type: String,
required: false,
default: 'issue',
},
updateUrl: {
type: String,
required: false,
default: null,
},
},
data() {
return {
preAnimation: false,
pulseAnimation: false,
};
},
watch: {
descriptionHtml() {
this.animateChange();
 
this.$nextTick(() => {
this.renderGFM();
});
},
taskStatus() {
this.updateTaskStatusText();
},
this.$nextTick(() => {
this.renderGFM();
});
},
mounted() {
this.renderGFM();
taskStatus() {
this.updateTaskStatusText();
},
methods: {
renderGFM() {
$(this.$refs['gfm-content']).renderGFM();
},
mounted() {
this.renderGFM();
this.updateTaskStatusText();
},
methods: {
renderGFM() {
$(this.$refs['gfm-content']).renderGFM();
 
if (this.canUpdate) {
// eslint-disable-next-line no-new
new TaskList({
dataType: this.issuableType,
fieldName: 'description',
selector: '.detail-page-description',
onSuccess: this.taskListUpdateSuccess.bind(this),
});
}
},
if (this.canUpdate) {
// eslint-disable-next-line no-new
new TaskList({
dataType: this.issuableType,
fieldName: 'description',
selector: '.detail-page-description',
onSuccess: this.taskListUpdateSuccess.bind(this),
});
}
},
 
taskListUpdateSuccess(data) {
try {
this.checkForSpam(data);
this.closeRecaptcha();
} catch (error) {
if (error && error.name === 'SpamError') this.openRecaptcha();
}
},
taskListUpdateSuccess(data) {
try {
this.checkForSpam(data);
this.closeRecaptcha();
} catch (error) {
if (error && error.name === 'SpamError') this.openRecaptcha();
}
},
 
updateTaskStatusText() {
const taskRegexMatches = this.taskStatus.match(/(\d+) of ((?!0)\d+)/);
const $issuableHeader = $('.issuable-meta');
const $tasks = $('#task_status', $issuableHeader);
const $tasksShort = $('#task_status_short', $issuableHeader);
updateTaskStatusText() {
const taskRegexMatches = this.taskStatus.match(/(\d+) of ((?!0)\d+)/);
const $issuableHeader = $('.issuable-meta');
const $tasks = $('#task_status', $issuableHeader);
const $tasksShort = $('#task_status_short', $issuableHeader);
 
if (taskRegexMatches) {
$tasks.text(this.taskStatus);
$tasksShort.text(
`${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ?
's' :
''}`,
);
} else {
$tasks.text('');
$tasksShort.text('');
}
},
if (taskRegexMatches) {
$tasks.text(this.taskStatus);
$tasksShort.text(
`${taskRegexMatches[1]}/${taskRegexMatches[2]} task${taskRegexMatches[2] > 1 ? 's' : ''}`,
);
} else {
$tasks.text('');
$tasksShort.text('');
}
},
};
},
};
</script>
 
<template>
Loading
Loading
<script>
import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update';
import eventHub from '../event_hub';
import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update';
import eventHub from '../event_hub';
 
const issuableTypes = {
issue: __('Issue'),
epic: __('Epic'),
};
const issuableTypes = {
issue: __('Issue'),
epic: __('Epic'),
};
 
export default {
mixins: [updateMixin],
props: {
canDestroy: {
type: Boolean,
required: true,
},
formState: {
type: Object,
required: true,
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
issuableType: {
type: String,
required: true,
},
export default {
mixins: [updateMixin],
props: {
canDestroy: {
type: Boolean,
required: true,
},
data() {
return {
deleteLoading: false,
};
formState: {
type: Object,
required: true,
},
computed: {
isSubmitEnabled() {
return this.formState.title.trim() !== '';
},
shouldShowDeleteButton() {
return this.canDestroy && this.showDeleteButton;
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
methods: {
closeForm() {
eventHub.$emit('close.form');
},
deleteIssuable() {
const confirmMessage = sprintf(__('%{issuableType} will be removed! Are you sure?'), {
issuableType: issuableTypes[this.issuableType],
});
// eslint-disable-next-line no-alert
if (window.confirm(confirmMessage)) {
this.deleteLoading = true;
issuableType: {
type: String,
required: true,
},
},
data() {
return {
deleteLoading: false,
};
},
computed: {
isSubmitEnabled() {
return this.formState.title.trim() !== '';
},
shouldShowDeleteButton() {
return this.canDestroy && this.showDeleteButton;
},
},
methods: {
closeForm() {
eventHub.$emit('close.form');
},
deleteIssuable() {
const confirmMessage = sprintf(__('%{issuableType} will be removed! Are you sure?'), {
issuableType: issuableTypes[this.issuableType],
});
// eslint-disable-next-line no-alert
if (window.confirm(confirmMessage)) {
this.deleteLoading = true;
 
eventHub.$emit('delete.issuable');
}
},
eventHub.$emit('delete.issuable');
}
},
};
},
};
</script>
 
<template>
Loading
Loading
<script>
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
 
export default {
components: {
timeAgoTooltip,
export default {
components: {
timeAgoTooltip,
},
props: {
updatedAt: {
type: String,
required: false,
default: '',
},
props: {
updatedAt: {
type: String,
required: false,
default: '',
},
updatedByName: {
type: String,
required: false,
default: '',
},
updatedByPath: {
type: String,
required: false,
default: '',
},
updatedByName: {
type: String,
required: false,
default: '',
},
computed: {
hasUpdatedBy() {
return this.updatedByName && this.updatedByPath;
},
updatedByPath: {
type: String,
required: false,
default: '',
},
};
},
computed: {
hasUpdatedBy() {
return this.updatedByName && this.updatedByPath;
},
},
};
</script>
 
<template>
Loading
Loading
@@ -53,4 +53,3 @@
</span>
</small>
</template>
<script>
import updateMixin from '../../mixins/update';
import markdownField from '../../../vue_shared/components/markdown/field.vue';
import updateMixin from '../../mixins/update';
import markdownField from '../../../vue_shared/components/markdown/field.vue';
 
export default {
components: {
markdownField,
export default {
components: {
markdownField,
},
mixins: [updateMixin],
props: {
formState: {
type: Object,
required: true,
},
mixins: [updateMixin],
props: {
formState: {
type: Object,
required: true,
},
markdownPreviewPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
markdownVersion: {
type: Number,
required: false,
default: 0,
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
markdownPreviewPath: {
type: String,
required: true,
},
mounted() {
this.$refs.textarea.focus();
markdownDocsPath: {
type: String,
required: true,
},
};
markdownVersion: {
type: Number,
required: false,
default: 0,
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
},
mounted() {
this.$refs.textarea.focus();
},
};
</script>
 
<template>
Loading
Loading
<script>
import $ from 'jquery';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
import $ from 'jquery';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
 
export default {
props: {
formState: {
type: Object,
required: true,
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
export default {
props: {
formState: {
type: Object,
required: true,
},
computed: {
issuableTemplatesJson() {
return JSON.stringify(this.issuableTemplates);
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
mounted() {
// Create the editor for the template
const editor = document.querySelector('.detail-page-description .note-textarea') || {};
editor.setValue = (val) => {
this.formState.description = val;
};
editor.getValue = () => this.formState.description;
this.issuableTemplate = new IssuableTemplateSelectors({
$dropdowns: $(this.$refs.toggle),
editor,
});
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
};
},
computed: {
issuableTemplatesJson() {
return JSON.stringify(this.issuableTemplates);
},
},
mounted() {
// Create the editor for the template
const editor = document.querySelector('.detail-page-description .note-textarea') || {};
editor.setValue = val => {
this.formState.description = val;
};
editor.getValue = () => this.formState.description;
this.issuableTemplate = new IssuableTemplateSelectors({
$dropdowns: $(this.$refs.toggle),
editor,
});
},
};
</script>
 
<template>
Loading
Loading
<script>
import updateMixin from '../../mixins/update';
import updateMixin from '../../mixins/update';
 
export default {
mixins: [updateMixin],
props: {
formState: {
type: Object,
required: true,
},
export default {
mixins: [updateMixin],
props: {
formState: {
type: Object,
required: true,
},
};
},
};
</script>
 
<template>
Loading
Loading
<script>
import lockedWarning from './locked_warning.vue';
import titleField from './fields/title.vue';
import descriptionField from './fields/description.vue';
import editActions from './edit_actions.vue';
import descriptionTemplate from './fields/description_template.vue';
import lockedWarning from './locked_warning.vue';
import titleField from './fields/title.vue';
import descriptionField from './fields/description.vue';
import editActions from './edit_actions.vue';
import descriptionTemplate from './fields/description_template.vue';
 
export default {
components: {
lockedWarning,
titleField,
descriptionField,
descriptionTemplate,
editActions,
export default {
components: {
lockedWarning,
titleField,
descriptionField,
descriptionTemplate,
editActions,
},
props: {
canDestroy: {
type: Boolean,
required: true,
},
props: {
canDestroy: {
type: Boolean,
required: true,
},
formState: {
type: Object,
required: true,
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
issuableType: {
type: String,
required: true,
},
markdownPreviewPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
formState: {
type: Object,
required: true,
},
computed: {
hasIssuableTemplates() {
return this.issuableTemplates.length;
},
issuableTemplates: {
type: Array,
required: false,
default: () => [],
},
};
issuableType: {
type: String,
required: true,
},
markdownPreviewPath: {
type: String,
required: true,
},
markdownDocsPath: {
type: String,
required: true,
},
markdownVersion: {
type: Number,
required: false,
default: 0,
},
projectPath: {
type: String,
required: true,
},
projectNamespace: {
type: String,
required: true,
},
showDeleteButton: {
type: Boolean,
required: false,
default: true,
},
canAttachFile: {
type: Boolean,
required: false,
default: true,
},
enableAutocomplete: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
hasIssuableTemplates() {
return this.issuableTemplates.length;
},
},
};
</script>
 
<template>
Loading
Loading
<script>
export default {
computed: {
currentPath() {
return window.location.pathname;
},
export default {
computed: {
currentPath() {
return window.location.pathname;
},
};
},
};
</script>
 
<template>
Loading
Loading
Loading
Loading
@@ -25,8 +25,10 @@ export default class Store {
}
 
stateShouldUpdate(data) {
return this.state.titleText !== data.title_text ||
this.state.descriptionText !== data.description_text;
return (
this.state.titleText !== data.title_text ||
this.state.descriptionText !== data.description_text
);
}
 
setFormState(state) {
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