Commit cdc49388 authored by Filipa Lacerda's avatar Filipa Lacerda

[ci skip] Fix more rules

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