Commit cdc49388 authored by Filipa Lacerda's avatar Filipa Lacerda

[ci skip] Fix more rules

parent 318d6f44
...@@ -91,18 +91,21 @@ ...@@ -91,18 +91,21 @@
<template> <template>
<div class="cell text-cell"> <div class="cell text-cell">
<prompt /> <prompt />
<div class="markdown" v-html="markdown"></div> <div
class="markdown"
v-html="markdown">
</div>
</div> </div>
</template> </template>
<style> <style>
.markdown .katex { .markdown .katex {
display: block; display: block;
text-align: center; text-align: center;
} }
.markdown .inline-katex .katex { .markdown .inline-katex .katex {
display: inline; display: inline;
text-align: initial; text-align: initial;
} }
</style> </style>
<script> <script>
import Prompt from '../prompt.vue'; import Prompt from '../prompt.vue';
export default { export default {
components: {
prompt: Prompt,
},
props: { props: {
rawCode: { rawCode: {
type: String, type: String,
required: true, required: true,
}, },
}, },
components: { };
prompt: Prompt,
},
};
</script> </script>
<template> <template>
......
<script> <script>
import Prompt from '../prompt.vue'; import Prompt from '../prompt.vue';
export default { export default {
components: {
prompt: Prompt,
},
props: { props: {
outputType: { outputType: {
type: String, type: String,
...@@ -12,16 +15,12 @@ export default { ...@@ -12,16 +15,12 @@ export default {
required: true, required: true,
}, },
}, },
components: { };
prompt: Prompt,
},
};
</script> </script>
<template> <template>
<div class="output"> <div class="output">
<prompt /> <prompt />
<img <img :src="'data:' + outputType + ';base64,' + rawCode" />
:src="'data:' + outputType + ';base64,' + rawCode" />
</div> </div>
</template> </template>
<script> <script>
import CodeCell from '../code/index.vue'; import CodeCell from '../code/index.vue';
import Html from './html.vue'; import Html from './html.vue';
import Image from './image.vue'; import Image from './image.vue';
export default { export default {
components: {
'code-cell': CodeCell,
'html-output': Html,
'image-output': Image,
},
props: { props: {
codeCssClass: { codeCssClass: {
type: String, type: String,
...@@ -18,13 +23,9 @@ export default { ...@@ -18,13 +23,9 @@ export default {
output: { output: {
type: Object, type: Object,
requred: true, requred: true,
default: () => ({}),
}, },
}, },
components: {
'code-cell': CodeCell,
'html-output': Html,
'image-output': Image,
},
data() { data() {
return { return {
outputType: '', outputType: '',
...@@ -70,14 +71,16 @@ export default { ...@@ -70,14 +71,16 @@ export default {
return data; return data;
}, },
}, },
}; };
</script> </script>
<template> <template>
<component :is="componentName" <component
:is="componentName"
type="output" type="output"
:outputType="outputType" :output-type="outputType"
:count="count" :count="count"
:raw-code="rawCode" :raw-code="rawCode"
:code-css-class="codeCssClass" /> :code-css-class="codeCssClass"
/>
</template> </template>
...@@ -4,10 +4,17 @@ ...@@ -4,10 +4,17 @@
type: { type: {
type: String, type: String,
required: false, required: false,
default: '',
}, },
count: { count: {
type: Number, type: Number,
required: false, required: false,
default: 0,
},
},
computed: {
hasKeys() {
return this.type !== '' && this.count;
}, },
}, },
}; };
...@@ -15,16 +22,16 @@ ...@@ -15,16 +22,16 @@
<template> <template>
<div class="prompt"> <div class="prompt">
<span v-if="type && count"> <span v-if="hasKeys">
{{ type }} [{{ count }}]: {{ type }} [{{ count }}]:
</span> </span>
</div> </div>
</template> </template>
<style scoped> <style scoped>
.prompt { .prompt {
padding: 0 10px; padding: 0 10px;
min-width: 7em; min-width: 7em;
font-family: monospace; font-family: monospace;
} }
</style> </style>
...@@ -20,11 +20,6 @@ ...@@ -20,11 +20,6 @@
default: '', default: '',
}, },
}, },
methods: {
cellType(type) {
return `${type}-cell`;
},
},
computed: { computed: {
cells() { cells() {
if (this.notebook.worksheets) { if (this.notebook.worksheets) {
...@@ -45,6 +40,11 @@ ...@@ -45,6 +40,11 @@
return Object.keys(this.notebook).length; return Object.keys(this.notebook).length;
}, },
}, },
methods: {
cellType(type) {
return `${type}-cell`;
},
},
}; };
</script> </script>
......
...@@ -15,7 +15,17 @@ ...@@ -15,7 +15,17 @@
import issuableStateMixin from '../mixins/issuable_state'; import issuableStateMixin from '../mixins/issuable_state';
export default { export default {
name: 'commentForm', name: 'CommentForm',
components: {
issueWarning,
noteSignedOutWidget,
discussionLockedWidget,
markdownField,
userAvatarLink,
},
mixins: [
issuableStateMixin,
],
data() { data() {
return { return {
note: '', note: '',
...@@ -27,21 +37,6 @@ ...@@ -27,21 +37,6 @@
isSubmitButtonDisabled: true, isSubmitButtonDisabled: true,
}; };
}, },
components: {
issueWarning,
noteSignedOutWidget,
discussionLockedWidget,
markdownField,
userAvatarLink,
},
watch: {
note(newNote) {
this.setIsSubmitButtonDisabled(newNote, this.isSubmitting);
},
isSubmitting(newValue) {
this.setIsSubmitButtonDisabled(this.note, newValue);
},
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getCurrentUserLastNote', 'getCurrentUserLastNote',
...@@ -99,6 +94,23 @@ ...@@ -99,6 +94,23 @@
return this.getNoteableData.create_note_path; return this.getNoteableData.create_note_path;
}, },
}, },
watch: {
note(newNote) {
this.setIsSubmitButtonDisabled(newNote, this.isSubmitting);
},
isSubmitting(newValue) {
this.setIsSubmitButtonDisabled(this.note, newValue);
},
},
mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery.
$(document).on('issuable:change', (e, isClosed) => {
this.issueState = isClosed ? constants.CLOSED : constants.REOPENED;
});
this.initAutoSave();
this.initTaskList();
},
methods: { methods: {
...mapActions([ ...mapActions([
'saveNote', 'saveNote',
...@@ -231,18 +243,6 @@ Please check your network connection and try again.`; ...@@ -231,18 +243,6 @@ Please check your network connection and try again.`;
}); });
}, },
}, },
mixins: [
issuableStateMixin,
],
mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery.
$(document).on('issuable:change', (e, isClosed) => {
this.issueState = isClosed ? constants.CLOSED : constants.REOPENED;
});
this.initAutoSave();
this.initTaskList();
},
}; };
</script> </script>
...@@ -310,7 +310,7 @@ Please check your network connection and try again.`; ...@@ -310,7 +310,7 @@ Please check your network connection and try again.`;
:disabled="isSubmitButtonDisabled" :disabled="isSubmitButtonDisabled"
class="btn btn-create comment-btn js-comment-button js-comment-submit-button" class="btn btn-create comment-btn js-comment-button js-comment-submit-button"
type="submit"> type="submit">
{{commentButtonTitle}} {{ commentButtonTitle }}
</button> </button>
<button <button
:disabled="isSubmitButtonDisabled" :disabled="isSubmitButtonDisabled"
...@@ -370,7 +370,7 @@ Please check your network connection and try again.`; ...@@ -370,7 +370,7 @@ Please check your network connection and try again.`;
:class="actionButtonClassNames" :class="actionButtonClassNames"
:disabled="isSubmitting" :disabled="isSubmitting"
class="btn btn-comment btn-comment-and-close js-action-button"> class="btn btn-comment btn-comment-and-close js-action-button">
{{issueActionButtonTitle}} {{ issueActionButtonTitle }}
</button> </button>
<button <button
type="button" type="button"
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
import Issuable from '~/vue_shared/mixins/issuable'; import Issuable from '~/vue_shared/mixins/issuable';
export default { export default {
mixins: [
Issuable,
],
components: { components: {
Icon, Icon,
}, },
mixins: [
Issuable,
],
}; };
</script> </script>
...@@ -18,9 +18,11 @@ ...@@ -18,9 +18,11 @@
<icon <icon
name="lock" name="lock"
:size="16" :size="16"
class="icon"> class="icon"
</icon> />
<span>This {{ issuableDisplayName }} is locked. Only <b>project members</b> can comment.</span> <span>
This {{ issuableDisplayName }} is locked. Only <b>project members</b> can comment.
</span>
</span> </span>
</div> </div>
</template> </template>
...@@ -9,7 +9,13 @@ ...@@ -9,7 +9,13 @@
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
name: 'noteActions', name: 'NoteActions',
directives: {
tooltip,
},
components: {
loadingIcon,
},
props: { props: {
authorId: { authorId: {
type: Number, type: Number,
...@@ -41,12 +47,6 @@ ...@@ -41,12 +47,6 @@
required: true, required: true,
}, },
}, },
directives: {
tooltip,
},
components: {
loadingIcon,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getUserDataByProp', 'getUserDataByProp',
...@@ -98,7 +98,8 @@ ...@@ -98,7 +98,8 @@
data-placement="bottom" data-placement="bottom"
data-container="body" data-container="body"
href="#" href="#"
title="Add reaction"> title="Add reaction"
>
<loading-icon :inline="true" /> <loading-icon :inline="true" />
<span <span
v-html="emojiSmiling" v-html="emojiSmiling"
...@@ -127,7 +128,8 @@ ...@@ -127,7 +128,8 @@
data-placement="bottom"> data-placement="bottom">
<span <span
v-html="editSvg" v-html="editSvg"
class="link-highlight"></span> class="link-highlight">
</span>
</button> </button>
</div> </div>
<div <div
...@@ -143,7 +145,8 @@ ...@@ -143,7 +145,8 @@
data-placement="bottom"> data-placement="bottom">
<span <span
class="icon" class="icon"
v-html="ellipsisSvg"></span> v-html="ellipsisSvg">
</span>
</button> </button>
<ul class="dropdown-menu more-actions-dropdown dropdown-open-left"> <ul class="dropdown-menu more-actions-dropdown dropdown-open-left">
<li v-if="canReportAsAbuse"> <li v-if="canReportAsAbuse">
......
<script> <script>
export default { export default {
name: 'noteAttachment', name: 'NoteAttachment',
props: { props: {
attachment: { attachment: {
type: Object, type: Object,
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
rel="noopener noreferrer"> rel="noopener noreferrer">
<img <img
:src="attachment.url" :src="attachment.url"
class="note-image-attach" /> class="note-image-attach"
/>
</a> </a>
<div class="attachment"> <div class="attachment">
<a <a
...@@ -29,8 +30,9 @@ ...@@ -29,8 +30,9 @@
rel="noopener noreferrer"> rel="noopener noreferrer">
<i <i
class="fa fa-paperclip" class="fa fa-paperclip"
aria-hidden="true"></i> aria-hidden="true">
{{attachment.filename}} </i>
{{ attachment.filename }}
</a> </a>
</div> </div>
</div> </div>
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
directives: {
tooltip,
},
props: { props: {
awards: { awards: {
type: Array, type: Array,
...@@ -26,9 +29,6 @@ ...@@ -26,9 +29,6 @@
required: true, required: true,
}, },
}, },
directives: {
tooltip,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getUserData', 'getUserData',
...@@ -73,6 +73,11 @@ ...@@ -73,6 +73,11 @@
return this.getUserData.id; return this.getUserData.id;
}, },
}, },
created() {
this.emojiSmiling = emojiSmiling;
this.emojiSmile = emojiSmile;
this.emojiSmiley = emojiSmiley;
},
methods: { methods: {
...mapActions([ ...mapActions([
'toggleAwardRequest', 'toggleAwardRequest',
...@@ -168,11 +173,6 @@ ...@@ -168,11 +173,6 @@
.catch(() => Flash('Something went wrong on our end.')); .catch(() => Flash('Something went wrong on our end.'));
}, },
}, },
created() {
this.emojiSmiling = emojiSmiling;
this.emojiSmile = emojiSmile;
this.emojiSmiley = emojiSmiley;
},
}; };
</script> </script>
...@@ -191,7 +191,7 @@ ...@@ -191,7 +191,7 @@
type="button"> type="button">
<span v-html="getAwardHTML(awardName)"></span> <span v-html="getAwardHTML(awardName)"></span>
<span class="award-control-text js-counter"> <span class="award-control-text js-counter">
{{awardList.length}} {{ awardList.length }}
</span> </span>
</button> </button>
<div <div
......
...@@ -7,6 +7,15 @@ ...@@ -7,6 +7,15 @@
import autosave from '../mixins/autosave'; import autosave from '../mixins/autosave';
export default { export default {
components: {
noteEditedText,
noteAwardsList,
noteAttachment,
noteForm,
},
mixins: [
autosave,
],
props: { props: {
note: { note: {
type: Object, type: Object,
...@@ -22,40 +31,11 @@ ...@@ -22,40 +31,11 @@
default: false, default: false,
}, },
}, },
mixins: [
autosave,
],
components: {
noteEditedText,
noteAwardsList,
noteAttachment,
noteForm,
},
computed: { computed: {
noteBody() { noteBody() {
return this.note.note; return this.note.note;
}, },
}, },
methods: {
renderGFM() {
$(this.$refs['note-body']).renderGFM();
},
initTaskList() {
if (this.canEdit) {
this.taskList = new TaskList({
dataType: 'note',
fieldName: 'note',
selector: '.notes',
});
}
},
handleFormUpdate(note, parentElement, callback) {
this.$emit('handleFormUpdate', note, parentElement, callback);
},
formCancelHandler(shouldConfirm, isDirty) {
this.$emit('cancelFormEdition', shouldConfirm, isDirty);
},
},
mounted() { mounted() {
this.renderGFM(); this.renderGFM();
this.initTaskList(); this.initTaskList();
...@@ -76,6 +56,26 @@ ...@@ -76,6 +56,26 @@
} }
} }
}, },
methods: {
renderGFM() {
$(this.$refs['note-body']).renderGFM();
},
initTaskList() {
if (this.canEdit) {
this.taskList = new TaskList({
dataType: 'note',
fieldName: 'note',
selector: '.notes',
});
}
},
handleFormUpdate(note, parentElement, callback) {
this.$emit('handleFormUpdate', note, parentElement, callback);
},
formCancelHandler(shouldConfirm, isDirty) {
this.$emit('cancelFormEdition', shouldConfirm, isDirty);
},
},
}; };
</script> </script>
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default { export default {
name: 'editedNoteText', name: 'EditedNoteText',
components: {
timeAgoTooltip,
},
props: { props: {
actionText: { actionText: {
type: String, type: String,
...@@ -15,6 +18,7 @@ ...@@ -15,6 +18,7 @@
editedBy: { editedBy: {
type: Object, type: Object,
required: false, required: false,
default: () => ({}),
}, },
className: { className: {
type: String, type: String,
...@@ -22,15 +26,12 @@ ...@@ -22,15 +26,12 @@
default: 'edited-text', default: 'edited-text',
}, },
}, },
components: {
timeAgoTooltip,
},
}; };
</script> </script>
<template> <template>
<div :class="className"> <div :class="className">
{{actionText}} {{ actionText }}
<time-ago-tooltip <time-ago-tooltip
:time="editedAt" :time="editedAt"
tooltip-placement="bottom" tooltip-placement="bottom"
...@@ -40,7 +41,7 @@ ...@@ -40,7 +41,7 @@
<a <a
:href="editedBy.path" :href="editedBy.path"
class="js-vue-author author_link"> class="js-vue-author author_link">
{{editedBy.name}} {{ editedBy.name }}
</a> </a>
</template> </template>
</div> </div>
......
...@@ -6,7 +6,14 @@ ...@@ -6,7 +6,14 @@
import issuableStateMixin from '../mixins/issuable_state'; import issuableStateMixin from '../mixins/issuable_state';
export default { export default {
name: 'issueNoteForm', name: 'IssueNoteForm',
components: {
issueWarning,
markdownField,
},
mixins: [
issuableStateMixin,
],
props: { props: {
noteBody: { noteBody: {
type: String, type: String,
...@@ -16,6 +23,7 @@ ...@@ -16,6 +23,7 @@
noteId: { noteId: {
type: Number, type: Number,
required: false, required: false,
default: 0,
}, },
saveButtonTitle: { saveButtonTitle: {
type: String, type: String,
...@@ -39,10 +47,6 @@ ...@@ -39,10 +47,6 @@
isSubmitting: false, isSubmitting: false,
}; };
}, },
components: {
issueWarning,
markdownField,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getDiscussionLastNote', 'getDiscussionLastNote',
...@@ -70,6 +74,18 @@ ...@@ -70,6 +74,18 @@
return !this.note.length || this.isSubmitting; return !this.note.length || this.isSubmitting;
}, },
}, },
watch: {
noteBody() {
if (this.note === this.noteBody) {
this.note = this.noteBody;
} else {
this.conflictWhileEditing = true;
}
},
},
mounted() {
this.$refs.textarea.focus();
},
methods: { methods: {
handleUpdate() { handleUpdate() {
this.isSubmitting = true; this.isSubmitting = true;
...@@ -94,26 +110,13 @@ ...@@ -94,26 +110,13 @@
this.$emit('cancelFormEdition', shouldConfirm, this.noteBody !== this.note); this.$emit('cancelFormEdition', shouldConfirm, this.noteBody !== this.note);
}, },
}, },
mixins: [
issuableStateMixin,
],
mounted() {
this.$refs.textarea.focus();
},
watch: {
noteBody() {
if (this.note === this.noteBody) {
this.note = this.noteBody;
} else {
this.conflictWhileEditing = true;
}
},
},
}; };
</script> </script>
<template> <template>
<div ref="editNoteForm" class="note-edit-form current-note-edit-form"> <div
ref="editNoteForm"
class="note-edit-form current-note-edit-form">
<div <div
v-if="conflictWhileEditing" v-if="conflictWhileEditing"
class="js-conflict-edit-warning alert alert-danger"> class="js-conflict-edit-warning alert alert-danger">
...@@ -121,12 +124,13 @@ ...@@ -121,12 +124,13 @@
<a <a
:href="noteHash" :href="noteHash"
target="_blank" target="_blank"
rel="noopener noreferrer">updated comment</a> rel="noopener noreferrer">
updated comment
</a>
to ensure information is not lost. to ensure information is not lost.
</div> </div>
<div class="flash-container timeline-content"></div> <div class="flash-container timeline-content"></div>
<form <form class="edit-note common-note-form js-quick-submit gfm-form">
class="edit-note common-note-form js-quick-submit gfm-form">
<issue-warning <issue-warning
v-if="hasWarning(getNoteableData)" v-if="hasWarning(getNoteableData)"
...@@ -160,7 +164,7 @@ ...@@ -160,7 +164,7 @@
@click="handleUpdate()" @click="handleUpdate()"
:disabled="isDisabled" :disabled="isDisabled"
class="js-vue-issue-save btn btn-save"> class="js-vue-issue-save btn btn-save">
{{saveButtonTitle}} {{ saveButtonTitle }}
</button> </button>
<button <button
@click="cancelHandler()" @click="cancelHandler()"
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import timeAgoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
export default { export default {
components: {
timeAgoTooltip,
},
props: { props: {
author: { author: {
type: Object, type: Object,
...@@ -37,9 +40,6 @@ ...@@ -37,9 +40,6 @@
isExpanded: true, isExpanded: true,
}; };
}, },
components: {
timeAgoTooltip,
},
computed: { computed: {
toggleChevronClass() { toggleChevronClass() {
return this.isExpanded ? 'fa-chevron-up' : 'fa-chevron-down'; return this.isExpanded ? 'fa-chevron-up' : 'fa-chevron-down';
...@@ -67,16 +67,16 @@ ...@@ -67,16 +67,16 @@
<div class="note-header-info"> <div class="note-header-info">
<a :href="author.path"> <a :href="author.path">
<span class="note-header-author-name"> <span class="note-header-author-name">
{{author.name}} {{ author.name }}
</span> </span>
<span class="note-headline-light"> <span class="note-headline-light">
@{{author.username}} @{{ author.username }}
</span> </span>
</a> </a>
<span class="note-headline-light"> <span class="note-headline-light">
<span class="note-headline-meta"> <span class="note-headline-meta">
<template v-if="actionText"> <template v-if="actionText">
{{actionText}} {{ actionText }}
</template> </template>
<span <span
v-if="actionTextHtml" v-if="actionTextHtml"
...@@ -95,7 +95,8 @@ ...@@ -95,7 +95,8 @@
<i <i
class="fa fa-spinner fa-spin editing-spinner" class="fa fa-spinner fa-spin editing-spinner"
aria-label="Comment is being updated" aria-label="Comment is being updated"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</span> </span>
</span> </span>
......
...@@ -13,17 +13,6 @@ ...@@ -13,17 +13,6 @@
import autosave from '../mixins/autosave'; import autosave from '../mixins/autosave';
export default { export default {
props: {
note: {
type: Object,
required: true,
},
},
data() {
return {
isReplying: false,
};
},
components: { components: {
noteableNote, noteableNote,
userAvatarLink, userAvatarLink,
...@@ -37,6 +26,17 @@ ...@@ -37,6 +26,17 @@
mixins: [ mixins: [
autosave, autosave,
], ],
props: {
note: {
type: Object,
required: true,
},
},
data() {
return {
isReplying: false,
};
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getNoteableData', 'getNoteableData',
...@@ -72,6 +72,20 @@ ...@@ -72,6 +72,20 @@
return null; return null;
}, },
}, },
mounted() {
if (this.isReplying) {
this.initAutoSave();
}
},
updated() {
if (this.isReplying) {
if (!this.autosave) {
this.initAutoSave();
} else {
this.setAutoSave();
}
}
},
methods: { methods: {
...mapActions([ ...mapActions([
'saveNote', 'saveNote',
...@@ -139,20 +153,6 @@ Please check your network connection and try again.`; ...@@ -139,20 +153,6 @@ Please check your network connection and try again.`;
}); });
}, },
}, },
mounted() {
if (this.isReplying) {
this.initAutoSave();
}
},
updated() {
if (this.isReplying) {
if (!this.autosave) {
this.initAutoSave();
} else {
this.setAutoSave();
}
}
},
}; };
</script> </script>
...@@ -209,7 +209,9 @@ Please check your network connection and try again.`; ...@@ -209,7 +209,9 @@ Please check your network connection and try again.`;
@click="showReplyForm" @click="showReplyForm"
type="button" type="button"
class="js-vue-discussion-reply btn btn-text-field" class="js-vue-discussion-reply btn btn-text-field"
title="Add a reply">Reply...</button> title="Add a reply">
Reply...
</button>
<note-form <note-form
v-if="isReplying" v-if="isReplying"
save-button-title="Comment" save-button-title="Comment"
...@@ -226,6 +228,5 @@ Please check your network connection and try again.`; ...@@ -226,6 +228,5 @@ Please check your network connection and try again.`;
</div> </div>
</div> </div>
</div> </div>
</div>
</li> </li>
</template> </template>
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
components: {
userAvatarLink,
noteHeader,
noteActions,
noteBody,
},
props: { props: {
note: { note: {
type: Object, type: Object,
...@@ -22,12 +28,6 @@ ...@@ -22,12 +28,6 @@
isRequesting: false, isRequesting: false,
}; };
}, },
components: {
userAvatarLink,
noteHeader,
noteActions,
noteBody,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'targetNoteHash', 'targetNoteHash',
...@@ -51,6 +51,16 @@ ...@@ -51,6 +51,16 @@
return `note_${this.note.id}`; return `note_${this.note.id}`;
}, },
}, },
created() {
eventHub.$on('enterEditMode', ({ noteId }) => {
if (noteId === this.note.id) {
this.isEditing = true;
this.scrollToNoteIfNeeded($(this.$el));
}
});
},
methods: { methods: {
...mapActions([ ...mapActions([
'deleteNote', 'deleteNote',
...@@ -126,14 +136,6 @@ ...@@ -126,14 +136,6 @@
this.$refs.noteBody.$refs.noteForm.note = noteText; this.$refs.noteBody.$refs.noteForm.note = noteText;
}, },
}, },
created() {
eventHub.$on('enterEditMode', ({ noteId }) => {
if (noteId === this.note.id) {
this.isEditing = true;
this.scrollToNoteIfNeeded($(this.$el));
}
});
},
}; };
</script> </script>
......
...@@ -13,7 +13,16 @@ ...@@ -13,7 +13,16 @@
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
name: 'notesApp', name: 'NotesApp',
components: {
noteableNote,
noteableDiscussion,
systemNote,
commentForm,
loadingIcon,
placeholderNote,
placeholderSystemNote,
},
props: { props: {
noteableData: { noteableData: {
type: Object, type: Object,
...@@ -26,7 +35,7 @@ ...@@ -26,7 +35,7 @@
userData: { userData: {
type: Object, type: Object,
required: false, required: false,
default: {}, default: () => ({}),
}, },
}, },
store, store,
...@@ -35,21 +44,30 @@ ...@@ -35,21 +44,30 @@
isLoading: true, isLoading: true,
}; };
}, },
components: {
noteableNote,
noteableDiscussion,
systemNote,
commentForm,
loadingIcon,
placeholderNote,
placeholderSystemNote,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'notes', 'notes',
'getNotesDataByProp', 'getNotesDataByProp',
]), ]),
}, },
created() {
this.setNotesData(this.notesData);
this.setNoteableData(this.noteableData);
this.setUserData(this.userData);
},
mounted() {
this.fetchNotes();
const parentElement = this.$el.parentElement;
if (parentElement &&
parentElement.classList.contains('js-vue-notes-event')) {
parentElement.addEventListener('toggleAward', (event) => {
const { awardName, noteId } = event.detail;
this.actionToggleAward({ awardName, noteId });
});
}
},
methods: { methods: {
...mapActions({ ...mapActions({
actionFetchNotes: 'fetchNotes', actionFetchNotes: 'fetchNotes',
...@@ -105,24 +123,6 @@ ...@@ -105,24 +123,6 @@
} }
}, },
}, },
created() {
this.setNotesData(this.notesData);
this.setNoteableData(this.noteableData);
this.setUserData(this.userData);
},
mounted() {
this.fetchNotes();
const parentElement = this.$el.parentElement;
if (parentElement &&
parentElement.classList.contains('js-vue-notes-event')) {
parentElement.addEventListener('toggleAward', (event) => {
const { awardName, noteId } = event.detail;
this.actionToggleAward({ awardName, noteId });
});
}
},
}; };
</script> </script>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import page from './page/index.vue'; import page from './page/index.vue';
export default { export default {
components: { page },
props: { props: {
pdf: { pdf: {
type: [String, Uint8Array], type: [String, Uint8Array],
...@@ -17,8 +18,6 @@ ...@@ -17,8 +18,6 @@
pages: [], pages: [],
}; };
}, },
components: { page },
watch: { pdf: 'load' },
computed: { computed: {
document() { document() {
return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf }; return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf };
...@@ -27,6 +26,11 @@ ...@@ -27,6 +26,11 @@
return this.pdf && this.pdf.length > 0; return this.pdf && this.pdf.length > 0;
}, },
}, },
watch: { pdf: 'load' },
mounted() {
pdfjsLib.PDFJS.workerSrc = workerSrc;
if (this.hasPDF) this.load();
},
methods: { methods: {
load() { load() {
this.pages = []; this.pages = [];
...@@ -47,20 +51,20 @@ ...@@ -47,20 +51,20 @@
return Promise.all(pagePromises); return Promise.all(pagePromises);
}, },
}, },
mounted() {
pdfjsLib.PDFJS.workerSrc = workerSrc;
if (this.hasPDF) this.load();
},
}; };
</script> </script>
<template> <template>
<div class="pdf-viewer" v-if="hasPDF"> <div
<page v-for="(page, index) in pages" class="pdf-viewer"
v-if="hasPDF">
<page
v-for="(page, index) in pages"
:key="index" :key="index"
:v-if="!loading" :v-if="!loading"
:page="page" :page="page"
:number="index + 1" /> :number="index + 1"
/>
</div> </div>
</template> </template>
......
...@@ -32,6 +32,20 @@ ...@@ -32,6 +32,20 @@
return !!(this.customInputEnabled || !this.intervalIsPreset); return !!(this.customInputEnabled || !this.intervalIsPreset);
}, },
}, },
watch: {
cronInterval() {
// updates field validation state when model changes, as
// glFieldError only updates on input.
this.$nextTick(() => {
gl.pipelineScheduleFieldErrors.updateFormValidityState();
});
},
},
created() {
if (this.intervalIsPreset) {
this.enableCustomInput = false;
}
},
methods: { methods: {
toggleCustomInput(shouldEnable) { toggleCustomInput(shouldEnable) {
this.customInputEnabled = shouldEnable; this.customInputEnabled = shouldEnable;
...@@ -43,20 +57,6 @@ ...@@ -43,20 +57,6 @@
} }
}, },
}, },
created() {
if (this.intervalIsPreset) {
this.enableCustomInput = false;
}
},
watch: {
cronInterval() {
// updates field validation state when model changes, as
// glFieldError only updates on input.
this.$nextTick(() => {
gl.pipelineScheduleFieldErrors.updateFormValidityState();
});
},
},
}; };
</script> </script>
...@@ -78,7 +78,12 @@ ...@@ -78,7 +78,12 @@
</label> </label>
<span class="cron-syntax-link-wrap"> <span class="cron-syntax-link-wrap">
(<a :href="cronSyntaxUrl" target="_blank">{{ __('Cron syntax') }}</a>) (<a
:href="cronSyntaxUrl"
target="_blank"
>
{{ __('Cron syntax') }}
</a>)
</span> </span>
</div> </div>
...@@ -93,7 +98,10 @@ ...@@ -93,7 +98,10 @@
@click="toggleCustomInput(false)" @click="toggleCustomInput(false)"
/> />
<label class="label-light" for="every-day"> <label
class="label-light"
for="every-day"
>
{{ __('Every day (at 4:00am)') }} {{ __('Every day (at 4:00am)') }}
</label> </label>
</div> </div>
...@@ -109,7 +117,10 @@ ...@@ -109,7 +117,10 @@
@click="toggleCustomInput(false)" @click="toggleCustomInput(false)"
/> />
<label class="label-light" for="every-week"> <label
class="label-light"
for="every-week"
>
{{ __('Every week (Sundays at 4:00am)') }} {{ __('Every week (Sundays at 4:00am)') }}
</label> </label>
</div> </div>
...@@ -125,7 +136,10 @@ ...@@ -125,7 +136,10 @@
@click="toggleCustomInput(false)" @click="toggleCustomInput(false)"
/> />
<label class="label-light" for="every-month"> <label
class="label-light"
for="every-month"
>
{{ __('Every month (on the 1st at 4:00am)') }} {{ __('Every month (on the 1st at 4:00am)') }}
</label> </label>
</div> </div>
......
...@@ -16,15 +16,15 @@ ...@@ -16,15 +16,15 @@
calloutDismissed: Cookies.get(cookieKey) === 'true', calloutDismissed: Cookies.get(cookieKey) === 'true',
}; };
}, },
created() {
this.illustrationSvg = illustrationSvg;
},
methods: { methods: {
dismissCallout() { dismissCallout() {
this.calloutDismissed = true; this.calloutDismissed = true;
Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 }); Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
}, },
}, },
created() {
this.illustrationSvg = illustrationSvg;
},
}; };
</script> </script>
<template> <template>
...@@ -41,7 +41,10 @@ ...@@ -41,7 +41,10 @@
class="fa fa-times"> class="fa fa-times">
</i> </i>
</button> </button>
<div class="svg-container" v-html="illustrationSvg"></div> <div
class="svg-container"
v-html="illustrationSvg">
</div>
<div class="user-callout-copy"> <div class="user-callout-copy">
<h4>{{ __('Scheduling Pipelines') }}</h4> <h4>{{ __('Scheduling Pipelines') }}</h4>
<p> <p>
...@@ -51,7 +54,10 @@ ...@@ -51,7 +54,10 @@
<a <a
:href="docsUrl" :href="docsUrl"
target="_blank" target="_blank"
rel="nofollow">{{ s__('Learn more in the|pipeline schedules documentation') }}</a>. <!-- oneline to prevent extra space before period --> rel="nofollow"
>
{{ s__('Learn more in the|pipeline schedules documentation') }}</a>.
<!-- oneline to prevent extra space before period -->
</p> </p>
</div> </div>
</div> </div>
......
<script> <script>
/* eslint-disable no-new, no-alert */ /* eslint-disable no-alert */
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
directives: {
tooltip,
},
components: {
loadingIcon,
},
props: { props: {
endpoint: { endpoint: {
type: String, type: String,
...@@ -26,14 +32,9 @@ export default { ...@@ -26,14 +32,9 @@ export default {
confirmActionMessage: { confirmActionMessage: {
type: String, type: String,
required: false, required: false,
default: '',
}, },
}, },
directives: {
tooltip,
},
components: {
loadingIcon,
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
...@@ -49,9 +50,9 @@ export default { ...@@ -49,9 +50,9 @@ export default {
}, },
methods: { methods: {
onClick() { onClick() {
if (this.confirmActionMessage && confirm(this.confirmActionMessage)) { if (this.confirmActionMessage !== '' && confirm(this.confirmActionMessage)) {
this.makeRequest(); this.makeRequest();
} else if (!this.confirmActionMessage) { } else if (this.confirmActionMessage === '') {
this.makeRequest(); this.makeRequest();
} }
}, },
...@@ -61,7 +62,7 @@ export default { ...@@ -61,7 +62,7 @@ export default {
eventHub.$emit('postAction', this.endpoint); eventHub.$emit('postAction', this.endpoint);
}, },
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -7,6 +7,14 @@ ...@@ -7,6 +7,14 @@
* TODO: Remove UJS from here and use an async request instead. * TODO: Remove UJS from here and use an async request instead.
*/ */
export default { export default {
components: {
icon,
},
directives: {
tooltip,
},
props: { props: {
tooltipText: { tooltipText: {
type: String, type: String,
...@@ -29,14 +37,6 @@ ...@@ -29,14 +37,6 @@
}, },
}, },
components: {
icon,
},
directives: {
tooltip,
},
computed: { computed: {
cssClass() { cssClass() {
const actionIconDash = dasherize(this.actionIcon); const actionIconDash = dasherize(this.actionIcon);
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
:href="link" :href="link"
class="ci-action-icon-container ci-action-icon-wrapper" class="ci-action-icon-container ci-action-icon-wrapper"
:class="cssClass" :class="cssClass"
data-container="body"> data-container="body"
<icon :name="actionIcon"/> >
<icon :name="actionIcon" />
</a> </a>
</template> </template>
...@@ -7,6 +7,13 @@ ...@@ -7,6 +7,13 @@
* TODO: Remove UJS from here and use an async request instead. * TODO: Remove UJS from here and use an async request instead.
*/ */
export default { export default {
components: {
icon,
},
directives: {
tooltip,
},
props: { props: {
tooltipText: { tooltipText: {
type: String, type: String,
...@@ -28,14 +35,6 @@ ...@@ -28,14 +35,6 @@
required: true, required: true,
}, },
}, },
components: {
icon,
},
directives: {
tooltip,
},
}; };
</script> </script>
<template> <template>
...@@ -47,7 +46,8 @@ ...@@ -47,7 +46,8 @@
rel="nofollow" rel="nofollow"
class="ci-action-icon-wrapper js-ci-status-icon" class="ci-action-icon-wrapper js-ci-status-icon"
data-container="body" data-container="body"
aria-label="Job's action"> aria-label="Job's action"
<icon :name="actionIcon"/> >
<icon :name="actionIcon" />
</a> </a>
</template> </template>
...@@ -27,13 +27,6 @@ ...@@ -27,13 +27,6 @@
* } * }
*/ */
export default { export default {
props: {
job: {
type: Object,
required: true,
},
},
directives: { directives: {
tooltip, tooltip,
}, },
...@@ -43,12 +36,23 @@ ...@@ -43,12 +36,23 @@
jobNameComponent, jobNameComponent,
}, },
props: {
job: {
type: Object,
required: true,
},
},
computed: { computed: {
tooltipText() { tooltipText() {
return `${this.job.name} - ${this.job.status.label}`; return `${this.job.name} - ${this.job.status.label}`;
}, },
}, },
mounted() {
this.stopDropdownClickPropagation();
},
methods: { methods: {
/** /**
* When the user right clicks or cmd/ctrl + click in the job name * When the user right clicks or cmd/ctrl + click in the job name
...@@ -66,10 +70,6 @@ ...@@ -66,10 +70,6 @@
}); });
}, },
}, },
mounted() {
this.stopDropdownClickPropagation();
},
}; };
</script> </script>
<template> <template>
...@@ -84,17 +84,20 @@ ...@@ -84,17 +84,20 @@
<job-name-component <job-name-component
:name="job.name" :name="job.name"
:status="job.status" /> :status="job.status"
/>
<span class="dropdown-counter-badge"> <span class="dropdown-counter-badge">
{{job.size}} {{ job.size }}
</span> </span>
</button> </button>
<ul class="dropdown-menu big-pipeline-graph-dropdown-menu js-grouped-pipeline-dropdown"> <ul class="dropdown-menu big-pipeline-graph-dropdown-menu js-grouped-pipeline-dropdown">
<li class="scrollable-menu"> <li class="scrollable-menu">
<ul> <ul>
<li v-for="item in job.jobs"> <li
v-for="(item, i) in job.jobs"
:key="i">
<job-component <job-component
:job="item" :job="item"
:is-dropdown="true" :is-dropdown="true"
......
<script> <script>
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import '~/flash';
import stageColumnComponent from './stage_column_component.vue'; import stageColumnComponent from './stage_column_component.vue';
export default { export default {
components: {
stageColumnComponent,
loadingIcon,
},
props: { props: {
isLoading: { isLoading: {
type: Boolean, type: Boolean,
...@@ -15,11 +19,6 @@ ...@@ -15,11 +19,6 @@
}, },
}, },
components: {
stageColumnComponent,
loadingIcon,
},
computed: { computed: {
graph() { graph() {
return this.pipeline.details && this.pipeline.details.stages; return this.pipeline.details && this.pipeline.details.stages;
...@@ -70,7 +69,8 @@ ...@@ -70,7 +69,8 @@
:jobs="stage.groups" :jobs="stage.groups"
:key="stage.name" :key="stage.name"
:stage-connector-class="stageConnectorClass(index, stage)" :stage-connector-class="stageConnectorClass(index, stage)"
:is-first-column="isFirstColumn(index)"/> :is-first-column="isFirstColumn(index)"
/>
</ul> </ul>
</div> </div>
</div> </div>
......
...@@ -29,6 +29,15 @@ ...@@ -29,6 +29,15 @@
*/ */
export default { export default {
components: {
actionComponent,
dropdownActionComponent,
jobNameComponent,
},
directives: {
tooltip,
},
props: { props: {
job: { job: {
type: Object, type: Object,
...@@ -48,16 +57,6 @@ ...@@ -48,16 +57,6 @@
}, },
}, },
components: {
actionComponent,
dropdownActionComponent,
jobNameComponent,
},
directives: {
tooltip,
},
computed: { computed: {
status() { status() {
return this.job && this.job.status ? this.job.status : {}; return this.job && this.job.status ? this.job.status : {};
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
* - Dropdown badge components * - Dropdown badge components
*/ */
export default { export default {
components: {
ciIcon,
},
props: { props: {
name: { name: {
type: String, type: String,
...@@ -19,19 +22,14 @@ ...@@ -19,19 +22,14 @@
required: true, required: true,
}, },
}, },
components: {
ciIcon,
},
}; };
</script> </script>
<template> <template>
<span class="ci-job-name-component"> <span class="ci-job-name-component">
<ci-icon <ci-icon :status="status" />
:status="status" />
<span class="ci-status-text"> <span class="ci-status-text">
{{name}} {{ name }}
</span> </span>
</span> </span>
</template> </template>
<script> <script>
import jobComponent from './job_component.vue'; import jobComponent from './job_component.vue';
import dropdownJobComponent from './dropdown_job_component.vue'; import dropdownJobComponent from './dropdown_job_component.vue';
export default {
components: {
jobComponent,
dropdownJobComponent,
},
export default {
props: { props: {
title: { title: {
type: String, type: String,
...@@ -27,11 +32,6 @@ export default { ...@@ -27,11 +32,6 @@ export default {
}, },
}, },
components: {
jobComponent,
dropdownJobComponent,
},
methods: { methods: {
firstJob(list) { firstJob(list) {
return list[0]; return list[0];
...@@ -45,14 +45,14 @@ export default { ...@@ -45,14 +45,14 @@ export default {
return index === 0 && !this.isFirstColumn ? 'left-connector' : ''; return index === 0 && !this.isFirstColumn ? 'left-connector' : '';
}, },
}, },
}; };
</script> </script>
<template> <template>
<li <li
class="stage-column" class="stage-column"
:class="stageConnectorClass"> :class="stageConnectorClass">
<div class="stage-name"> <div class="stage-name">
{{title}} {{ title }}
</div> </div>
<div class="builds-container"> <div class="builds-container">
<ul> <ul>
...@@ -61,7 +61,8 @@ export default { ...@@ -61,7 +61,8 @@ export default {
:key="job.id" :key="job.id"
class="build" class="build"
:class="buildConnnectorClass(index)" :class="buildConnnectorClass(index)"
:id="jobId(job)"> :id="jobId(job)"
>
<div class="curve"></div> <div class="curve"></div>
......
<script> <script>
import ciHeader from '../../vue_shared/components/header_ci_component.vue'; import ciHeader from '../../vue_shared/components/header_ci_component.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
name: 'PipelineHeaderSection', name: 'PipelineHeaderSection',
components: {
ciHeader,
loadingIcon,
},
props: { props: {
pipeline: { pipeline: {
type: Object, type: Object,
...@@ -15,11 +19,6 @@ export default { ...@@ -15,11 +19,6 @@ export default {
required: true, required: true,
}, },
}, },
components: {
ciHeader,
loadingIcon,
},
data() { data() {
return { return {
actions: this.getActions(), actions: this.getActions(),
...@@ -35,6 +34,12 @@ export default { ...@@ -35,6 +34,12 @@ export default {
}, },
}, },
watch: {
pipeline() {
this.actions = this.getActions();
},
},
methods: { methods: {
postAction(action) { postAction(action) {
const index = this.actions.indexOf(action); const index = this.actions.indexOf(action);
...@@ -70,13 +75,7 @@ export default { ...@@ -70,13 +75,7 @@ export default {
return actions; return actions;
}, },
}, },
};
watch: {
pipeline() {
this.actions = this.getActions();
},
},
};
</script> </script>
<template> <template>
<div class="pipeline-header-container"> <div class="pipeline-header-container">
...@@ -92,6 +91,7 @@ export default { ...@@ -92,6 +91,7 @@ export default {
/> />
<loading-icon <loading-icon
v-if="isLoading" v-if="isLoading"
size="2"/> size="2"
/>
</div> </div>
</template> </template>
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
import popover from '../../vue_shared/directives/popover'; import popover from '../../vue_shared/directives/popover';
export default { export default {
components: {
userAvatarLink,
},
directives: {
tooltip,
popover,
},
props: { props: {
pipeline: { pipeline: {
type: Object, type: Object,
...@@ -14,13 +21,6 @@ ...@@ -14,13 +21,6 @@
required: true, required: true,
}, },
}, },
components: {
userAvatarLink,
},
directives: {
tooltip,
popover,
},
computed: { computed: {
user() { user() {
return this.pipeline.user; return this.pipeline.user;
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<a <a
:href="pipeline.path" :href="pipeline.path"
class="js-pipeline-url-link"> class="js-pipeline-url-link">
<span class="pipeline-id">#{{pipeline.id}}</span> <span class="pipeline-id">#{{ pipeline.id }}</span>
</a> </a>
<span>by</span> <span>by</span>
<user-avatar-link <user-avatar-link
......
...@@ -13,6 +13,15 @@ ...@@ -13,6 +13,15 @@
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
export default { export default {
components: {
tablePagination,
navigationTabs,
navigationControls,
},
mixins: [
pipelinesMixin,
CIPaginationMixin,
],
props: { props: {
store: { store: {
type: Object, type: Object,
...@@ -28,15 +37,6 @@ ...@@ -28,15 +37,6 @@
default: 'root', default: 'root',
}, },
}, },
components: {
tablePagination,
navigationTabs,
navigationControls,
},
mixins: [
pipelinesMixin,
CIPaginationMixin,
],
data() { data() {
const pipelinesData = document.querySelector('#pipelines-list-vue').dataset; const pipelinesData = document.querySelector('#pipelines-list-vue').dataset;
...@@ -247,7 +247,8 @@ ...@@ -247,7 +247,8 @@
<div <div
class="blank-state-row" class="blank-state-row"
v-if="shouldRenderNoPipelinesMessage"> v-if="shouldRenderNoPipelinesMessage"
>
<div class="blank-state-center"> <div class="blank-state-center">
<h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2>
</div> </div>
...@@ -255,7 +256,8 @@ ...@@ -255,7 +256,8 @@
<div <div
class="table-holder" class="table-holder"
v-if="shouldRenderTable"> v-if="shouldRenderTable"
>
<pipelines-table-component <pipelines-table-component
:pipelines="state.pipelines" :pipelines="state.pipelines"
......
...@@ -5,18 +5,18 @@ ...@@ -5,18 +5,18 @@
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default { export default {
props: {
actions: {
type: Array,
required: true,
},
},
directives: { directives: {
tooltip, tooltip,
}, },
components: { components: {
loadingIcon, loadingIcon,
}, },
props: {
actions: {
type: Array,
required: true,
},
},
data() { data() {
return { return {
playIconSvg, playIconSvg,
...@@ -50,7 +50,8 @@ ...@@ -50,7 +50,8 @@
data-toggle="dropdown" data-toggle="dropdown"
data-placement="top" data-placement="top"
aria-label="Manual job" aria-label="Manual job"
:disabled="isLoading"> :disabled="isLoading"
>
<span v-html="playIconSvg"></span> <span v-html="playIconSvg"></span>
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
...@@ -60,14 +61,18 @@ ...@@ -60,14 +61,18 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-align-right"> <ul class="dropdown-menu dropdown-menu-align-right">
<li v-for="action in actions"> <li
v-for="(action, i) in actions"
:key="i"
>
<button <button
type="button" type="button"
class="js-pipeline-action-link no-btn btn" class="js-pipeline-action-link no-btn btn"
@click="onClickAction(action.path)" @click="onClickAction(action.path)"
:class="{ disabled: isActionDisabled(action) }" :class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"> :disabled="isActionDisabled(action)"
{{action.name}} >
{{ action.name }}
</button> </button>
</li> </li>
</ul> </ul>
......
...@@ -3,46 +3,50 @@ ...@@ -3,46 +3,50 @@
import icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
export default { export default {
props: {
artifacts: {
type: Array,
required: true,
},
},
directives: { directives: {
tooltip, tooltip,
}, },
components: { components: {
icon, icon,
}, },
props: {
artifacts: {
type: Array,
required: true,
},
},
}; };
</script> </script>
<template> <template>
<div <div
class="btn-group" class="btn-group"
role="group"> role="group"
>
<button <button
v-tooltip v-tooltip
class="dropdown-toggle btn btn-default build-artifacts js-pipeline-dropdown-download" class="dropdown-toggle btn btn-default build-artifacts js-pipeline-dropdown-download"
title="Artifacts" title="Artifacts"
data-placement="top" data-placement="top"
data-toggle="dropdown" data-toggle="dropdown"
aria-label="Artifacts"> aria-label="Artifacts"
<icon >
name="download"> <icon name="download" />
</icon>
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</button> </button>
<ul class="dropdown-menu dropdown-menu-align-right"> <ul class="dropdown-menu dropdown-menu-align-right">
<li v-for="artifact in artifacts"> <li
v-for="(artifact, i) in artifacts"
:key="i">
<a <a
rel="nofollow" rel="nofollow"
download download
:href="artifact.path"> :href="artifact.path"
Download {{artifact.name}} artifacts >
Download {{ artifact.name }} artifacts
</a> </a>
</li> </li>
</ul> </ul>
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* Given an array of objects, renders a table. * Given an array of objects, renders a table.
*/ */
export default { export default {
components: {
pipelinesTableRowComponent,
},
props: { props: {
pipelines: { pipelines: {
type: Array, type: Array,
...@@ -26,34 +29,36 @@ ...@@ -26,34 +29,36 @@
required: true, required: true,
}, },
}, },
components: {
pipelinesTableRowComponent,
},
}; };
</script> </script>
<template> <template>
<div class="ci-table"> <div class="ci-table">
<div <div
class="gl-responsive-table-row table-row-header" class="gl-responsive-table-row table-row-header"
role="row"> role="row"
>
<div <div
class="table-section section-10 js-pipeline-status pipeline-status" class="table-section section-10 js-pipeline-status pipeline-status"
role="rowheader"> role="rowheader"
>
Status Status
</div> </div>
<div <div
class="table-section section-15 js-pipeline-info pipeline-info" class="table-section section-15 js-pipeline-info pipeline-info"
role="rowheader"> role="rowheader"
>
Pipeline Pipeline
</div> </div>
<div <div
class="table-section section-25 js-pipeline-commit pipeline-commit" class="table-section section-25 js-pipeline-commit pipeline-commit"
role="rowheader"> role="rowheader"
>
Commit Commit
</div> </div>
<div <div
class="table-section section-15 js-pipeline-stages pipeline-stages" class="table-section section-15 js-pipeline-stages pipeline-stages"
role="rowheader"> role="rowheader"
>
Stages Stages
</div> </div>
</div> </div>
......
<script> <script>
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
import asyncButtonComponent from './async_button.vue'; import asyncButtonComponent from './async_button.vue';
import pipelinesActionsComponent from './pipelines_actions.vue'; import pipelinesActionsComponent from './pipelines_actions.vue';
import pipelinesArtifactsComponent from './pipelines_artifacts.vue'; import pipelinesArtifactsComponent from './pipelines_artifacts.vue';
import ciBadge from '../../vue_shared/components/ci_badge_link.vue'; import ciBadge from '../../vue_shared/components/ci_badge_link.vue';
import pipelineStage from './stage.vue'; import pipelineStage from './stage.vue';
import pipelineUrl from './pipeline_url.vue'; import pipelineUrl from './pipeline_url.vue';
import pipelinesTimeago from './time_ago.vue'; import pipelinesTimeago from './time_ago.vue';
import commitComponent from '../../vue_shared/components/commit.vue'; import commitComponent from '../../vue_shared/components/commit.vue';
/** /**
* Pipeline table row. * Pipeline table row.
* *
* Given the received object renders a table row in the pipelines' table. * Given the received object renders a table row in the pipelines' table.
*/ */
export default { export default {
components: {
asyncButtonComponent,
pipelinesActionsComponent,
pipelinesArtifactsComponent,
commitComponent,
pipelineStage,
pipelineUrl,
ciBadge,
pipelinesTimeago,
},
props: { props: {
pipeline: { pipeline: {
type: Object, type: Object,
...@@ -34,16 +44,6 @@ export default { ...@@ -34,16 +44,6 @@ export default {
required: true, required: true,
}, },
}, },
components: {
asyncButtonComponent,
pipelinesActionsComponent,
pipelinesArtifactsComponent,
commitComponent,
pipelineStage,
pipelineUrl,
ciBadge,
pipelinesTimeago,
},
computed: { computed: {
/** /**
* If provided, returns the commit tag. * If provided, returns the commit tag.
...@@ -216,12 +216,13 @@ export default { ...@@ -216,12 +216,13 @@ export default {
return this.viewType === 'child'; return this.viewType === 'child';
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="commit gl-responsive-table-row"> <div class="commit gl-responsive-table-row">
<div class="table-section section-10 commit-link"> <div class="table-section section-10 commit-link">
<div class="table-mobile-header" <div
class="table-mobile-header"
role="rowheader"> role="rowheader">
Status Status
</div> </div>
...@@ -264,14 +265,17 @@ export default { ...@@ -264,14 +265,17 @@ export default {
Stages Stages
</div> </div>
<div class="table-mobile-content"> <div class="table-mobile-content">
<div class="stage-container dropdown js-mini-pipeline-graph" <template v-if="pipeline.details.stages.length > 0">
v-if="pipeline.details.stages.length > 0" <div
v-for="stage in pipeline.details.stages"> class="stage-container dropdown js-mini-pipeline-graph"
v-for="(stage, index) in pipeline.details.stages"
:key="index">
<pipeline-stage <pipeline-stage
:stage="stage" :stage="stage"
:update-dropdown="updateGraphDropdown" :update-dropdown="updateGraphDropdown"
/> />
</div> </div>
</template>
</div> </div>
</div> </div>
......
<script> <script>
/** /**
* Renders each stage of the pipeline mini graph. * Renders each stage of the pipeline mini graph.
* *
* Given the provided endpoint will make a request to * Given the provided endpoint will make a request to
...@@ -13,12 +13,21 @@ ...@@ -13,12 +13,21 @@
* 4. Commit widget * 4. Commit widget
*/ */
import Flash from '../../flash'; import Flash from '../../flash';
import icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
export default {
components: {
loadingIcon,
icon,
},
directives: {
tooltip,
},
export default {
props: { props: {
stage: { stage: {
type: Object, type: Object,
...@@ -32,10 +41,6 @@ export default { ...@@ -32,10 +41,6 @@ export default {
}, },
}, },
directives: {
tooltip,
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
...@@ -43,15 +48,20 @@ export default { ...@@ -43,15 +48,20 @@ export default {
}; };
}, },
components: { computed: {
loadingIcon, dropdownClass() {
icon, return this.dropdownContent.length > 0 ?
'js-builds-dropdown-container' :
'js-builds-dropdown-loading';
}, },
updated() { triggerButtonClass() {
if (this.dropdownContent.length > 0) { return `ci-status-icon-${this.stage.status.group}`;
this.stopDropdownClickPropagation(); },
}
borderlessIcon() {
return `${this.stage.status.icon}_borderless`;
},
}, },
watch: { watch: {
...@@ -64,6 +74,12 @@ export default { ...@@ -64,6 +74,12 @@ export default {
}, },
}, },
updated() {
if (this.dropdownContent.length > 0) {
this.stopDropdownClickPropagation();
}
},
methods: { methods: {
onClickStage() { onClickStage() {
if (!this.isDropdownOpen()) { if (!this.isDropdownOpen()) {
...@@ -113,23 +129,7 @@ export default { ...@@ -113,23 +129,7 @@ export default {
return this.$el.classList.contains('open'); return this.$el.classList.contains('open');
}, },
}, },
};
computed: {
dropdownClass() {
return this.dropdownContent.length > 0 ?
'js-builds-dropdown-container' :
'js-builds-dropdown-loading';
},
triggerButtonClass() {
return `ci-status-icon-${this.stage.status.group}`;
},
borderlessIcon() {
return `${this.stage.status.icon}_borderless`;
},
},
};
</script> </script>
<template> <template>
...@@ -145,36 +145,41 @@ export default { ...@@ -145,36 +145,41 @@ export default {
type="button" type="button"
id="stageDropdown" id="stageDropdown"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false"
>
<span <span
aria-hidden="true" aria-hidden="true"
:aria-label="stage.title"> :aria-label="stage.title"
<icon >
:name="borderlessIcon"/> <icon :name="borderlessIcon" />
</span> </span>
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</button> </button>
<ul <ul
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container" class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
aria-labelledby="stageDropdown"> aria-labelledby="stageDropdown"
>
<li <li
:class="dropdownClass" :class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"> class="js-builds-dropdown-list scrollable-menu"
>
<loading-icon v-if="isLoading"/> <loading-icon v-if="isLoading"/>
<ul <ul
v-else v-else
v-html="dropdownContent"> v-html="dropdownContent"
>
</ul> </ul>
</li> </li>
</ul> </ul>
</div> </div>
</script> </template>
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
import timeagoMixin from '../../vue_shared/mixins/timeago'; import timeagoMixin from '../../vue_shared/mixins/timeago';
export default { export default {
directives: {
tooltip,
},
mixins: [
timeagoMixin,
],
props: { props: {
finishedTime: { finishedTime: {
type: String, type: String,
...@@ -15,12 +21,6 @@ ...@@ -15,12 +21,6 @@
required: true, required: true,
}, },
}, },
mixins: [
timeagoMixin,
],
directives: {
tooltip,
},
data() { data() {
return { return {
iconTimerSvg, iconTimerSvg,
...@@ -60,26 +60,29 @@ ...@@ -60,26 +60,29 @@
<div class="table-section section-15 pipelines-time-ago"> <div class="table-section section-15 pipelines-time-ago">
<div <div
class="table-mobile-header" class="table-mobile-header"
role="rowheader"> role="rowheader"
>
Duration Duration
</div> </div>
<div class="table-mobile-content"> <div class="table-mobile-content">
<p <p
class="duration" class="duration"
v-if="hasDuration"> v-if="hasDuration"
<span >
v-html="iconTimerSvg"> <span v-html="iconTimerSvg">
</span> </span>
{{durationFormated}} {{ durationFormated }}
</p> </p>
<p <p
class="finished-at hidden-xs hidden-sm" class="finished-at hidden-xs hidden-sm"
v-if="hasFinishedTime"> v-if="hasFinishedTime"
>
<i <i
class="fa fa-calendar" class="fa fa-calendar"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
<time <time
...@@ -87,9 +90,9 @@ ...@@ -87,9 +90,9 @@
data-placement="top" data-placement="top"
data-container="body" data-container="body"
:title="tooltipTitle(finishedTime)"> :title="tooltipTitle(finishedTime)">
{{timeFormated(finishedTime)}} {{ timeFormated(finishedTime) }}
</time> </time>
</p> </p>
</div> </div>
</div> </div>
</script> </template>
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
import csrf from '../../../lib/utils/csrf'; import csrf from '../../../lib/utils/csrf';
export default { export default {
components: {
modal,
},
props: { props: {
actionUrl: { actionUrl: {
type: String, type: String,
...@@ -25,9 +28,6 @@ ...@@ -25,9 +28,6 @@
isOpen: false, isOpen: false,
}; };
}, },
components: {
modal,
},
computed: { computed: {
csrfToken() { csrfToken() {
return csrf.token; return csrf.token;
...@@ -99,7 +99,9 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -99,7 +99,9 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
@toggle="toggleOpen" @toggle="toggleOpen"
@submit="onSubmit"> @submit="onSubmit">
<template slot="body" slot-scope="props"> <template
slot="body"
slot-scope="props">
<p v-html="props.text"></p> <p v-html="props.text"></p>
<form <form
...@@ -110,13 +112,19 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -110,13 +112,19 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
<input <input
type="hidden" type="hidden"
name="_method" name="_method"
value="delete" /> value="delete"
/>
<input <input
type="hidden" type="hidden"
name="authenticity_token" name="authenticity_token"
:value="csrfToken" /> :value="csrfToken"
/>
<p id="input-label" v-html="inputLabel"></p> <p
id="input-label"
v-html="inputLabel"
>
</p>
<input <input
v-if="confirmWithPassword" v-if="confirmWithPassword"
...@@ -124,14 +132,16 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -124,14 +132,16 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
class="form-control" class="form-control"
type="password" type="password"
v-model="enteredPassword" v-model="enteredPassword"
aria-labelledby="input-label" /> aria-labelledby="input-label"
/>
<input <input
v-else v-else
name="username" name="username"
class="form-control" class="form-control"
type="text" type="text"
v-model="enteredUsername" v-model="enteredUsername"
aria-labelledby="input-label" /> aria-labelledby="input-label"
/>
</form> </form>
</template> </template>
...@@ -140,7 +150,8 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -140,7 +150,8 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
<button <button
type="button" type="button"
class="btn btn-danger" class="btn btn-danger"
@click="toggleOpen(true)"> @click="toggleOpen(true)"
>
{{ s__('Profiles|Delete account') }} {{ s__('Profiles|Delete account') }}
</button> </button>
</div> </div>
......
<script> <script>
import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue';
export default {
components: {
projectFeatureToggle,
},
model: {
prop: 'value',
event: 'change',
},
export default {
props: { props: {
name: { name: {
type: String, type: String,
...@@ -25,10 +34,6 @@ export default { ...@@ -25,10 +34,6 @@ export default {
}, },
}, },
components: {
projectFeatureToggle,
},
computed: { computed: {
featureEnabled() { featureEnabled() {
return this.value !== 0; return this.value !== 0;
...@@ -48,11 +53,6 @@ export default { ...@@ -48,11 +53,6 @@ export default {
}, },
}, },
model: {
prop: 'value',
event: 'change',
},
methods: { methods: {
toggleFeature(featureEnabled) { toggleFeature(featureEnabled) {
if (featureEnabled === false || this.options.length < 1) { if (featureEnabled === false || this.options.length < 1) {
...@@ -67,11 +67,14 @@ export default { ...@@ -67,11 +67,14 @@ export default {
this.$emit('change', Number(e.target.value)); this.$emit('change', Number(e.target.value));
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="project-feature-controls" :data-for="name"> <div
class="project-feature-controls"
:data-for="name"
>
<input <input
v-if="name" v-if="name"
type="hidden" type="hidden"
...@@ -81,7 +84,7 @@ export default { ...@@ -81,7 +84,7 @@ export default {
<project-feature-toggle <project-feature-toggle
:value="featureEnabled" :value="featureEnabled"
@change="toggleFeature" @change="toggleFeature"
:disabledInput="disabledInput" :disabled-input="disabledInput"
/> />
<div class="select-wrapper"> <div class="select-wrapper">
<select <select
...@@ -95,10 +98,14 @@ export default { ...@@ -95,10 +98,14 @@ export default {
:value="optionValue" :value="optionValue"
:selected="optionValue === value" :selected="optionValue === value"
> >
{{optionName}} {{ optionName }}
</option> </option>
</select> </select>
<i aria-hidden="true" class="fa fa-chevron-down"></i> <i
aria-hidden="true"
class="fa fa-chevron-down"
>
</i>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
props: { props: {
label: { label: {
type: String, type: String,
...@@ -17,19 +17,34 @@ export default { ...@@ -17,19 +17,34 @@ export default {
default: null, default: null,
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="project-feature-row"> <div class="project-feature-row">
<label v-if="label" class="label-light"> <label
{{label}} v-if="label"
<a v-if="helpPath" :href="helpPath" target="_blank"> class="label-light"
<i aria-hidden="true" data-hidden="true" class="fa fa-question-circle"></i> >
{{ label }}
<a
v-if="helpPath"
:href="helpPath"
target="_blank"
>
<i
aria-hidden="true"
data-hidden="true"
class="fa fa-question-circle"
>
</i>
</a> </a>
</label> </label>
<span v-if="helpText" class="help-block"> <span
{{helpText}} v-if="helpText"
class="help-block"
>
{{ helpText }}
</span> </span>
<slot /> <slot />
</div> </div>
......
<script> <script>
import projectFeatureSetting from './project_feature_setting.vue'; import projectFeatureSetting from './project_feature_setting.vue';
import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue';
import projectSettingRow from './project_setting_row.vue'; import projectSettingRow from './project_setting_row.vue';
import { visibilityOptions, visibilityLevelDescriptions } from '../constants'; import { visibilityOptions, visibilityLevelDescriptions } from '../constants';
import { toggleHiddenClassBySelector } from '../external'; import { toggleHiddenClassBySelector } from '../external';
export default {
components: {
projectFeatureSetting,
projectFeatureToggle,
projectSettingRow,
},
export default {
props: { props: {
currentSettings: { currentSettings: {
type: Object, type: Object,
...@@ -64,12 +70,6 @@ export default { ...@@ -64,12 +70,6 @@ export default {
return { ...defaults, ...this.currentSettings }; return { ...defaults, ...this.currentSettings };
}, },
components: {
projectFeatureSetting,
projectFeatureToggle,
projectSettingRow,
},
computed: { computed: {
featureAccessLevelOptions() { featureAccessLevelOptions() {
const options = [ const options = [
...@@ -96,19 +96,6 @@ export default { ...@@ -96,19 +96,6 @@ export default {
}, },
}, },
methods: {
highlightChanges() {
this.highlightChangesClass = true;
this.$nextTick(() => {
this.highlightChangesClass = false;
});
},
visibilityAllowed(option) {
return this.allowedVisibilityOptions.includes(option);
},
},
watch: { watch: {
visibilityLevel(value, oldValue) { visibilityLevel(value, oldValue) {
if (value === visibilityOptions.PRIVATE) { if (value === visibilityOptions.PRIVATE) {
...@@ -165,8 +152,20 @@ export default { ...@@ -165,8 +152,20 @@ export default {
else if (oldValue === 0) toggleHiddenClassBySelector('.builds-feature', false); else if (oldValue === 0) toggleHiddenClassBySelector('.builds-feature', false);
}, },
}, },
};
methods: {
highlightChanges() {
this.highlightChangesClass = true;
this.$nextTick(() => {
this.highlightChangesClass = false;
});
},
visibilityAllowed(option) {
return this.allowedVisibilityOptions.includes(option);
},
},
};
</script> </script>
<template> <template>
...@@ -203,22 +202,36 @@ export default { ...@@ -203,22 +202,36 @@ export default {
Public Public
</option> </option>
</select> </select>
<i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"></i> <i
aria-hidden="true"
data-hidden="true"
class="fa fa-chevron-down"
>
</i>
</div> </div>
</div> </div>
<span class="help-block">{{ visibilityLevelDescription }}</span> <span class="help-block">{{ visibilityLevelDescription }}</span>
<label v-if="visibilityLevel !== visibilityOptions.PUBLIC" class="request-access"> <label
v-if="visibilityLevel !== visibilityOptions.PUBLIC"
class="request-access"
>
<input <input
type="hidden" type="hidden"
name="project[request_access_enabled]" name="project[request_access_enabled]"
:value="requestAccessEnabled" :value="requestAccessEnabled"
/> />
<input type="checkbox" v-model="requestAccessEnabled" /> <input
type="checkbox"
v-model="requestAccessEnabled"
/>
Allow users to request access Allow users to request access
</label> </label>
</project-setting-row> </project-setting-row>
</div> </div>
<div class="project-feature-settings" :class="{ 'highlight-changes': highlightChangesClass }"> <div
class="project-feature-settings"
:class="{ 'highlight-changes': highlightChangesClass }"
>
<project-setting-row <project-setting-row
label="Issues" label="Issues"
help-text="Lightweight issue tracking system for this project" help-text="Lightweight issue tracking system for this project"
...@@ -248,7 +261,7 @@ export default { ...@@ -248,7 +261,7 @@ export default {
name="project[project_feature_attributes][merge_requests_access_level]" name="project[project_feature_attributes][merge_requests_access_level]"
:options="repoFeatureAccessLevelOptions" :options="repoFeatureAccessLevelOptions"
v-model="mergeRequestsAccessLevel" v-model="mergeRequestsAccessLevel"
:disabledInput="!repositoryEnabled" :disabled-input="!repositoryEnabled"
/> />
</project-setting-row> </project-setting-row>
<project-setting-row <project-setting-row
...@@ -259,7 +272,7 @@ export default { ...@@ -259,7 +272,7 @@ export default {
name="project[project_feature_attributes][builds_access_level]" name="project[project_feature_attributes][builds_access_level]"
:options="repoFeatureAccessLevelOptions" :options="repoFeatureAccessLevelOptions"
v-model="buildsAccessLevel" v-model="buildsAccessLevel"
:disabledInput="!repositoryEnabled" :disabled-input="!repositoryEnabled"
/> />
</project-setting-row> </project-setting-row>
<project-setting-row <project-setting-row
...@@ -271,7 +284,7 @@ export default { ...@@ -271,7 +284,7 @@ export default {
<project-feature-toggle <project-feature-toggle
name="project[container_registry_enabled]" name="project[container_registry_enabled]"
v-model="containerRegistryEnabled" v-model="containerRegistryEnabled"
:disabledInput="!repositoryEnabled" :disabled-input="!repositoryEnabled"
/> />
</project-setting-row> </project-setting-row>
<project-setting-row <project-setting-row
...@@ -283,7 +296,7 @@ export default { ...@@ -283,7 +296,7 @@ export default {
<project-feature-toggle <project-feature-toggle
name="project[lfs_enabled]" name="project[lfs_enabled]"
v-model="lfsEnabled" v-model="lfsEnabled"
:disabledInput="!repositoryEnabled" :disabled-input="!repositoryEnabled"
/> />
</project-setting-row> </project-setting-row>
</div> </div>
......
...@@ -47,6 +47,22 @@ export default { ...@@ -47,6 +47,22 @@ export default {
return this.store.getSearchedProjects(); return this.store.getSearchedProjects();
}, },
}, },
created() {
if (this.currentProject.id) {
this.logCurrentProjectAccess();
}
eventHub.$on('dropdownOpen', this.fetchFrequentProjects);
eventHub.$on('searchProjects', this.fetchSearchedProjects);
eventHub.$on('searchCleared', this.handleSearchClear);
eventHub.$on('searchFailed', this.handleSearchFailure);
},
beforeDestroy() {
eventHub.$off('dropdownOpen', this.fetchFrequentProjects);
eventHub.$off('searchProjects', this.fetchSearchedProjects);
eventHub.$off('searchCleared', this.handleSearchClear);
eventHub.$off('searchFailed', this.handleSearchFailure);
},
methods: { methods: {
toggleFrequentProjectsList(state) { toggleFrequentProjectsList(state) {
this.isLoadingProjects = !state; this.isLoadingProjects = !state;
...@@ -108,22 +124,6 @@ export default { ...@@ -108,22 +124,6 @@ export default {
this.toggleSearchProjectsList(true); this.toggleSearchProjectsList(true);
}, },
}, },
created() {
if (this.currentProject.id) {
this.logCurrentProjectAccess();
}
eventHub.$on('dropdownOpen', this.fetchFrequentProjects);
eventHub.$on('searchProjects', this.fetchSearchedProjects);
eventHub.$on('searchCleared', this.handleSearchClear);
eventHub.$on('searchFailed', this.handleSearchFailure);
},
beforeDestroy() {
eventHub.$off('dropdownOpen', this.fetchFrequentProjects);
eventHub.$off('searchProjects', this.fetchSearchedProjects);
eventHub.$off('searchCleared', this.handleSearchClear);
eventHub.$off('searchFailed', this.handleSearchFailure);
},
}; };
</script> </script>
......
<script> <script>
import { s__ } from '../../locale'; import { s__ } from '../../locale';
import projectsListItem from './projects_list_item.vue'; import projectsListItem from './projects_list_item.vue';
export default { export default {
components: { components: {
projectsListItem, projectsListItem,
}, },
...@@ -26,7 +26,7 @@ export default { ...@@ -26,7 +26,7 @@ export default {
s__('ProjectsDropdown|Projects you visit often will appear here'); s__('ProjectsDropdown|Projects you visit often will appear here');
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -40,7 +40,7 @@ export default { ...@@ -40,7 +40,7 @@ export default {
class="section-empty" class="section-empty"
v-if="isListEmpty" v-if="isListEmpty"
> >
{{listEmptyMessage}} {{ listEmptyMessage }}
</li> </li>
<projects-list-item <projects-list-item
v-else v-else
......
<script> <script>
import identicon from '../../vue_shared/components/identicon.vue'; import identicon from '../../vue_shared/components/identicon.vue';
export default { export default {
components: { components: {
identicon, identicon,
}, },
...@@ -70,7 +70,7 @@ export default { ...@@ -70,7 +70,7 @@ export default {
return namespace; return namespace;
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -92,7 +92,7 @@ export default { ...@@ -92,7 +92,7 @@ export default {
<identicon <identicon
v-else v-else
size-class="s32" size-class="s32"
:entity-id=projectId :entity-id="projectId"
:entity-name="projectName" :entity-name="projectName"
/> />
</div> </div>
...@@ -108,7 +108,7 @@ export default { ...@@ -108,7 +108,7 @@ export default {
<div <div
class="project-namespace" class="project-namespace"
:title="namespace" :title="namespace"
>{{truncatedNamespace}}</div> >{{ truncatedNamespace }}</div>
</div> </div>
</a> </a>
</li> </li>
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
export default { export default {
data() { data() {
return { return {
searchQuery: '', searchQuery: '',
...@@ -13,6 +13,12 @@ export default { ...@@ -13,6 +13,12 @@ export default {
this.handleInput(); this.handleInput();
}, },
}, },
mounted() {
eventHub.$on('dropdownOpen', this.setFocus);
},
beforeDestroy() {
eventHub.$off('dropdownOpen', this.setFocus);
},
methods: { methods: {
setFocus() { setFocus() {
this.$refs.search.focus(); this.$refs.search.focus();
...@@ -35,13 +41,7 @@ export default { ...@@ -35,13 +41,7 @@ export default {
this.emitSearchEvents(); this.emitSearchEvents();
}, 500), }, 500),
}, },
mounted() { };
eventHub.$on('dropdownOpen', this.setFocus);
},
beforeDestroy() {
eventHub.$off('dropdownOpen', this.setFocus);
},
};
</script> </script>
<template> <template>
......
<script> <script>
/* globals Flash */
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
import '../../flash'; import Flash from '../../flash';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import store from '../stores'; import store from '../stores';
import collapsibleContainer from './collapsible_container.vue'; import collapsibleContainer from './collapsible_container.vue';
import { errorMessages, errorMessagesTypes } from '../constants'; import { errorMessages, errorMessagesTypes } from '../constants';
export default { export default {
name: 'registryListApp', name: 'RegistryListApp',
components: {
collapsibleContainer,
loadingIcon,
},
props: { props: {
endpoint: { endpoint: {
type: String, type: String,
...@@ -16,22 +19,12 @@ ...@@ -16,22 +19,12 @@
}, },
}, },
store, store,
components: {
collapsibleContainer,
loadingIcon,
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'isLoading', 'isLoading',
'repos', 'repos',
]), ]),
}, },
methods: {
...mapActions([
'setMainEndpoint',
'fetchRepos',
]),
},
created() { created() {
this.setMainEndpoint(this.endpoint); this.setMainEndpoint(this.endpoint);
}, },
...@@ -39,6 +32,12 @@ ...@@ -39,6 +32,12 @@
this.fetchRepos() this.fetchRepos()
.catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS])); .catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS]));
}, },
methods: {
...mapActions([
'setMainEndpoint',
'fetchRepos',
]),
},
}; };
</script> </script>
<template> <template>
...@@ -56,7 +55,7 @@ ...@@ -56,7 +55,7 @@
/> />
<p v-else-if="!isLoading && !repos.length"> <p v-else-if="!isLoading && !repos.length">
{{__("No container images stored for this project. Add one by following the instructions above.")}} {{ __("No container images stored for this project. Add one by following the instructions above.") }}
</p> </p>
</div> </div>
</template> </template>
<script> <script>
/* globals Flash */
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import '../../flash'; import Flash from '../../flash';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
...@@ -9,13 +8,7 @@ ...@@ -9,13 +8,7 @@
import { errorMessages, errorMessagesTypes } from '../constants'; import { errorMessages, errorMessagesTypes } from '../constants';
export default { export default {
name: 'collapsibeContainerRegisty', name: 'CollapsibeContainerRegisty',
props: {
repo: {
type: Object,
required: true,
},
},
components: { components: {
clipboardButton, clipboardButton,
loadingIcon, loadingIcon,
...@@ -24,6 +17,12 @@ ...@@ -24,6 +17,12 @@
directives: { directives: {
tooltip, tooltip,
}, },
props: {
repo: {
type: Object,
required: true,
},
},
data() { data() {
return { return {
isOpen: false, isOpen: false,
...@@ -65,21 +64,22 @@ ...@@ -65,21 +64,22 @@
<template> <template>
<div class="container-image"> <div class="container-image">
<div <div class="container-image-head">
class="container-image-head">
<button <button
type="button" type="button"
@click="toggleRepo" @click="toggleRepo"
class="js-toggle-repo btn-link"> class="js-toggle-repo btn-link"
>
<i <i
class="fa" class="fa"
:class="{ :class="{
'fa-chevron-right': !isOpen, 'fa-chevron-right': !isOpen,
'fa-chevron-up': isOpen, 'fa-chevron-up': isOpen,
}" }"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
{{repo.name}} {{ repo.name }}
</button> </button>
<clipboard-button <clipboard-button
...@@ -96,14 +96,15 @@ ...@@ -96,14 +96,15 @@
:title="s__('ContainerRegistry|Remove repository')" :title="s__('ContainerRegistry|Remove repository')"
:aria-label="s__('ContainerRegistry|Remove repository')" :aria-label="s__('ContainerRegistry|Remove repository')"
v-tooltip v-tooltip
@click="handleDeleteRepository"> @click="handleDeleteRepository"
>
<i <i
class="fa fa-trash" class="fa fa-trash"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</button> </button>
</div> </div>
</div> </div>
<loading-icon <loading-icon
...@@ -114,7 +115,8 @@ ...@@ -114,7 +115,8 @@
<div <div
v-else-if="!repo.isLoading && isOpen" v-else-if="!repo.isLoading && isOpen"
class="container-image-tags"> class="container-image-tags"
>
<table-registry <table-registry
v-if="repo.list.length" v-if="repo.list.length"
...@@ -123,8 +125,9 @@ ...@@ -123,8 +125,9 @@
<div <div
v-else v-else
class="nothing-here-block"> class="nothing-here-block"
{{s__("ContainerRegistry|No tags in Container Registry for this container image.")}} >
{{ s__("ContainerRegistry|No tags in Container Registry for this container image.") }}
</div> </div>
</div> </div>
</div> </div>
......
<script> <script>
/* globals Flash */
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { n__ } from '../../locale'; import { n__ } from '../../locale';
import '../../flash'; import Flash from '../../flash';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
...@@ -11,21 +10,21 @@ ...@@ -11,21 +10,21 @@
import { numberToHumanSize } from '../../lib/utils/number_utils'; import { numberToHumanSize } from '../../lib/utils/number_utils';
export default { export default {
props: {
repo: {
type: Object,
required: true,
},
},
components: { components: {
clipboardButton, clipboardButton,
tablePagination, tablePagination,
}, },
directives: {
tooltip,
},
mixins: [ mixins: [
timeagoMixin, timeagoMixin,
], ],
directives: { props: {
tooltip, repo: {
type: Object,
required: true,
},
}, },
computed: { computed: {
shouldRenderPagination() { shouldRenderPagination() {
...@@ -68,14 +67,14 @@ ...@@ -68,14 +67,14 @@
}; };
</script> </script>
<template> <template>
<div> <div>
<table class="table tags"> <table class="table tags">
<thead> <thead>
<tr> <tr>
<th>{{s__('ContainerRegistry|Tag')}}</th> <th>{{ s__('ContainerRegistry|Tag') }}</th>
<th>{{s__('ContainerRegistry|Tag ID')}}</th> <th>{{ s__('ContainerRegistry|Tag ID') }}</th>
<th>{{s__("ContainerRegistry|Size")}}</th> <th>{{ s__("ContainerRegistry|Size") }}</th>
<th>{{s__("ContainerRegistry|Created")}}</th> <th>{{ s__("ContainerRegistry|Created") }}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
...@@ -85,7 +84,7 @@ ...@@ -85,7 +84,7 @@
:key="i"> :key="i">
<td> <td>
{{item.tag}} {{ item.tag }}
<clipboard-button <clipboard-button
v-if="item.location" v-if="item.location"
...@@ -97,20 +96,21 @@ ...@@ -97,20 +96,21 @@
<span <span
v-tooltip v-tooltip
:title="item.revision" :title="item.revision"
data-placement="bottom"> data-placement="bottom"
{{item.shortRevision}} >
{{ item.shortRevision }}
</span> </span>
</td> </td>
<td> <td>
{{formatSize(item.size)}} {{ formatSize(item.size) }}
<template v-if="item.size && item.layers"> <template v-if="item.size && item.layers">
&middot; &middot;
</template> </template>
{{layers(item)}} {{ layers(item) }}
</td> </td>
<td> <td>
{{timeFormated(item.createdAt)}} {{ timeFormated(item.createdAt) }}
</td> </td>
<td class="content"> <td class="content">
...@@ -122,10 +122,12 @@ ...@@ -122,10 +122,12 @@
:aria-label="s__('ContainerRegistry|Remove tag')" :aria-label="s__('ContainerRegistry|Remove tag')"
data-container="body" data-container="body"
v-tooltip v-tooltip
@click="handleDeleteRegistry(item)"> @click="handleDeleteRegistry(item)"
>
<i <i
class="fa fa-trash" class="fa fa-trash"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</button> </button>
</td> </td>
...@@ -138,5 +140,5 @@ ...@@ -138,5 +140,5 @@
:change="onPageChange" :change="onPageChange"
:page-info="repo.pagination" :page-info="repo.pagination"
/> />
</div> </div>
</template> </template>
<script> <script>
import Flash from '../../../flash'; import Flash from '../../../flash';
import editForm from './edit_form.vue'; import editForm from './edit_form.vue';
import Icon from '../../../vue_shared/components/icon.vue'; import Icon from '../../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
editForm, editForm,
Icon, Icon,
...@@ -41,11 +41,11 @@ export default { ...@@ -41,11 +41,11 @@ export default {
.then(() => location.reload()) .then(() => location.reload())
.catch(() => { .catch(() => {
Flash(`Something went wrong trying to Flash(`Something went wrong trying to
change the confidentiality of this issue`); change the confidentiality of this issue`);
}); });
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -54,8 +54,8 @@ change the confidentiality of this issue`); ...@@ -54,8 +54,8 @@ change the confidentiality of this issue`);
<icon <icon
:name="confidentialityIcon" :name="confidentialityIcon"
:size="16" :size="16"
aria-hidden="true"> aria-hidden="true"
</icon> />
</div> </div>
<div class="title hide-collapsed"> <div class="title hide-collapsed">
Confidentiality Confidentiality
...@@ -75,22 +75,26 @@ change the confidentiality of this issue`); ...@@ -75,22 +75,26 @@ change the confidentiality of this issue`);
:is-confidential="isConfidential" :is-confidential="isConfidential"
:update-confidential-attribute="updateConfidentialAttribute" :update-confidential-attribute="updateConfidentialAttribute"
/> />
<div v-if="!isConfidential" class="no-value sidebar-item-value"> <div
v-if="!isConfidential"
class="no-value sidebar-item-value">
<icon <icon
name="eye" name="eye"
:size="16" :size="16"
aria-hidden="true" aria-hidden="true"
class="sidebar-item-icon inline"> class="sidebar-item-icon inline"
</icon> />
Not confidential Not confidential
</div> </div>
<div v-else class="value sidebar-item-value hide-collapsed"> <div
v-else
class="value sidebar-item-value hide-collapsed">
<icon <icon
name="eye-slash" name="eye-slash"
:size="16" :size="16"
aria-hidden="true" aria-hidden="true"
class="sidebar-item-icon inline is-active"> class="sidebar-item-icon inline is-active"
</icon> />
This issue is confidential This issue is confidential
</div> </div>
</div> </div>
......
<script> <script>
import editFormButtons from './edit_form_buttons.vue'; import editFormButtons from './edit_form_buttons.vue';
export default { export default {
components: {
editFormButtons,
},
props: { props: {
isConfidential: { isConfidential: {
required: true, required: true,
...@@ -16,11 +19,7 @@ export default { ...@@ -16,11 +19,7 @@ export default {
type: Function, type: Function,
}, },
}, },
};
components: {
editFormButtons,
},
};
</script> </script>
<template> <template>
......
<script> <script>
import editFormButtons from './edit_form_buttons.vue'; import editFormButtons from './edit_form_buttons.vue';
import issuableMixin from '../../../vue_shared/mixins/issuable'; import issuableMixin from '../../../vue_shared/mixins/issuable';
export default { export default {
components: {
editFormButtons,
},
mixins: [
issuableMixin,
],
props: { props: {
isLocked: { isLocked: {
required: true, required: true,
...@@ -19,27 +25,23 @@ export default { ...@@ -19,27 +25,23 @@ export default {
type: Function, type: Function,
}, },
}, },
};
mixins: [
issuableMixin,
],
components: {
editFormButtons,
},
};
</script> </script>
<template> <template>
<div class="dropdown open"> <div class="dropdown open">
<div class="dropdown-menu sidebar-item-warning-message"> <div class="dropdown-menu sidebar-item-warning-message">
<p class="text" v-if="isLocked"> <p
class="text"
v-if="isLocked">
Unlock this {{ issuableDisplayName }}? Unlock this {{ issuableDisplayName }}?
<strong>Everyone</strong> <strong>Everyone</strong>
will be able to comment. will be able to comment.
</p> </p>
<p class="text" v-else> <p
class="text"
v-else>
Lock this {{ issuableDisplayName }}? Lock this {{ issuableDisplayName }}?
Only Only
<strong>project members</strong> <strong>project members</strong>
......
<script> <script>
/* global Flash */ import Flash from '../../../flash';
import editForm from './edit_form.vue'; import editForm from './edit_form.vue';
import issuableMixin from '../../../vue_shared/mixins/issuable'; import issuableMixin from '../../../vue_shared/mixins/issuable';
import Icon from '../../../vue_shared/components/icon.vue'; import Icon from '../../../vue_shared/components/icon.vue';
export default {
components: {
editForm,
Icon,
},
mixins: [
issuableMixin,
],
export default {
props: { props: {
isLocked: { isLocked: {
required: true, required: true,
...@@ -25,15 +33,6 @@ export default { ...@@ -25,15 +33,6 @@ export default {
}, },
}, },
mixins: [
issuableMixin,
],
components: {
editForm,
Icon,
},
computed: { computed: {
lockIcon() { lockIcon() {
return this.isLocked ? 'lock' : 'lock-open'; return this.isLocked ? 'lock' : 'lock-open';
...@@ -55,10 +54,10 @@ export default { ...@@ -55,10 +54,10 @@ export default {
}) })
.then(() => location.reload()) .then(() => location.reload())
.catch(() => Flash(this.__(`Something went wrong trying to .catch(() => Flash(this.__(`Something went wrong trying to
change the locked state of this ${this.issuableDisplayName}`))); change the locked state of this ${this.issuableDisplayName}`)));
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -68,8 +67,8 @@ change the locked state of this ${this.issuableDisplayName}`))); ...@@ -68,8 +67,8 @@ change the locked state of this ${this.issuableDisplayName}`)));
:name="lockIcon" :name="lockIcon"
:size="16" :size="16"
aria-hidden="true" aria-hidden="true"
class="sidebar-item-icon is-active"> class="sidebar-item-icon is-active"
</icon> />
</div> </div>
<div class="title hide-collapsed"> <div class="title hide-collapsed">
...@@ -101,8 +100,8 @@ change the locked state of this ${this.issuableDisplayName}`))); ...@@ -101,8 +100,8 @@ change the locked state of this ${this.issuableDisplayName}`)));
name="lock" name="lock"
:size="16" :size="16"
aria-hidden="true" aria-hidden="true"
class="sidebar-item-icon inline is-active"> class="sidebar-item-icon inline is-active"
</icon> />
{{ __('Locked') }} {{ __('Locked') }}
</div> </div>
...@@ -114,8 +113,8 @@ change the locked state of this ${this.issuableDisplayName}`))); ...@@ -114,8 +113,8 @@ change the locked state of this ${this.issuableDisplayName}`)));
name="lock-open" name="lock-open"
:size="16" :size="16"
aria-hidden="true" aria-hidden="true"
class="sidebar-item-icon inline"> class="sidebar-item-icon inline"
</icon> />
{{ __('Unlocked') }} {{ __('Unlocked') }}
</div> </div>
</div> </div>
......
<script> <script>
import { __, n__, sprintf } from '../../../locale'; import { __, n__, sprintf } from '../../../locale';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
import userAvatarImage from '../../../vue_shared/components/user_avatar/user_avatar_image.vue'; import userAvatarImage from '../../../vue_shared/components/user_avatar/user_avatar_image.vue';
export default { export default {
components: {
loadingIcon,
userAvatarImage,
},
props: { props: {
loading: { loading: {
type: Boolean, type: Boolean,
...@@ -26,10 +30,6 @@ export default { ...@@ -26,10 +30,6 @@ export default {
isShowingMoreParticipants: false, isShowingMoreParticipants: false,
}; };
}, },
components: {
loadingIcon,
userAvatarImage,
},
computed: { computed: {
lessParticipants() { lessParticipants() {
return this.participants.slice(0, this.numberOfLessParticipants); return this.participants.slice(0, this.numberOfLessParticipants);
...@@ -67,7 +67,7 @@ export default { ...@@ -67,7 +67,7 @@ export default {
this.isShowingMoreParticipants = !this.isShowingMoreParticipants; this.isShowingMoreParticipants = !this.isShowingMoreParticipants;
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -75,14 +75,17 @@ export default { ...@@ -75,14 +75,17 @@ export default {
<div class="sidebar-collapsed-icon"> <div class="sidebar-collapsed-icon">
<i <i
class="fa fa-users" class="fa fa-users"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
<loading-icon <loading-icon
v-if="loading" v-if="loading"
class="js-participants-collapsed-loading-icon" /> class="js-participants-collapsed-loading-icon"
/>
<span <span
v-else v-else
class="js-participants-collapsed-count"> class="js-participants-collapsed-count"
>
{{ participantCount }} {{ participantCount }}
</span> </span>
</div> </div>
...@@ -90,34 +93,40 @@ export default { ...@@ -90,34 +93,40 @@ export default {
<loading-icon <loading-icon
v-if="loading" v-if="loading"
:inline="true" :inline="true"
class="js-participants-expanded-loading-icon" /> class="js-participants-expanded-loading-icon"
/>
{{ participantLabel }} {{ participantLabel }}
</div> </div>
<div class="participants-list hide-collapsed"> <div class="participants-list hide-collapsed">
<div <div
v-for="participant in visibleParticipants" v-for="participant in visibleParticipants"
:key="participant.id" :key="participant.id"
class="participants-author js-participants-author"> class="participants-author js-participants-author"
>
<a <a
class="author_link" class="author_link"
:href="participant.web_url"> :href="participant.web_url"
>
<user-avatar-image <user-avatar-image
:lazy="true" :lazy="true"
:img-src="participant.avatar_url" :img-src="participant.avatar_url"
css-classes="avatar-inline" css-classes="avatar-inline"
:size="24" :size="24"
:tooltip-text="participant.name" :tooltip-text="participant.name"
tooltip-placement="bottom" /> tooltip-placement="bottom"
/>
</a> </a>
</div> </div>
</div> </div>
<div <div
v-if="hasMoreParticipants" v-if="hasMoreParticipants"
class="participants-more hide-collapsed"> class="participants-more hide-collapsed"
>
<button <button
type="button" type="button"
class="btn-transparent btn-blank js-toggle-participants-button" class="btn-transparent btn-blank js-toggle-participants-button"
@click="toggleMoreParticipants"> @click="toggleMoreParticipants"
>
{{ toggleLabel }} {{ toggleLabel }}
</button> </button>
</div> </div>
......
<script> <script>
import Store from '../../stores/sidebar_store'; import Store from '../../stores/sidebar_store';
import participants from './participants.vue'; import participants from './participants.vue';
export default { export default {
data() { components: {
return { participants,
store: new Store(),
};
}, },
props: { props: {
mediator: { mediator: {
...@@ -14,10 +12,12 @@ export default { ...@@ -14,10 +12,12 @@ export default {
required: true, required: true,
}, },
}, },
components: { data() {
participants, return {
store: new Store(),
};
}, },
}; };
</script> </script>
<template> <template>
......
...@@ -6,10 +6,8 @@ import { __ } from '../../../locale'; ...@@ -6,10 +6,8 @@ import { __ } from '../../../locale';
import subscriptions from './subscriptions.vue'; import subscriptions from './subscriptions.vue';
export default { export default {
data() { components: {
return { subscriptions,
store: new Store(),
};
}, },
props: { props: {
mediator: { mediator: {
...@@ -17,10 +15,17 @@ export default { ...@@ -17,10 +15,17 @@ export default {
required: true, required: true,
}, },
}, },
components: { data() {
subscriptions, return {
store: new Store(),
};
},
created() {
eventHub.$on('toggleSubscription', this.onToggleSubscription);
},
beforeDestroy() {
eventHub.$off('toggleSubscription', this.onToggleSubscription);
}, },
methods: { methods: {
onToggleSubscription() { onToggleSubscription() {
this.mediator.toggleSubscription() this.mediator.toggleSubscription()
...@@ -29,14 +34,6 @@ export default { ...@@ -29,14 +34,6 @@ export default {
}); });
}, },
}, },
created() {
eventHub.$on('toggleSubscription', this.onToggleSubscription);
},
beforeDestroy() {
eventHub.$off('toggleSubscription', this.onToggleSubscription);
},
}; };
</script> </script>
...@@ -44,6 +41,7 @@ export default { ...@@ -44,6 +41,7 @@ export default {
<div class="block subscriptions"> <div class="block subscriptions">
<subscriptions <subscriptions
:loading="store.isFetching.subscriptions" :loading="store.isFetching.subscriptions"
:subscribed="store.subscribed" /> :subscribed="store.subscribed"
/>
</div> </div>
</template> </template>
<script> <script>
import { __ } from '../../../locale'; import { __ } from '../../../locale';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import loadingButton from '../../../vue_shared/components/loading_button.vue'; import loadingButton from '../../../vue_shared/components/loading_button.vue';
export default { export default {
components: {
loadingButton,
},
props: { props: {
loading: { loading: {
type: Boolean, type: Boolean,
...@@ -13,15 +16,14 @@ export default { ...@@ -13,15 +16,14 @@ export default {
subscribed: { subscribed: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false,
}, },
id: { id: {
type: Number, type: Number,
required: false, required: false,
default: 0,
}, },
}, },
components: {
loadingButton,
},
computed: { computed: {
buttonLabel() { buttonLabel() {
let label; let label;
...@@ -39,7 +41,7 @@ export default { ...@@ -39,7 +41,7 @@ export default {
eventHub.$emit('toggleSubscription', this.id); eventHub.$emit('toggleSubscription', this.id);
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -47,7 +49,8 @@ export default { ...@@ -47,7 +49,8 @@ export default {
<div class="sidebar-collapsed-icon"> <div class="sidebar-collapsed-icon">
<i <i
class="fa fa-rss" class="fa fa-rss"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</div> </div>
<span class="issuable-header-text hide-collapsed pull-left"> <span class="issuable-header-text hide-collapsed pull-left">
......
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
export default { export default {
name: 'MRWidgetPipeline', name: 'MRWidgetPipeline',
components: {
pipelineStage,
ciIcon,
icon,
},
props: { props: {
pipeline: { pipeline: {
type: Object, type: Object,
...@@ -21,11 +26,6 @@ ...@@ -21,11 +26,6 @@
required: false, required: false,
}, },
}, },
components: {
pipelineStage,
ciIcon,
icon,
},
computed: { computed: {
hasPipeline() { hasPipeline() {
return this.pipeline && Object.keys(this.pipeline).length > 0; return this.pipeline && Object.keys(this.pipeline).length > 0;
...@@ -62,7 +62,8 @@ ...@@ -62,7 +62,8 @@
<template v-else-if="hasPipeline"> <template v-else-if="hasPipeline">
<a <a
class="append-right-10" class="append-right-10"
:href="this.status.details_path"> :href="status.details_path"
>
<ci-icon :status="status" /> <ci-icon :status="status" />
</a> </a>
...@@ -70,33 +71,37 @@ ...@@ -70,33 +71,37 @@
Pipeline Pipeline
<a <a
:href="pipeline.path" :href="pipeline.path"
class="pipeline-id"> class="pipeline-id"
#{{pipeline.id}} >
#{{ pipeline.id }}
</a> </a>
{{pipeline.details.status.label}} for {{ pipeline.details.status.label }} for
<a <a
:href="pipeline.commit.commit_path" :href="pipeline.commit.commit_path"
class="commit-sha js-commit-link"> class="commit-sha js-commit-link"
{{pipeline.commit.short_id}}</a>. >
{{ pipeline.commit.short_id }}</a>.
<span class="mr-widget-pipeline-graph"> <span class="mr-widget-pipeline-graph">
<span class="stage-cell"> <span
<div class="stage-cell"
v-if="hasStages" v-if="hasStages"
>
<div
v-for="(stage, i) in pipeline.details.stages" v-for="(stage, i) in pipeline.details.stages"
:key="i" :key="i"
class="stage-container dropdown js-mini-pipeline-graph"> class="stage-container dropdown js-mini-pipeline-graph"
>
<pipeline-stage :stage="stage" /> <pipeline-stage :stage="stage" />
</div> </div>
</span> </span>
</span> </span>
<template v-if="pipeline.coverage"> <template v-if="pipeline.coverage">
Coverage {{pipeline.coverage}}% Coverage {{ pipeline.coverage }}%
</template> </template>
</div> </div>
</template> </template>
</div> </div>
......
...@@ -23,6 +23,12 @@ ...@@ -23,6 +23,12 @@
*/ */
export default { export default {
components: {
ciIcon,
},
directives: {
tooltip,
},
props: { props: {
status: { status: {
type: Object, type: Object,
...@@ -34,12 +40,6 @@ ...@@ -34,12 +40,6 @@
default: true, default: true,
}, },
}, },
components: {
ciIcon,
},
directives: {
tooltip,
},
computed: { computed: {
cssClass() { cssClass() {
const className = this.status.group; const className = this.status.group;
...@@ -53,11 +53,12 @@ ...@@ -53,11 +53,12 @@
:href="status.details_path" :href="status.details_path"
:class="cssClass" :class="cssClass"
v-tooltip v-tooltip
:title="!showText ? status.text : ''"> :title="!showText ? status.text : ''"
>
<ci-icon :status="status" /> <ci-icon :status="status" />
<template v-if="showText"> <template v-if="showText">
{{status.text}} {{ status.text }}
</template> </template>
</a> </a>
</template> </template>
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
* - Jobs show view sidebar * - Jobs show view sidebar
*/ */
export default { export default {
components: {
icon,
},
props: { props: {
status: { status: {
type: Object, type: Object,
...@@ -30,10 +33,6 @@ ...@@ -30,10 +33,6 @@
}, },
}, },
components: {
icon,
},
computed: { computed: {
cssClass() { cssClass() {
const status = this.status.group; const status = this.status.group;
...@@ -43,9 +42,7 @@ ...@@ -43,9 +42,7 @@
}; };
</script> </script>
<template> <template>
<span <span :class="cssClass">
:class="cssClass"> <icon :name="status.icon" />
<icon
:name="status.icon"/>
</span> </span>
</template> </template>
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*/ */
export default { export default {
name: 'clipboardButton', name: 'ClipboardButton',
props: { props: {
text: { text: {
type: String, type: String,
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
type="button" type="button"
class="btn btn-transparent btn-clipboard" class="btn btn-transparent btn-clipboard"
:data-title="title" :data-title="title"
:data-clipboard-text="text"> :data-clipboard-text="text"
>
<i <i
aria-hidden="true" aria-hidden="true"
class="fa fa-clipboard"> class="fa fa-clipboard"
>
</i> </i>
</button> </button>
</template> </template>
...@@ -2,9 +2,16 @@ ...@@ -2,9 +2,16 @@
import commitIconSvg from 'icons/_icon_commit.svg'; import commitIconSvg from 'icons/_icon_commit.svg';
import userAvatarLink from './user_avatar/user_avatar_link.vue'; import userAvatarLink from './user_avatar/user_avatar_link.vue';
import tooltip from '../directives/tooltip'; import tooltip from '../directives/tooltip';
import Icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
export default { export default {
directives: {
tooltip,
},
components: {
userAvatarLink,
icon,
},
props: { props: {
/** /**
* Indicates the existance of a tag. * Indicates the existance of a tag.
...@@ -103,13 +110,6 @@ ...@@ -103,13 +110,6 @@
this.author.username ? `${this.author.username}'s avatar` : null; this.author.username ? `${this.author.username}'s avatar` : null;
}, },
}, },
directives: {
tooltip,
},
components: {
userAvatarLink,
Icon,
},
created() { created() {
this.commitIconSvg = commitIconSvg; this.commitIconSvg = commitIconSvg;
}, },
...@@ -118,17 +118,17 @@ ...@@ -118,17 +118,17 @@
<template> <template>
<div class="branch-commit"> <div class="branch-commit">
<template v-if="hasCommitRef && showBranch"> <template v-if="hasCommitRef && showBranch">
<div <div class="icon-container hidden-xs">
class="icon-container hidden-xs">
<i <i
v-if="tag" v-if="tag"
class="fa fa-tag" class="fa fa-tag"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
<icon <icon
v-if="!tag" v-if="!tag"
name="fork"> name="fork"
</icon> />
</div> </div>
<a <a
...@@ -136,25 +136,29 @@ ...@@ -136,25 +136,29 @@
:href="commitRef.ref_url" :href="commitRef.ref_url"
v-tooltip v-tooltip
data-container="body" data-container="body"
:title="commitRef.name"> :title="commitRef.name"
{{commitRef.name}} >
{{ commitRef.name }}
</a> </a>
</template> </template>
<div <div
v-html="commitIconSvg" v-html="commitIconSvg"
class="commit-icon js-commit-icon"> class="commit-icon js-commit-icon"
>
</div> </div>
<a <a
class="commit-sha" class="commit-sha"
:href="commitUrl"> :href="commitUrl"
{{shortSha}} >
{{ shortSha }}
</a> </a>
<div class="commit-title flex-truncate-parent"> <div class="commit-title flex-truncate-parent">
<span <span
v-if="title" v-if="title"
class="flex-truncate-child"> class="flex-truncate-child"
>
<user-avatar-link <user-avatar-link
v-if="hasAuthor" v-if="hasAuthor"
class="avatar-image-container" class="avatar-image-container"
...@@ -165,8 +169,9 @@ ...@@ -165,8 +169,9 @@
/> />
<a <a
class="commit-row-message" class="commit-row-message"
:href="commitUrl"> :href="commitUrl"
{{title}} >
{{ title }}
</a> </a>
</span> </span>
<span v-else> <span v-else>
......
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
*/ */
export default { export default {
components: {
loadingIcon,
icon,
},
props: { props: {
fileName: { fileName: {
type: String, type: String,
...@@ -52,10 +56,6 @@ ...@@ -52,10 +56,6 @@
default: '', default: '',
}, },
}, },
components: {
loadingIcon,
icon,
},
computed: { computed: {
spriteHref() { spriteHref() {
const iconName = getIconForFile(this.fileName) || 'file'; const iconName = getIconForFile(this.fileName) || 'file';
...@@ -75,9 +75,9 @@ ...@@ -75,9 +75,9 @@
<span> <span>
<svg <svg
:class="[iconSizeClass, cssClasses]" :class="[iconSizeClass, cssClasses]"
v-if="!loading && !folder"> v-if="!loading && !folder"
<use >
v-bind="{'xlink:href':spriteHref}"/> <use v-bind="{ 'xlink:href':spriteHref }" />
</svg> </svg>
<icon <icon
v-if="!loading && folder" v-if="!loading && folder"
......
<script> <script>
import ciIconBadge from './ci_badge_link.vue'; import ciIconBadge from './ci_badge_link.vue';
import loadingIcon from './loading_icon.vue'; import loadingIcon from './loading_icon.vue';
import timeagoTooltip from './time_ago_tooltip.vue'; import timeagoTooltip from './time_ago_tooltip.vue';
import tooltip from '../directives/tooltip'; import tooltip from '../directives/tooltip';
import userAvatarImage from './user_avatar/user_avatar_image.vue'; import userAvatarImage from './user_avatar/user_avatar_image.vue';
/** /**
* Renders header component for job and pipeline page based on UI mockups * Renders header component for job and pipeline page based on UI mockups
* *
* Used in: * Used in:
* - job show page * - job show page
* - pipeline show page * - pipeline show page
*/ */
export default { export default {
directives: {
tooltip,
},
components: {
ciIconBadge,
loadingIcon,
timeagoTooltip,
userAvatarImage,
},
props: { props: {
status: { status: {
type: Object, type: Object,
...@@ -47,17 +57,6 @@ export default { ...@@ -47,17 +57,6 @@ export default {
}, },
}, },
directives: {
tooltip,
},
components: {
ciIconBadge,
loadingIcon,
timeagoTooltip,
userAvatarImage,
},
computed: { computed: {
userAvatarAltText() { userAvatarAltText() {
return `${this.user.name}'s avatar`; return `${this.user.name}'s avatar`;
...@@ -69,7 +68,7 @@ export default { ...@@ -69,7 +68,7 @@ export default {
this.$emit('actionClicked', action); this.$emit('actionClicked', action);
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -79,7 +78,7 @@ export default { ...@@ -79,7 +78,7 @@ export default {
<ci-icon-badge :status="status" /> <ci-icon-badge :status="status" />
<strong> <strong>
{{itemName}} #{{itemId}} {{ itemName }} #{{ itemId }}
</strong> </strong>
triggered triggered
...@@ -93,7 +92,8 @@ export default { ...@@ -93,7 +92,8 @@ export default {
v-tooltip v-tooltip
:href="user.path" :href="user.path"
:title="user.email" :title="user.email"
class="js-user-link commit-committer-link"> class="js-user-link commit-committer-link"
>
<user-avatar-image <user-avatar-image
:img-src="user.avatar_url" :img-src="user.avatar_url"
...@@ -102,21 +102,25 @@ export default { ...@@ -102,21 +102,25 @@ export default {
:img-size="24" :img-size="24"
/> />
{{user.name}} {{ user.name }}
</a> </a>
</template> </template>
</section> </section>
<section <section
class="header-action-buttons" class="header-action-buttons"
v-if="actions.length"> v-if="actions.length"
>
<template <template
v-for="action in actions"> v-for="(action, i) in actions"
>
<a <a
v-if="action.type === 'link'" v-if="action.type === 'link'"
:href="action.path" :href="action.path"
:class="action.cssClass"> :class="action.cssClass"
{{action.label}} :key="i"
>
{{ action.label }}
</a> </a>
<a <a
...@@ -124,8 +128,10 @@ export default { ...@@ -124,8 +128,10 @@ export default {
:href="action.path" :href="action.path"
data-method="post" data-method="post"
rel="nofollow" rel="nofollow"
:class="action.cssClass"> :class="action.cssClass"
{{action.label}} :key="i"
>
{{ action.label }}
</a> </a>
<button <button
...@@ -133,12 +139,15 @@ export default { ...@@ -133,12 +139,15 @@ export default {
@click="onClickAction(action)" @click="onClickAction(action)"
:disabled="action.isLoading" :disabled="action.isLoading"
:class="action.cssClass" :class="action.cssClass"
type="button"> type="button"
{{action.label}} :key="i"
>
{{ action.label }}
<i <i
v-show="action.isLoading" v-show="action.isLoading"
class="fa fa-spin fa-spinner" class="fa fa-spin fa-spinner"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
</button> </button>
</template> </template>
...@@ -147,11 +156,13 @@ export default { ...@@ -147,11 +156,13 @@ export default {
type="button" type="button"
class="btn btn-default visible-xs-block visible-sm-block sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header" class="btn btn-default visible-xs-block visible-sm-block sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header"
aria-label="Toggle Sidebar" aria-label="Toggle Sidebar"
id="toggleSidebar"> id="toggleSidebar"
>
<i <i
class="fa fa-angle-double-left" class="fa fa-angle-double-left"
aria-hidden="true" aria-hidden="true"
aria-labelledby="toggleSidebar"> aria-labelledby="toggleSidebar"
>
</i> </i>
</button> </button>
</section> </section>
......
<script> <script>
/* This is a re-usable vue component for rendering a svg sprite /* This is a re-usable vue component for rendering a svg sprite
icon icon
Sample configuration: Sample configuration:
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
css-classes="top" css-classes="top"
/> />
*/ */
// only allow classes in images.scss e.g. s12 // only allow classes in images.scss e.g. s12
const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; const validSizes = [8, 12, 16, 18, 24, 32, 48, 72];
...@@ -80,7 +80,6 @@ ...@@ -80,7 +80,6 @@
:height="height" :height="height"
:x="x" :x="x"
:y="y"> :y="y">
<use <use v-bind="{ 'xlink:href':spriteHref }" />
v-bind="{'xlink:href':spriteHref}"/>
</svg> </svg>
</template> </template>
...@@ -46,6 +46,6 @@ export default { ...@@ -46,6 +46,6 @@ export default {
class="avatar identicon" class="avatar identicon"
:class="sizeClass" :class="sizeClass"
:style="identiconStyles"> :style="identiconStyles">
{{identiconTitle}} {{ identiconTitle }}
</div> </div>
</template> </template>
<script> <script>
import Icon from '../../../vue_shared/components/icon.vue'; import icon from '../../../vue_shared/components/icon.vue';
export default { export default {
components: {
icon,
},
props: { props: {
isLocked: { isLocked: {
type: Boolean, type: Boolean,
...@@ -16,10 +19,6 @@ ...@@ -16,10 +19,6 @@
}, },
}, },
components: {
Icon,
},
computed: { computed: {
warningIcon() { warningIcon() {
if (this.isConfidential) return 'eye-slash'; if (this.isConfidential) return 'eye-slash';
...@@ -41,8 +40,8 @@ ...@@ -41,8 +40,8 @@
:size="16" :size="16"
class="icon inline" class="icon inline"
aria-hidden="true" aria-hidden="true"
v-if="!isLockedAndConfidential"> v-if="!isLockedAndConfidential"
</icon> />
<span v-if="isLockedAndConfidential"> <span v-if="isLockedAndConfidential">
{{ __('This issue is confidential and locked.') }} {{ __('This issue is confidential and locked.') }}
......
<script> <script>
/* This is a re-usable vue component for rendering a button /* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need that will probably be sending off ajax requests and need
to show the loading status by setting the `loading` option. to show the loading status by setting the `loading` option.
This can also be used for initial page load when you don't This can also be used for initial page load when you don't
...@@ -15,11 +15,14 @@ ...@@ -15,11 +15,14 @@
@click="..." @click="..."
/> />
*/ */
import loadingIcon from './loading_icon.vue'; import loadingIcon from './loading_icon.vue';
export default { export default {
components: {
loadingIcon,
},
props: { props: {
loading: { loading: {
type: Boolean, type: Boolean,
...@@ -34,6 +37,7 @@ export default { ...@@ -34,6 +37,7 @@ export default {
label: { label: {
type: String, type: String,
required: false, required: false,
default: '',
}, },
containerClass: { containerClass: {
type: String, type: String,
...@@ -41,15 +45,17 @@ export default { ...@@ -41,15 +45,17 @@ export default {
default: 'btn btn-align-content', default: 'btn btn-align-content',
}, },
}, },
components: { computed: {
loadingIcon, hasLabel() {
return this.label !== '';
},
}, },
methods: { methods: {
onClick(e) { onClick(e) {
this.$emit('click', e); this.$emit('click', e);
}, },
}, },
}; };
</script> </script>
<template> <template>
...@@ -71,7 +77,7 @@ export default { ...@@ -71,7 +77,7 @@ export default {
</transition> </transition>
<transition name="fade"> <transition name="fade">
<span <span
v-if="label" v-if="hasLabel"
class="js-loading-button-label" class="js-loading-button-label"
> >
{{ label }} {{ label }}
......
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
class="fa fa-spin fa-spinner" class="fa fa-spin fa-spinner"
:class="cssClass" :class="cssClass"
aria-hidden="true" aria-hidden="true"
:aria-label="label"> :aria-label="label"
>
</i> </i>
</component> </component>
</template> </template>
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
import icon from '../icon.vue'; import icon from '../icon.vue';
export default { export default {
components: {
markdownHeader,
markdownToolbar,
icon,
},
props: { props: {
markdownPreviewPath: { markdownPreviewPath: {
type: String, type: String,
...@@ -24,6 +29,7 @@ ...@@ -24,6 +29,7 @@
quickActionsDocsPath: { quickActionsDocsPath: {
type: String, type: String,
required: false, required: false,
default: '',
}, },
canAttachFile: { canAttachFile: {
type: Boolean, type: Boolean,
...@@ -45,17 +51,24 @@ ...@@ -45,17 +51,24 @@
previewMarkdown: false, previewMarkdown: false,
}; };
}, },
components: {
markdownHeader,
markdownToolbar,
icon,
},
computed: { computed: {
shouldShowReferencedUsers() { shouldShowReferencedUsers() {
const referencedUsersThreshold = 10; const referencedUsersThreshold = 10;
return this.referencedUsers.length >= referencedUsersThreshold; return this.referencedUsers.length >= referencedUsersThreshold;
}, },
}, },
mounted() {
/*
GLForm class handles all the toolbar buttons
*/
return new GLForm($(this.$refs['gl-form']), this.enableAutocomplete);
},
beforeDestroy() {
const glForm = $(this.$refs['gl-form']).data('gl-form');
if (glForm) {
glForm.destroy();
}
},
methods: { methods: {
showPreviewTab() { showPreviewTab() {
if (this.previewMarkdown) return; if (this.previewMarkdown) return;
...@@ -98,18 +111,6 @@ ...@@ -98,18 +111,6 @@
}); });
}, },
}, },
mounted() {
/*
GLForm class handles all the toolbar buttons
*/
return new GLForm($(this.$refs['gl-form']), this.enableAutocomplete);
},
beforeDestroy() {
const glForm = $(this.$refs['gl-form']).data('gl-form');
if (glForm) {
glForm.destroy();
}
},
}; };
</script> </script>
...@@ -121,20 +122,23 @@ ...@@ -121,20 +122,23 @@
<markdown-header <markdown-header
:preview-markdown="previewMarkdown" :preview-markdown="previewMarkdown"
@preview-markdown="showPreviewTab" @preview-markdown="showPreviewTab"
@write-markdown="showWriteTab" /> @write-markdown="showWriteTab"
/>
<div <div
class="md-write-holder" class="md-write-holder"
v-show="!previewMarkdown"> v-show="!previewMarkdown"
>
<div class="zen-backdrop"> <div class="zen-backdrop">
<slot name="textarea"></slot> <slot name="textarea"></slot>
<a <a
class="zen-control zen-control-leave js-zen-leave" class="zen-control zen-control-leave js-zen-leave"
href="#" href="#"
aria-label="Enter zen mode"> aria-label="Enter zen mode"
>
<icon <icon
name="screen-normal" name="screen-normal"
:size="32"> :size="32"
</icon> />
</a> </a>
<markdown-toolbar <markdown-toolbar
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
...@@ -145,10 +149,12 @@ ...@@ -145,10 +149,12 @@
</div> </div>
<div <div
class="md md-preview-holder md-preview" class="md md-preview-holder md-preview"
v-show="previewMarkdown"> v-show="previewMarkdown"
>
<div <div
ref="markdown-preview" ref="markdown-preview"
v-html="markdownPreview"> v-html="markdownPreview"
>
</div> </div>
<span v-if="markdownPreviewLoading"> <span v-if="markdownPreviewLoading">
Loading... Loading...
...@@ -158,19 +164,23 @@ ...@@ -158,19 +164,23 @@
<div <div
v-if="referencedCommands" v-if="referencedCommands"
v-html="referencedCommands" v-html="referencedCommands"
class="referenced-commands"></div> class="referenced-commands"
>
</div>
<div <div
v-if="shouldShowReferencedUsers" v-if="shouldShowReferencedUsers"
class="referenced-users"> class="referenced-users"
>
<span> <span>
<i <i
class="fa fa-exclamation-triangle" class="fa fa-exclamation-triangle"
aria-hidden="true"> aria-hidden="true"
>
</i> </i>
You are about to add You are about to add
<strong> <strong>
<span class="js-referenced-users-count"> <span class="js-referenced-users-count">
{{referencedUsers.length}} {{ referencedUsers.length }}
</span> </span>
</strong> people to the discussion. Proceed with caution. </strong> people to the discussion. Proceed with caution.
</span> </span>
......
...@@ -4,18 +4,26 @@ ...@@ -4,18 +4,26 @@
import icon from '../icon.vue'; import icon from '../icon.vue';
export default { export default {
directives: {
tooltip,
},
components: {
toolbarButton,
icon,
},
props: { props: {
previewMarkdown: { previewMarkdown: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
}, },
directives: { mounted() {
tooltip, $(document).on('markdown-preview:show.vue', this.previewMarkdownTab);
$(document).on('markdown-preview:hide.vue', this.writeMarkdownTab);
}, },
components: { beforeDestroy() {
toolbarButton, $(document).off('markdown-preview:show.vue', this.previewMarkdownTab);
icon, $(document).off('markdown-preview:hide.vue', this.writeMarkdownTab);
}, },
methods: { methods: {
isMarkdownForm(form) { isMarkdownForm(form) {
...@@ -36,14 +44,6 @@ ...@@ -36,14 +44,6 @@
this.$emit('write-markdown'); this.$emit('write-markdown');
}, },
}, },
mounted() {
$(document).on('markdown-preview:show.vue', this.previewMarkdownTab);
$(document).on('markdown-preview:hide.vue', this.writeMarkdownTab);
},
beforeDestroy() {
$(document).off('markdown-preview:show.vue', this.previewMarkdownTab);
$(document).off('markdown-preview:hide.vue', this.writeMarkdownTab);
},
}; };
</script> </script>
...@@ -52,12 +52,14 @@ ...@@ -52,12 +52,14 @@
<ul class="nav-links clearfix"> <ul class="nav-links clearfix">
<li <li
class="md-header-tab" class="md-header-tab"
:class="{ active: !previewMarkdown }"> :class="{ active: !previewMarkdown }"
>
<a <a
class="js-write-link" class="js-write-link"
href="#md-write-holder" href="#md-write-holder"
tabindex="-1" tabindex="-1"
@click.prevent="writeMarkdownTab($event)"> @click.prevent="writeMarkdownTab($event)"
>
Write Write
</a> </a>
</li> </li>
...@@ -68,46 +70,55 @@ ...@@ -68,46 +70,55 @@
class="js-preview-link" class="js-preview-link"
href="#md-preview-holder" href="#md-preview-holder"
tabindex="-1" tabindex="-1"
@click.prevent="previewMarkdownTab($event)"> @click.prevent="previewMarkdownTab($event)"
>
Preview Preview
</a> </a>
</li> </li>
<li <li
class="md-header-toolbar" class="md-header-toolbar"
:class="{ active: !previewMarkdown }"> :class="{ active: !previewMarkdown }"
>
<toolbar-button <toolbar-button
tag="**" tag="**"
button-title="Add bold text" button-title="Add bold text"
icon="bold" /> icon="bold"
/>
<toolbar-button <toolbar-button
tag="*" tag="*"
button-title="Add italic text" button-title="Add italic text"
icon="italic" /> icon="italic"
/>
<toolbar-button <toolbar-button
tag="> " tag="> "
:prepend="true" :prepend="true"
button-title="Insert a quote" button-title="Insert a quote"
icon="quote" /> icon="quote"
/>
<toolbar-button <toolbar-button
tag="`" tag="`"
tag-block="```" tag-block="```"
button-title="Insert code" button-title="Insert code"
icon="code" /> icon="code"
/>
<toolbar-button <toolbar-button
tag="* " tag="* "
:prepend="true" :prepend="true"
button-title="Add a bullet list" button-title="Add a bullet list"
icon="list-bulleted" /> icon="list-bulleted"
/>
<toolbar-button <toolbar-button
tag="1. " tag="1. "
:prepend="true" :prepend="true"
button-title="Add a numbered list" button-title="Add a numbered list"
icon="list-numbered" /> icon="list-numbered"
/>
<toolbar-button <toolbar-button
tag="* [ ] " tag="* [ ] "
:prepend="true" :prepend="true"
button-title="Add a task list" button-title="Add a task list"
icon="task-done" /> icon="task-done"
/>
<button <button
v-tooltip v-tooltip
aria-label="Go full screen" aria-label="Go full screen"
...@@ -115,10 +126,11 @@ ...@@ -115,10 +126,11 @@
data-container="body" data-container="body"
tabindex="-1" tabindex="-1"
title="Go full screen" title="Go full screen"
type="button"> type="button"
>
<icon <icon
name="screen-full"> name="screen-full"
</icon> />
</button> </button>
</li> </li>
</ul> </ul>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
quickActionsDocsPath: { quickActionsDocsPath: {
type: String, type: String,
required: false, required: false,
default: '',
}, },
canAttachFile: { canAttachFile: {
type: Boolean, type: Boolean,
...@@ -15,32 +16,40 @@ ...@@ -15,32 +16,40 @@
default: true, default: true,
}, },
}, },
computed: {
hasQuickActionsDocsPath() {
return this.quickActionsDocsPath !== '';
},
},
}; };
</script> </script>
<template> <template>
<div class="comment-toolbar clearfix"> <div class="comment-toolbar clearfix">
<div class="toolbar-text"> <div class="toolbar-text">
<template v-if="!quickActionsDocsPath && markdownDocsPath"> <template v-if="!hasQuickActionsDocsPath && markdownDocsPath">
<a <a
:href="markdownDocsPath" :href="markdownDocsPath"
target="_blank" target="_blank"
tabindex="-1"> tabindex="-1"
>
Markdown is supported Markdown is supported
</a> </a>
</template> </template>
<template v-if="quickActionsDocsPath && markdownDocsPath"> <template v-if="hasQuickActionsDocsPath && markdownDocsPath">
<a <a
:href="markdownDocsPath" :href="markdownDocsPath"
target="_blank" target="_blank"
tabindex="-1"> tabindex="-1"
>
Markdown Markdown
</a> </a>
and and
<a <a
:href="quickActionsDocsPath" :href="quickActionsDocsPath"
target="_blank" target="_blank"
tabindex="-1"> tabindex="-1"
>
quick actions quick actions
</a> </a>
are supported are supported
...@@ -53,46 +62,58 @@ ...@@ -53,46 +62,58 @@
<span class="uploading-progress-container hide"> <span class="uploading-progress-container hide">
<i <i
class="fa fa-file-image-o toolbar-button-icon" class="fa fa-file-image-o toolbar-button-icon"
aria-hidden="true"></i> aria-hidden="true"
>
</i>
<span class="attaching-file-message"></span> <span class="attaching-file-message"></span>
<span class="uploading-progress">0%</span> <span class="uploading-progress">0%</span>
<span class="uploading-spinner"> <span class="uploading-spinner">
<i <i
class="fa fa-spinner fa-spin toolbar-button-icon" class="fa fa-spinner fa-spin toolbar-button-icon"
aria-hidden="true"></i> aria-hidden="true"
>
</i>
</span> </span>
</span> </span>
<span class="uploading-error-container hide"> <span class="uploading-error-container hide">
<span class="uploading-error-icon"> <span class="uploading-error-icon">
<i <i
class="fa fa-file-image-o toolbar-button-icon" class="fa fa-file-image-o toolbar-button-icon"
aria-hidden="true"></i> aria-hidden="true"
>
</i>
</span> </span>
<span class="uploading-error-message"></span> <span class="uploading-error-message"></span>
<button <button
class="retry-uploading-link" class="retry-uploading-link"
type="button"> type="button"
>
Try again Try again
</button> </button>
or or
<button <button
class="attach-new-file markdown-selector" class="attach-new-file markdown-selector"
type="button"> type="button"
>
attach a new file attach a new file
</button> </button>
</span> </span>
<button <button
class="markdown-selector button-attach-file" class="markdown-selector button-attach-file"
tabindex="-1" tabindex="-1"
type="button"> type="button"
>
<i <i
class="fa fa-file-image-o toolbar-button-icon" class="fa fa-file-image-o toolbar-button-icon"
aria-hidden="true"></i> aria-hidden="true"
>
</i>
Attach a file Attach a file
</button> </button>
<button <button
class="btn btn-default btn-xs hide button-cancel-uploading-files" class="btn btn-default btn-xs hide button-cancel-uploading-files"
type="button"> type="button"
>
Cancel Cancel
</button> </button>
</span> </span>
......
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
import icon from '../icon.vue'; import icon from '../icon.vue';
export default { export default {
components: {
icon,
},
directives: {
tooltip,
},
props: { props: {
buttonTitle: { buttonTitle: {
type: String, type: String,
...@@ -27,12 +33,6 @@ ...@@ -27,12 +33,6 @@
default: false, default: false,
}, },
}, },
components: {
icon,
},
directives: {
tooltip,
},
}; };
</script> </script>
...@@ -47,9 +47,10 @@ ...@@ -47,9 +47,10 @@
:data-md-block="tagBlock" :data-md-block="tagBlock"
:data-md-prepend="prepend" :data-md-prepend="prepend"
:title="buttonTitle" :title="buttonTitle"
:aria-label="buttonTitle"> :aria-label="buttonTitle"
>
<icon <icon
:name="icon"> :name="icon"
</icon> />
</button> </button>
</template> </template>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment