summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared/components')
-rw-r--r--app/assets/javascripts/vue_shared/components/bar_chart.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/deprecated_modal.vue150
-rw-r--r--app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js5
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue34
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue143
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_countdown.vue49
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue31
-rw-r--r--app/assets/javascripts/vue_shared/components/icon.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_warning.vue51
-rw-r--r--app/assets/javascripts/vue_shared/components/loading_button.vue56
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue236
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue117
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue72
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue68
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue32
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/system_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/panel_resizer.vue156
-rw-r--r--app/assets/javascripts/vue_shared/components/pikaday.vue106
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/image.vue123
-rw-r--r--app/assets/javascripts/vue_shared/components/recaptcha_modal.vue94
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue182
-rw-r--r--app/assets/javascripts/vue_shared/components/table_pagination.vue206
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/toggle_button.vue94
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue2
29 files changed, 1149 insertions, 930 deletions
diff --git a/app/assets/javascripts/vue_shared/components/bar_chart.vue b/app/assets/javascripts/vue_shared/components/bar_chart.vue
index 33af7a7f1df..690dd794ba4 100644
--- a/app/assets/javascripts/vue_shared/components/bar_chart.vue
+++ b/app/assets/javascripts/vue_shared/components/bar_chart.vue
@@ -118,7 +118,9 @@ export default {
this.rectYAxisLabelDims.height != null ? this.rectYAxisLabelDims.height / 2 : 0;
const yCoord = this.vbHeight / 2 + rectWidth - 5;
- return `translate(${this.minX + this.yAxisTextTransformPadding}, ${yCoord}) rotate(-${this.yAxisTextRotation})`;
+ return `translate(${this.minX + this.yAxisTextTransformPadding}, ${yCoord}) rotate(-${
+ this.yAxisTextRotation
+ })`;
},
},
mounted() {
@@ -207,8 +209,7 @@ export default {
renderedYAxis.selectAll('.tick').each(function createTickLines(d, i) {
if (i > 0) {
- d3
- .select(this)
+ d3.select(this)
.select('line')
.attr('x2', width)
.attr('class', 'axis-tick');
@@ -217,8 +218,7 @@ export default {
// Add the panning capabilities
if (this.isPanAvailable) {
- d3
- .select(this.$refs.baseSvg)
+ d3.select(this.$refs.baseSvg)
.call(this.zoom)
.on('wheel.zoom', null); // This disables the pan of the graph with the scroll of the mouse wheel
}
diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
index a2518e2a611..c60052fec50 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -43,7 +43,7 @@ export default {
computed: {
cssClass() {
const className = this.status.group;
- return className ? `ci-status ci-${className}` : 'ci-status';
+ return className ? `ci-status ci-${className} qa-status-badge` : 'ci-status qa-status-badge';
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
index 9c1e5c68649..4d63296e332 100644
--- a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
@@ -1,85 +1,85 @@
<script>
- /* eslint-disable vue/require-default-prop */
- export default {
- name: 'DeprecatedModal', // use GlModal instead
+/* eslint-disable vue/require-default-prop */
+export default {
+ name: 'DeprecatedModal', // use GlModal instead
- props: {
- id: {
- type: String,
- required: false,
- },
- title: {
- type: String,
- required: false,
- },
- text: {
- type: String,
- required: false,
- },
- hideFooter: {
- type: Boolean,
- required: false,
- default: false,
- },
- kind: {
- type: String,
- required: false,
- default: 'primary',
- },
- modalDialogClass: {
- type: String,
- required: false,
- default: '',
- },
- closeKind: {
- type: String,
- required: false,
- default: 'default',
- },
- closeButtonLabel: {
- type: String,
- required: false,
- default: 'Cancel',
- },
- primaryButtonLabel: {
- type: String,
- required: false,
- default: '',
- },
- secondaryButtonLabel: {
- type: String,
- required: false,
- default: '',
- },
- submitDisabled: {
- type: Boolean,
- required: false,
- default: false,
- },
+ props: {
+ id: {
+ type: String,
+ required: false,
},
+ title: {
+ type: String,
+ required: false,
+ },
+ text: {
+ type: String,
+ required: false,
+ },
+ hideFooter: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ kind: {
+ type: String,
+ required: false,
+ default: 'primary',
+ },
+ modalDialogClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ closeKind: {
+ type: String,
+ required: false,
+ default: 'default',
+ },
+ closeButtonLabel: {
+ type: String,
+ required: false,
+ default: 'Cancel',
+ },
+ primaryButtonLabel: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ secondaryButtonLabel: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ submitDisabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
- computed: {
- btnKindClass() {
- return {
- [`btn-${this.kind}`]: true,
- };
- },
- btnCancelKindClass() {
- return {
- [`btn-${this.closeKind}`]: true,
- };
- },
+ computed: {
+ btnKindClass() {
+ return {
+ [`btn-${this.kind}`]: true,
+ };
+ },
+ btnCancelKindClass() {
+ return {
+ [`btn-${this.closeKind}`]: true,
+ };
},
+ },
- methods: {
- emitCancel(event) {
- this.$emit('cancel', event);
- },
- emitSubmit(event) {
- this.$emit('submit', event);
- },
+ methods: {
+ emitCancel(event) {
+ this.$emit('cancel', event);
+ },
+ emitSubmit(event) {
+ this.$emit('submit', event);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
index 9bca1993ccc..bffaa096210 100644
--- a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
+++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
@@ -549,6 +549,7 @@ const fileNameIcons = {
jenkinsfile: 'jenkins',
'firebase.json': 'firebase',
'.firebaserc': 'firebase',
+ Rakefile: 'ruby',
'rollup.config.js': 'rollup',
'rollup.config.ts': 'rollup',
'rollup-config.js': 'rollup',
@@ -583,7 +584,5 @@ const fileNameIcons = {
};
export default function getIconForFile(name) {
- return fileNameIcons[name] ||
- fileExtensionIcons[name ? name.split('.').pop() : ''] ||
- '';
+ return fileNameIcons[name] || fileExtensionIcons[name ? name.split('.').pop() : ''] || '';
}
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 36a345130c0..2d89a156117 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -34,10 +34,21 @@ export default {
required: false,
default: false,
},
+ displayTextKey: {
+ type: String,
+ required: false,
+ default: 'name',
+ },
+ shouldTruncateStart: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
mouseOver: false,
+ truncateStart: 0,
};
},
computed: {
@@ -60,6 +71,15 @@ export default {
'is-open': this.file.opened,
};
},
+ outputText() {
+ const text = this.file[this.displayTextKey];
+
+ if (this.truncateStart === 0) {
+ return text;
+ }
+
+ return `...${text.substring(this.truncateStart, text.length)}`;
+ },
},
watch: {
'file.active': function fileActiveWatch(active) {
@@ -72,6 +92,15 @@ export default {
if (this.hasPathAtCurrentRoute()) {
this.scrollIntoView(true);
}
+
+ if (this.shouldTruncateStart) {
+ const { scrollWidth, offsetWidth } = this.$refs.textOutput;
+ const textOverflow = scrollWidth - offsetWidth;
+
+ if (textOverflow > 0) {
+ this.truncateStart = Math.ceil(textOverflow / 5) + 3;
+ }
+ }
},
methods: {
toggleTreeOpen(path) {
@@ -139,6 +168,7 @@ export default {
class="file-row-name-container"
>
<span
+ ref="textOutput"
:style="levelIndentation"
class="file-row-name str-truncated"
>
@@ -156,7 +186,7 @@ export default {
:size="16"
class="append-right-5"
/>
- {{ file.name }}
+ {{ outputText }}
</span>
<component
:is="extraComponent"
@@ -175,6 +205,8 @@ export default {
:hide-extra-on-tree="hideExtraOnTree"
:extra-component="extraComponent"
:show-changed-icon="showChangedIcon"
+ :display-text-key="displayTextKey"
+ :should-truncate-start="shouldTruncateStart"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="clickedFile"
/>
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
new file mode 100644
index 00000000000..460fa6ad72e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
@@ -0,0 +1,143 @@
+<script>
+import $ from 'jquery';
+import Icon from '~/vue_shared/components/icon.vue';
+/**
+ * Renders a split dropdown with
+ * an input that allows to search through the given
+ * array of options.
+ */
+export default {
+ name: 'FilteredSearchDropdown',
+ components: {
+ Icon,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ buttonType: {
+ required: false,
+ validator: value =>
+ ['primary', 'default', 'secondary', 'success', 'info', 'warning', 'danger'].indexOf(
+ value,
+ ) !== -1,
+ default: 'default',
+ },
+ size: {
+ required: false,
+ type: String,
+ default: 'sm',
+ },
+ items: {
+ type: Array,
+ required: true,
+ },
+ visibleItems: {
+ type: Number,
+ required: false,
+ default: 5,
+ },
+ filterKey: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ filter: '',
+ };
+ },
+ computed: {
+ className() {
+ return `btn btn-${this.buttonType} btn-${this.size}`;
+ },
+ filteredResults() {
+ if (this.filter !== '') {
+ return this.items.filter(
+ item => item[this.filterKey] && item[this.filterKey].toLowerCase().includes(this.filter.toLowerCase()),
+ );
+ }
+
+ return this.items.slice(0, this.visibleItems);
+ }
+ },
+ mounted() {
+ /**
+ * Resets the filter every time the user closes the dropdown
+ */
+ $(this.$el)
+ .on('shown.bs.dropdown', () => {
+ this.$nextTick(() => this.$refs.searchInput.focus());
+ })
+ .on('hidden.bs.dropdown', () => {
+ this.filter = '';
+ });
+ },
+};
+</script>
+<template>
+ <div class="dropdown">
+ <div class="btn-group">
+ <slot
+ name="mainAction"
+ :class-name="className"
+ >
+ <button
+ type="button"
+ :class="className"
+ >
+ {{ title }}
+ </button>
+ </slot>
+
+ <button
+ type="button"
+ :class="className"
+ class="dropdown-toggle dropdown-toggle-split"
+ data-toggle="dropdown"
+ aria-haspopup="true"
+ aria-expanded="false"
+ aria-label="Expand dropdown"
+ >
+ <icon
+ name="angle-down"
+ :size="12"
+ />
+ </button>
+ <div class="dropdown-menu dropdown-menu-right">
+ <div class="dropdown-input">
+ <input
+ ref="searchInput"
+ v-model="filter"
+ type="search"
+ placeholder="Filter"
+ class="js-filtered-dropdown-input dropdown-input-field"
+ />
+ <icon
+ class="dropdown-input-search"
+ name="search"
+ />
+ </div>
+
+ <div class="dropdown-content">
+ <ul>
+ <li
+ v-for="(result, i) in filteredResults"
+ :key="i"
+ class="js-filtered-dropdown-result"
+ >
+ <slot
+ name="result"
+ :result="result"
+ >
+ {{ result[filterKey] }}
+ </slot>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/gl_countdown.vue b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
new file mode 100644
index 00000000000..9327a2a4a6c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
@@ -0,0 +1,49 @@
+<script>
+import { calculateRemainingMilliseconds, formatTime } from '~/lib/utils/datetime_utility';
+
+/**
+ * Counts down to a given end date.
+ */
+export default {
+ props: {
+ endDateString: {
+ type: String,
+ required: true,
+ validator(value) {
+ return !Number.isNaN(new Date(value).getTime());
+ },
+ },
+ },
+
+ data() {
+ return {
+ remainingTime: formatTime(0),
+ countdownUpdateIntervalId: null,
+ };
+ },
+
+ mounted() {
+ const updateRemainingTime = () => {
+ const remainingMilliseconds = calculateRemainingMilliseconds(this.endDateString);
+ this.remainingTime = formatTime(remainingMilliseconds);
+ };
+
+ updateRemainingTime();
+ this.countdownUpdateIntervalId = window.setInterval(updateRemainingTime, 1000);
+ },
+
+ beforeDestroy() {
+ window.clearInterval(this.countdownUpdateIntervalId);
+ },
+};
+</script>
+
+<template>
+ <time
+ v-gl-tooltip
+ :datetime="endDateString"
+ :title="endDateString"
+ >
+ {{ remainingTime }}
+ </time>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index b371b6adf7e..aee88cae48d 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -69,6 +69,9 @@ export default {
onClickAction(action) {
this.$emit('actionClicked', action);
},
+ onClickSidebarButton() {
+ this.$emit('clickedSidebarButton');
+ },
},
};
</script>
@@ -161,21 +164,21 @@ export default {
</i>
</button>
</template>
- <button
- v-if="hasSidebarButton"
- id="toggleSidebar"
- type="button"
- class="btn btn-default d-block d-sm-none d-md-none
+ </section>
+ <button
+ v-if="hasSidebarButton"
+ id="toggleSidebar"
+ type="button"
+ class="btn btn-default d-block d-sm-none
sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header"
- aria-label="Toggle Sidebar"
+ @click="onClickSidebarButton"
+ >
+ <i
+ class="fa fa-angle-double-left"
+ aria-hidden="true"
+ aria-labelledby="toggleSidebar"
>
- <i
- class="fa fa-angle-double-left"
- aria-hidden="true"
- aria-labelledby="toggleSidebar"
- >
- </i>
- </button>
- </section>
+ </i>
+ </button>
</header>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue
index 5e0e7315e99..26f9d5ddc91 100644
--- a/app/assets/javascripts/vue_shared/components/icon.vue
+++ b/app/assets/javascripts/vue_shared/components/icon.vue
@@ -1,5 +1,4 @@
<script>
-
// only allow classes in images.scss e.g. s12
const validSizes = [8, 10, 12, 16, 18, 24, 32, 48, 72];
let iconValidator = () => true;
@@ -105,6 +104,7 @@ export default {
:x="x"
:y="y"
:tabindex="tabIndex"
+ aria-hidden="true"
>
<use v-bind="{ 'xlink:href':spriteHref }"/>
</svg>
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
index ca8ce554588..dc88749c18f 100644
--- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
@@ -1,34 +1,34 @@
<script>
- import icon from '../../../vue_shared/components/icon.vue';
+import icon from '../../../vue_shared/components/icon.vue';
- export default {
- components: {
- icon,
+export default {
+ components: {
+ icon,
+ },
+ props: {
+ isLocked: {
+ type: Boolean,
+ default: false,
+ required: false,
},
- props: {
- isLocked: {
- type: Boolean,
- default: false,
- required: false,
- },
- isConfidential: {
- type: Boolean,
- default: false,
- required: false,
- },
+ isConfidential: {
+ type: Boolean,
+ default: false,
+ required: false,
},
- computed: {
- warningIcon() {
- if (this.isConfidential) return 'eye-slash';
- if (this.isLocked) return 'lock';
+ },
+ computed: {
+ warningIcon() {
+ if (this.isConfidential) return 'eye-slash';
+ if (this.isLocked) return 'lock';
- return '';
- },
- isLockedAndConfidential() {
- return this.isConfidential && this.isLocked;
- },
+ return '';
},
- };
+ isLockedAndConfidential() {
+ return this.isConfidential && this.isLocked;
+ },
+ },
+};
</script>
<template>
<div class="issuable-note-warning">
@@ -37,7 +37,6 @@
:name="warningIcon"
:size="16"
class="icon inline"
- aria-hidden="true"
/>
<span v-if="isLockedAndConfidential">
diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue
index 4cbd3e6429d..f9b7fd5b1f9 100644
--- a/app/assets/javascripts/vue_shared/components/loading_button.vue
+++ b/app/assets/javascripts/vue_shared/components/loading_button.vue
@@ -1,6 +1,6 @@
<script>
- /* eslint-disable vue/require-default-prop */
- /* This is a re-usable vue component for rendering a button
+/* eslint-disable vue/require-default-prop */
+/* 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
@@ -17,34 +17,34 @@
*/
- export default {
- props: {
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- disabled: {
- type: Boolean,
- required: false,
- default: false,
- },
- label: {
- type: String,
- required: false,
- },
- containerClass: {
- type: [String, Array, Object],
- required: false,
- default: 'btn btn-align-content',
- },
+export default {
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- methods: {
- onClick(e) {
- this.$emit('click', e);
- },
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- };
+ label: {
+ type: String,
+ required: false,
+ },
+ containerClass: {
+ type: [String, Array, Object],
+ required: false,
+ default: 'btn btn-align-content',
+ },
+ },
+ methods: {
+ onClick(e) {
+ this.$emit('click', e);
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 10e8ddad9cd..4687de62614 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -1,141 +1,141 @@
<script>
- import $ from 'jquery';
- import { s__ } from '~/locale';
- import Flash from '../../../flash';
- import GLForm from '../../../gl_form';
- import markdownHeader from './header.vue';
- import markdownToolbar from './toolbar.vue';
- import icon from '../icon.vue';
+import $ from 'jquery';
+import { s__ } from '~/locale';
+import Flash from '../../../flash';
+import GLForm from '../../../gl_form';
+import markdownHeader from './header.vue';
+import markdownToolbar from './toolbar.vue';
+import icon from '../icon.vue';
- export default {
- components: {
- markdownHeader,
- markdownToolbar,
- icon,
+export default {
+ components: {
+ markdownHeader,
+ markdownToolbar,
+ icon,
+ },
+ props: {
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
},
- props: {
- markdownPreviewPath: {
- type: String,
- required: false,
- default: '',
- },
- markdownDocsPath: {
- type: String,
- required: true,
- },
- markdownVersion: {
- type: Number,
- required: false,
- default: 0,
- },
- addSpacingClasses: {
- type: Boolean,
- required: false,
- default: true,
- },
- quickActionsDocsPath: {
- type: String,
- required: false,
- default: '',
- },
- canAttachFile: {
- type: Boolean,
- required: false,
- default: true,
- },
- enableAutocomplete: {
- type: Boolean,
- required: false,
- default: true,
- },
+ markdownDocsPath: {
+ type: String,
+ required: true,
},
- data() {
- return {
- markdownPreview: '',
- referencedCommands: '',
- referencedUsers: '',
- markdownPreviewLoading: false,
- previewMarkdown: false,
- };
+ markdownVersion: {
+ type: Number,
+ required: false,
+ default: 0,
},
- computed: {
- shouldShowReferencedUsers() {
- const referencedUsersThreshold = 10;
- return this.referencedUsers.length >= referencedUsersThreshold;
- },
+ addSpacingClasses: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- mounted() {
- /*
- GLForm class handles all the toolbar buttons
- */
- return new GLForm($(this.$refs['gl-form']), {
- emojis: this.enableAutocomplete,
- members: this.enableAutocomplete,
- issues: this.enableAutocomplete,
- mergeRequests: this.enableAutocomplete,
- epics: this.enableAutocomplete,
- milestones: this.enableAutocomplete,
- labels: this.enableAutocomplete,
- snippets: this.enableAutocomplete,
- });
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
},
- beforeDestroy() {
- const glForm = $(this.$refs['gl-form']).data('glForm');
- if (glForm) {
- glForm.destroy();
- }
+ canAttachFile: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ enableAutocomplete: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- methods: {
- showPreviewTab() {
- if (this.previewMarkdown) return;
+ },
+ data() {
+ return {
+ markdownPreview: '',
+ referencedCommands: '',
+ referencedUsers: '',
+ markdownPreviewLoading: false,
+ previewMarkdown: false,
+ };
+ },
+ 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']), {
+ emojis: this.enableAutocomplete,
+ members: this.enableAutocomplete,
+ issues: this.enableAutocomplete,
+ mergeRequests: this.enableAutocomplete,
+ epics: this.enableAutocomplete,
+ milestones: this.enableAutocomplete,
+ labels: this.enableAutocomplete,
+ snippets: this.enableAutocomplete,
+ });
+ },
+ beforeDestroy() {
+ const glForm = $(this.$refs['gl-form']).data('glForm');
+ if (glForm) {
+ glForm.destroy();
+ }
+ },
+ methods: {
+ showPreviewTab() {
+ if (this.previewMarkdown) return;
- this.previewMarkdown = true;
+ this.previewMarkdown = true;
- /*
+ /*
Can't use `$refs` as the component is technically in the parent component
so we access the VNode & then get the element
*/
- const text = this.$slots.textarea[0].elm.value;
+ const text = this.$slots.textarea[0].elm.value;
- if (text) {
- this.markdownPreviewLoading = true;
- this.$http
- .post(this.versionedPreviewPath(), { text })
- .then(resp => resp.json())
- .then(data => this.renderMarkdown(data))
- .catch(() => new Flash(s__('Error loading markdown preview')));
- } else {
- this.renderMarkdown();
- }
- },
+ if (text) {
+ this.markdownPreviewLoading = true;
+ this.$http
+ .post(this.versionedPreviewPath(), { text })
+ .then(resp => resp.json())
+ .then(data => this.renderMarkdown(data))
+ .catch(() => new Flash(s__('Error loading markdown preview')));
+ } else {
+ this.renderMarkdown();
+ }
+ },
- showWriteTab() {
- this.markdownPreview = '';
- this.previewMarkdown = false;
- },
+ showWriteTab() {
+ this.markdownPreview = '';
+ this.previewMarkdown = false;
+ },
- renderMarkdown(data = {}) {
- this.markdownPreviewLoading = false;
- this.markdownPreview = data.body || 'Nothing to preview.';
+ renderMarkdown(data = {}) {
+ this.markdownPreviewLoading = false;
+ this.markdownPreview = data.body || 'Nothing to preview.';
- if (data.references) {
- this.referencedCommands = data.references.commands;
- this.referencedUsers = data.references.users;
- }
+ if (data.references) {
+ this.referencedCommands = data.references.commands;
+ this.referencedUsers = data.references.users;
+ }
- this.$nextTick(() => {
- $(this.$refs['markdown-preview']).renderGFM();
- });
- },
+ this.$nextTick(() => {
+ $(this.$refs['markdown-preview']).renderGFM();
+ });
+ },
- versionedPreviewPath() {
- const { markdownPreviewPath, markdownVersion } = this;
- return `${markdownPreviewPath}${
- markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
- }markdown_version=${markdownVersion}`;
- },
+ versionedPreviewPath() {
+ const { markdownPreviewPath, markdownVersion } = this;
+ return `${markdownPreviewPath}${
+ markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
+ }markdown_version=${markdownVersion}`;
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index ccd53158820..3ddb39730c4 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -1,63 +1,64 @@
<script>
- import $ from 'jquery';
- import tooltip from '../../directives/tooltip';
- import toolbarButton from './toolbar_button.vue';
- import icon from '../icon.vue';
+import $ from 'jquery';
+import Tooltip from '../../directives/tooltip';
+import ToolbarButton from './toolbar_button.vue';
+import Icon from '../icon.vue';
- export default {
- directives: {
- tooltip,
+export default {
+ directives: {
+ Tooltip,
+ },
+ components: {
+ ToolbarButton,
+ Icon,
+ },
+ props: {
+ previewMarkdown: {
+ type: Boolean,
+ required: true,
},
- components: {
- toolbarButton,
- icon,
+ },
+ computed: {
+ mdTable() {
+ return [
+ '| header | header |',
+ '| ------ | ------ |',
+ '| cell | cell |',
+ '| cell | cell |',
+ ].join('\n');
},
- props: {
- previewMarkdown: {
- type: Boolean,
- required: true,
- },
+ },
+ 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);
+ },
+ methods: {
+ isValid(form) {
+ return (
+ !form ||
+ (form.find('.js-vue-markdown-field').length && $(this.$el).closest('form')[0] === form[0])
+ );
},
- computed: {
- mdTable() {
- return [
- '| header | header |',
- '| ------ | ------ |',
- '| cell | cell |',
- '| cell | cell |',
- ].join('\n');
- },
- },
- 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);
- },
- methods: {
- isValid(form) {
- return !form ||
- form.find('.js-vue-markdown-field').length &&
- $(this.$el).closest('form')[0] === form[0];
- },
- previewMarkdownTab(event, form) {
- if (event.target.blur) event.target.blur();
- if (!this.isValid(form)) return;
+ previewMarkdownTab(event, form) {
+ if (event.target.blur) event.target.blur();
+ if (!this.isValid(form)) return;
- this.$emit('preview-markdown');
- },
+ this.$emit('preview-markdown');
+ },
- writeMarkdownTab(event, form) {
- if (event.target.blur) event.target.blur();
- if (!this.isValid(form)) return;
+ writeMarkdownTab(event, form) {
+ if (event.target.blur) event.target.blur();
+ if (!this.isValid(form)) return;
- this.$emit('write-markdown');
- },
+ this.$emit('write-markdown');
},
- };
+ },
+};
</script>
<template>
@@ -67,27 +68,27 @@
:class="{ active: !previewMarkdown }"
class="md-header-tab"
>
- <a
+ <button
class="js-write-link"
- href="#md-write-holder"
tabindex="-1"
- @click.prevent="writeMarkdownTab($event)"
+ type="button"
+ @click="writeMarkdownTab($event)"
>
Write
- </a>
+ </button>
</li>
<li
:class="{ active: previewMarkdown }"
class="md-header-tab"
>
- <a
+ <button
class="js-preview-link js-md-preview-button"
- href="#md-preview-holder"
tabindex="-1"
- @click.prevent="previewMarkdownTab($event)"
+ type="button"
+ @click="previewMarkdownTab($event)"
>
Preview
- </a>
+ </button>
</li>
<li
:class="{ active: !previewMarkdown }"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index c45dafa9807..feb7b8f227e 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -1,32 +1,32 @@
<script>
- import { Link } from '@gitlab-org/gitlab-ui';
+import { Link } from '@gitlab-org/gitlab-ui';
- export default {
- components: {
- 'gl-link': Link,
+export default {
+ components: {
+ 'gl-link': Link,
+ },
+ props: {
+ markdownDocsPath: {
+ type: String,
+ required: true,
},
- props: {
- markdownDocsPath: {
- type: String,
- required: true,
- },
- quickActionsDocsPath: {
- type: String,
- required: false,
- default: '',
- },
- canAttachFile: {
- type: Boolean,
- required: false,
- default: true,
- },
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
},
- computed: {
- hasQuickActionsDocsPath() {
- return this.quickActionsDocsPath !== '';
- },
+ canAttachFile: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- };
+ },
+ computed: {
+ hasQuickActionsDocsPath() {
+ return this.quickActionsDocsPath !== '';
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
index bda33636369..3e89e1c1e75 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
@@ -1,44 +1,44 @@
<script>
- import tooltip from '../../directives/tooltip';
- import icon from '../icon.vue';
+import tooltip from '../../directives/tooltip';
+import icon from '../icon.vue';
- export default {
- components: {
- icon,
+export default {
+ components: {
+ icon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ buttonTitle: {
+ type: String,
+ required: true,
},
- directives: {
- tooltip,
+ icon: {
+ type: String,
+ required: true,
},
- props: {
- buttonTitle: {
- type: String,
- required: true,
- },
- icon: {
- type: String,
- required: true,
- },
- tag: {
- type: String,
- required: true,
- },
- tagBlock: {
- type: String,
- required: false,
- default: '',
- },
- tagSelect: {
- type: String,
- required: false,
- default: '',
- },
- prepend: {
- type: Boolean,
- required: false,
- default: false,
- },
+ tag: {
+ type: String,
+ required: true,
},
- };
+ tagBlock: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tagSelect: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ prepend: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.vue b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index 552a92541be..964dedb38c4 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.vue
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -41,7 +41,8 @@ export default {
// Find metric timestamp which is closest to deploymentTime
timestampDiff = Math.abs(metricTimestamps[0] - median);
metricTimestamps.forEach((timestamp, index) => {
- if (index === 0) { // Skip first element
+ if (index === 0) {
+ // Skip first element
return;
}
diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
index 38115f268bb..dcad79e521d 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
@@ -1,41 +1,39 @@
<script>
- /**
- * Common component to render a placeholder note and user information.
- *
- * This component needs to be used with a vuex store.
- * That vuex store needs to have a `getUserData` getter that contains
- * {
- * path: String,
- * avatar_url: String,
- * name: String,
- * username: String,
- * }
- *
- * @example
- * <placeholder-note
- * :note="{body: 'This is a note'}"
- * />
- */
- import { mapGetters } from 'vuex';
- import userAvatarLink from '../user_avatar/user_avatar_link.vue';
+/**
+ * Common component to render a placeholder note and user information.
+ *
+ * This component needs to be used with a vuex store.
+ * That vuex store needs to have a `getUserData` getter that contains
+ * {
+ * path: String,
+ * avatar_url: String,
+ * name: String,
+ * username: String,
+ * }
+ *
+ * @example
+ * <placeholder-note
+ * :note="{body: 'This is a note'}"
+ * />
+ */
+import { mapGetters } from 'vuex';
+import userAvatarLink from '../user_avatar/user_avatar_link.vue';
- export default {
- name: 'PlaceholderNote',
- components: {
- userAvatarLink,
+export default {
+ name: 'PlaceholderNote',
+ components: {
+ userAvatarLink,
+ },
+ props: {
+ note: {
+ type: Object,
+ required: true,
},
- props: {
- note: {
- type: Object,
- required: true,
- },
- },
- computed: {
- ...mapGetters([
- 'getUserData',
- ]),
- },
- };
+ },
+ computed: {
+ ...mapGetters(['getUserData']),
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
index 95e2b38e292..674f923478d 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
@@ -1,21 +1,21 @@
<script>
- /**
- * Common component to render a placeholder system note.
- *
- * @example
- * <placeholder-system-note
- * :note="{ body: 'Commands are being applied'}"
- * />
- */
- export default {
- name: 'PlaceholderSystemNote',
- props: {
- note: {
- type: Object,
- required: true,
- },
+/**
+ * Common component to render a placeholder system note.
+ *
+ * @example
+ * <placeholder-system-note
+ * :note="{ body: 'Commands are being applied'}"
+ * />
+ */
+export default {
+ name: 'PlaceholderSystemNote',
+ props: {
+ note: {
+ type: Object,
+ required: true,
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
index 2122d0a508e..de3c7a80365 100644
--- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
@@ -109,7 +109,7 @@ export default {
class="system-note-commit-list-toggler flex-row"
@click="expanded = !expanded"
>
- <Icon
+ <icon
:name="toggleIcon"
:size="8"
class="append-right-5"
diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
index 7947ae1e4da..bf736a378dd 100644
--- a/app/assets/javascripts/vue_shared/components/panel_resizer.vue
+++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
@@ -1,90 +1,90 @@
<script>
- export default {
- props: {
- startSize: {
- type: Number,
- required: true,
- },
- side: {
- type: String,
- required: true,
- },
- minSize: {
- type: Number,
- required: false,
- default: 0,
- },
- maxSize: {
- type: Number,
- required: false,
- default: Number.MAX_VALUE,
- },
- enabled: {
- type: Boolean,
- required: false,
- default: true,
- },
+export default {
+ props: {
+ startSize: {
+ type: Number,
+ required: true,
},
- data() {
- return {
- size: this.startSize,
- };
+ side: {
+ type: String,
+ required: true,
},
- computed: {
- className() {
- return `drag-${this.side}`;
- },
- cursorStyle() {
- if (this.enabled) {
- return { cursor: 'ew-resize' };
- }
- return {};
- },
+ minSize: {
+ type: Number,
+ required: false,
+ default: 0,
},
- methods: {
- resetSize(e) {
- e.preventDefault();
- this.$emit('resize-start', this.size);
+ maxSize: {
+ type: Number,
+ required: false,
+ default: Number.MAX_VALUE,
+ },
+ enabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ size: this.startSize,
+ };
+ },
+ computed: {
+ className() {
+ return `drag-${this.side}`;
+ },
+ cursorStyle() {
+ if (this.enabled) {
+ return { cursor: 'ew-resize' };
+ }
+ return {};
+ },
+ },
+ methods: {
+ resetSize(e) {
+ e.preventDefault();
+ this.$emit('resize-start', this.size);
- this.size = this.startSize;
- this.$emit('update:size', this.size);
+ this.size = this.startSize;
+ this.$emit('update:size', this.size);
- // End resizing on next tick so that listeners can react to DOM changes
- this.$nextTick(() => {
- this.$emit('resize-end', this.size);
- });
- },
- startDrag(e) {
- if (this.enabled) {
- e.preventDefault();
- this.startPos = e.clientX;
- this.currentStartSize = this.size;
- document.addEventListener('mousemove', this.drag);
- document.addEventListener('mouseup', this.endDrag, { once: true });
- this.$emit('resize-start', this.size);
- }
- },
- drag(e) {
+ // End resizing on next tick so that listeners can react to DOM changes
+ this.$nextTick(() => {
+ this.$emit('resize-end', this.size);
+ });
+ },
+ startDrag(e) {
+ if (this.enabled) {
e.preventDefault();
- let moved = e.clientX - this.startPos;
- if (this.side === 'left') moved = -moved;
- let newSize = this.currentStartSize + moved;
- if (newSize < this.minSize) {
- newSize = this.minSize;
- } else if (newSize > this.maxSize) {
- newSize = this.maxSize;
- }
- this.size = newSize;
+ this.startPos = e.clientX;
+ this.currentStartSize = this.size;
+ document.addEventListener('mousemove', this.drag);
+ document.addEventListener('mouseup', this.endDrag, { once: true });
+ this.$emit('resize-start', this.size);
+ }
+ },
+ drag(e) {
+ e.preventDefault();
+ let moved = e.clientX - this.startPos;
+ if (this.side === 'left') moved = -moved;
+ let newSize = this.currentStartSize + moved;
+ if (newSize < this.minSize) {
+ newSize = this.minSize;
+ } else if (newSize > this.maxSize) {
+ newSize = this.maxSize;
+ }
+ this.size = newSize;
- this.$emit('update:size', newSize);
- },
- endDrag(e) {
- e.preventDefault();
- document.removeEventListener('mousemove', this.drag);
- this.$emit('resize-end', this.size);
- },
+ this.$emit('update:size', newSize);
+ },
+ endDrag(e) {
+ e.preventDefault();
+ document.removeEventListener('mousemove', this.drag);
+ this.$emit('resize-end', this.size);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/pikaday.vue b/app/assets/javascripts/vue_shared/components/pikaday.vue
index bfeece12077..26c99aecae4 100644
--- a/app/assets/javascripts/vue_shared/components/pikaday.vue
+++ b/app/assets/javascripts/vue_shared/components/pikaday.vue
@@ -1,62 +1,62 @@
<script>
- import Pikaday from 'pikaday';
- import { parsePikadayDate, pikadayToString } from '../../lib/utils/datefix';
+import Pikaday from 'pikaday';
+import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
- export default {
- name: 'DatePicker',
- props: {
- label: {
- type: String,
- required: false,
- default: 'Date picker',
- },
- selectedDate: {
- type: Date,
- required: false,
- default: null,
- },
- minDate: {
- type: Date,
- required: false,
- default: null,
- },
- maxDate: {
- type: Date,
- required: false,
- default: null,
- },
+export default {
+ name: 'DatePicker',
+ props: {
+ label: {
+ type: String,
+ required: false,
+ default: 'Date picker',
},
- mounted() {
- this.calendar = new Pikaday({
- field: this.$el.querySelector('.dropdown-menu-toggle'),
- theme: 'gitlab-theme animate-picker',
- format: 'yyyy-mm-dd',
- container: this.$el,
- defaultDate: this.selectedDate,
- setDefaultDate: !!this.selectedDate,
- minDate: this.minDate,
- maxDate: this.maxDate,
- parse: dateString => parsePikadayDate(dateString),
- toString: date => pikadayToString(date),
- onSelect: this.selected.bind(this),
- onClose: this.toggled.bind(this),
- });
-
- this.$el.append(this.calendar.el);
- this.calendar.show();
+ selectedDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ minDate: {
+ type: Date,
+ required: false,
+ default: null,
},
- beforeDestroy() {
- this.calendar.destroy();
+ maxDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ },
+ mounted() {
+ this.calendar = new Pikaday({
+ field: this.$el.querySelector('.dropdown-menu-toggle'),
+ theme: 'gitlab-theme animate-picker',
+ format: 'yyyy-mm-dd',
+ container: this.$el,
+ defaultDate: this.selectedDate,
+ setDefaultDate: !!this.selectedDate,
+ minDate: this.minDate,
+ maxDate: this.maxDate,
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
+ onSelect: this.selected.bind(this),
+ onClose: this.toggled.bind(this),
+ });
+
+ this.$el.append(this.calendar.el);
+ this.calendar.show();
+ },
+ beforeDestroy() {
+ this.calendar.destroy();
+ },
+ methods: {
+ selected(dateText) {
+ this.$emit('newDateSelected', this.calendar.toString(dateText));
},
- methods: {
- selected(dateText) {
- this.$emit('newDateSelected', this.calendar.toString(dateText));
- },
- toggled() {
- this.$emit('hidePicker');
- },
+ toggled() {
+ this.$emit('hidePicker');
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
index 97ca4d93bd7..1a2fd2ad985 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
@@ -1,6 +1,5 @@
<script>
-
- /* This is a re-usable vue component for rendering a project avatar that
+/* This is a re-usable vue component for rendering a project avatar that
does not need to link to the project's profile. The image and an optional
tooltip can be configured by props passed to this component.
@@ -16,70 +15,70 @@
*/
- import defaultAvatarUrl from 'images/no_avatar.png';
- import { placeholderImage } from '../../../lazy_loader';
- import tooltip from '../../directives/tooltip';
+import defaultAvatarUrl from 'images/no_avatar.png';
+import { placeholderImage } from '../../../lazy_loader';
+import tooltip from '../../directives/tooltip';
- export default {
- name: 'ProjectAvatarImage',
- directives: {
- tooltip,
+export default {
+ name: 'ProjectAvatarImage',
+ directives: {
+ tooltip,
+ },
+ props: {
+ lazy: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ imgSrc: {
+ type: String,
+ required: false,
+ default: defaultAvatarUrl,
+ },
+ cssClasses: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ imgAlt: {
+ type: String,
+ required: false,
+ default: 'project avatar',
+ },
+ size: {
+ type: Number,
+ required: false,
+ default: 20,
+ },
+ tooltipText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tooltipPlacement: {
+ type: String,
+ required: false,
+ default: 'top',
+ },
+ },
+ computed: {
+ // API response sends null when gravatar is disabled and
+ // we provide an empty string when we use it inside project avatar link.
+ // In both cases we should render the defaultAvatarUrl
+ sanitizedSource() {
+ return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
+ },
+ resultantSrcAttribute() {
+ return this.lazy ? placeholderImage : this.sanitizedSource;
},
- props: {
- lazy: {
- type: Boolean,
- required: false,
- default: false,
- },
- imgSrc: {
- type: String,
- required: false,
- default: defaultAvatarUrl,
- },
- cssClasses: {
- type: String,
- required: false,
- default: '',
- },
- imgAlt: {
- type: String,
- required: false,
- default: 'project avatar',
- },
- size: {
- type: Number,
- required: false,
- default: 20,
- },
- tooltipText: {
- type: String,
- required: false,
- default: '',
- },
- tooltipPlacement: {
- type: String,
- required: false,
- default: 'top',
- },
+ tooltipContainer() {
+ return this.tooltipText ? 'body' : null;
},
- computed: {
- // API response sends null when gravatar is disabled and
- // we provide an empty string when we use it inside project avatar link.
- // In both cases we should render the defaultAvatarUrl
- sanitizedSource() {
- return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
- },
- resultantSrcAttribute() {
- return this.lazy ? placeholderImage : this.sanitizedSource;
- },
- tooltipContainer() {
- return this.tooltipText ? 'body' : null;
- },
- avatarSizeClass() {
- return `s${this.size}`;
- },
+ avatarSizeClass() {
+ return `s${this.size}`;
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
index a2a9a5e6987..09394847b10 100644
--- a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
@@ -1,67 +1,67 @@
<script>
- import DeprecatedModal from './deprecated_modal.vue';
+import DeprecatedModal from './deprecated_modal.vue';
- export default {
- name: 'RecaptchaModal',
+export default {
+ name: 'RecaptchaModal',
- components: {
- DeprecatedModal,
- },
+ components: {
+ DeprecatedModal,
+ },
- props: {
- html: {
- type: String,
- required: false,
- default: '',
- },
+ props: {
+ html: {
+ type: String,
+ required: false,
+ default: '',
},
+ },
- data() {
- return {
- script: {},
- scriptSrc: 'https://www.google.com/recaptcha/api.js',
- };
- },
+ data() {
+ return {
+ script: {},
+ scriptSrc: 'https://www.google.com/recaptcha/api.js',
+ };
+ },
- watch: {
- html() {
- this.appendRecaptchaScript();
- },
+ watch: {
+ html() {
+ this.appendRecaptchaScript();
},
+ },
- mounted() {
- window.recaptchaDialogCallback = this.submit.bind(this);
- },
+ mounted() {
+ window.recaptchaDialogCallback = this.submit.bind(this);
+ },
- methods: {
- appendRecaptchaScript() {
- this.removeRecaptchaScript();
+ methods: {
+ appendRecaptchaScript() {
+ this.removeRecaptchaScript();
- const script = document.createElement('script');
- script.src = this.scriptSrc;
- script.classList.add('js-recaptcha-script');
- script.async = true;
- script.defer = true;
+ const script = document.createElement('script');
+ script.src = this.scriptSrc;
+ script.classList.add('js-recaptcha-script');
+ script.async = true;
+ script.defer = true;
- this.script = script;
+ this.script = script;
- document.body.appendChild(script);
- },
+ document.body.appendChild(script);
+ },
- removeRecaptchaScript() {
- if (this.script instanceof Element) this.script.remove();
- },
+ removeRecaptchaScript() {
+ if (this.script instanceof Element) this.script.remove();
+ },
- close() {
- this.removeRecaptchaScript();
- this.$emit('close');
- },
+ close() {
+ this.removeRecaptchaScript();
+ this.$emit('close');
+ },
- submit() {
- this.$el.querySelector('form').submit();
- },
+ submit() {
+ this.$el.querySelector('form').submit();
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
index 9d757b27edc..500586302cf 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
@@ -1,96 +1,96 @@
<script>
- import datePicker from '../pikaday.vue';
- import toggleSidebar from './toggle_sidebar.vue';
- import collapsedCalendarIcon from './collapsed_calendar_icon.vue';
- import { dateInWords } from '../../../lib/utils/datetime_utility';
+import datePicker from '../pikaday.vue';
+import toggleSidebar from './toggle_sidebar.vue';
+import collapsedCalendarIcon from './collapsed_calendar_icon.vue';
+import { dateInWords } from '../../../lib/utils/datetime_utility';
- export default {
- name: 'SidebarDatePicker',
- components: {
- datePicker,
- toggleSidebar,
- collapsedCalendarIcon,
- },
- props: {
- blockClass: {
- type: String,
- required: false,
- default: '',
- },
- collapsed: {
- type: Boolean,
- required: false,
- default: true,
- },
- showToggleSidebar: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
- editable: {
- type: Boolean,
- required: false,
- default: false,
- },
- label: {
- type: String,
- required: false,
- default: 'Date picker',
- },
- selectedDate: {
- type: Date,
- required: false,
- default: null,
- },
- minDate: {
- type: Date,
- required: false,
- default: null,
- },
- maxDate: {
- type: Date,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- editing: false,
- };
- },
- computed: {
- selectedAndEditable() {
- return this.selectedDate && this.editable;
- },
- selectedDateWords() {
- return dateInWords(this.selectedDate, true);
- },
- collapsedText() {
- return this.selectedDateWords ? this.selectedDateWords : 'None';
- },
- },
- methods: {
- stopEditing() {
- this.editing = false;
- },
- toggleDatePicker() {
- this.editing = !this.editing;
- },
- newDateSelected(date = null) {
- this.date = date;
- this.editing = false;
- this.$emit('saveDate', date);
- },
- toggleSidebar() {
- this.$emit('toggleCollapse');
- },
- },
- };
+export default {
+ name: 'SidebarDatePicker',
+ components: {
+ datePicker,
+ toggleSidebar,
+ collapsedCalendarIcon,
+ },
+ props: {
+ blockClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ collapsed: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showToggleSidebar: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ editable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ label: {
+ type: String,
+ required: false,
+ default: 'Date picker',
+ },
+ selectedDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ minDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ maxDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ editing: false,
+ };
+ },
+ computed: {
+ selectedAndEditable() {
+ return this.selectedDate && this.editable;
+ },
+ selectedDateWords() {
+ return dateInWords(this.selectedDate, true);
+ },
+ collapsedText() {
+ return this.selectedDateWords ? this.selectedDateWords : 'None';
+ },
+ },
+ methods: {
+ stopEditing() {
+ this.editing = false;
+ },
+ toggleDatePicker() {
+ this.editing = !this.editing;
+ },
+ newDateSelected(date = null) {
+ this.date = date;
+ this.editing = false;
+ this.$emit('saveDate', date);
+ },
+ toggleSidebar() {
+ this.$emit('toggleCollapse');
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 8e9621c956f..03a5a078879 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -1,17 +1,17 @@
<script>
- import { s__ } from '../../locale';
-
- const PAGINATION_UI_BUTTON_LIMIT = 4;
- const UI_LIMIT = 6;
- const SPREAD = '...';
- const PREV = s__('Pagination|Prev');
- const NEXT = s__('Pagination|Next');
- const FIRST = s__('Pagination|« First');
- const LAST = s__('Pagination|Last »');
-
- export default {
- props: {
- /**
+import { s__ } from '../../locale';
+
+const PAGINATION_UI_BUTTON_LIMIT = 4;
+const UI_LIMIT = 6;
+const SPREAD = '...';
+const PREV = s__('Pagination|Prev');
+const NEXT = s__('Pagination|Next');
+const FIRST = s__('Pagination|« First');
+const LAST = s__('Pagination|Last »');
+
+export default {
+ props: {
+ /**
This function will take the information given by the pagination component
Here is an example `change` method:
@@ -20,12 +20,12 @@
gl.utils.visitUrl(`?page=${pagenum}`);
},
*/
- change: {
- type: Function,
- required: true,
- },
+ change: {
+ type: Function,
+ required: true,
+ },
- /**
+ /**
pageInfo will come from the headers of the API call
in the `.then` clause of the VueResource API call
there should be a function that contructs the pageInfo for this component
@@ -41,94 +41,94 @@
previousPage: +headers['X-Prev-Page'],
});
*/
- pageInfo: {
- type: Object,
- required: true,
- },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ prev() {
+ return this.pageInfo.previousPage;
+ },
+ next() {
+ return this.pageInfo.nextPage;
+ },
+ getItems() {
+ const total = this.pageInfo.totalPages;
+ const { page } = this.pageInfo;
+ const items = [];
+
+ if (page > 1) {
+ items.push({ title: FIRST, first: true });
+ }
+
+ if (page > 1) {
+ items.push({ title: PREV, prev: true });
+ } else {
+ items.push({ title: PREV, disabled: true, prev: true });
+ }
+
+ if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true });
+
+ const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
+ const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);
+
+ for (let i = start; i <= end; i += 1) {
+ const isActive = i === page;
+ items.push({ title: i, active: isActive, page: true });
+ }
+
+ if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
+ items.push({ title: SPREAD, separator: true, page: true });
+ }
+
+ if (page === total) {
+ items.push({ title: NEXT, disabled: true, next: true });
+ } else if (total - page >= 1) {
+ items.push({ title: NEXT, next: true });
+ }
+
+ if (total - page >= 1) {
+ items.push({ title: LAST, last: true });
+ }
+
+ return items;
+ },
+ showPagination() {
+ return this.pageInfo.totalPages > 1;
},
- computed: {
- prev() {
- return this.pageInfo.previousPage;
- },
- next() {
- return this.pageInfo.nextPage;
- },
- getItems() {
- const total = this.pageInfo.totalPages;
- const { page } = this.pageInfo;
- const items = [];
-
- if (page > 1) {
- items.push({ title: FIRST, first: true });
- }
-
- if (page > 1) {
- items.push({ title: PREV, prev: true });
- } else {
- items.push({ title: PREV, disabled: true, prev: true });
- }
-
- if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true });
-
- const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
- const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);
-
- for (let i = start; i <= end; i += 1) {
- const isActive = i === page;
- items.push({ title: i, active: isActive, page: true });
- }
-
- if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
- items.push({ title: SPREAD, separator: true, page: true });
- }
-
- if (page === total) {
- items.push({ title: NEXT, disabled: true, next: true });
- } else if (total - page >= 1) {
- items.push({ title: NEXT, next: true });
- }
-
- if (total - page >= 1) {
- items.push({ title: LAST, last: true });
- }
-
- return items;
- },
- showPagination() {
- return this.pageInfo.totalPages > 1;
- },
+ },
+ methods: {
+ changePage(text, isDisabled) {
+ if (isDisabled) return;
+
+ const { totalPages, nextPage, previousPage } = this.pageInfo;
+
+ switch (text) {
+ case SPREAD:
+ break;
+ case LAST:
+ this.change(totalPages);
+ break;
+ case NEXT:
+ this.change(nextPage);
+ break;
+ case PREV:
+ this.change(previousPage);
+ break;
+ case FIRST:
+ this.change(1);
+ break;
+ default:
+ this.change(+text);
+ break;
+ }
},
- methods: {
- changePage(text, isDisabled) {
- if (isDisabled) return;
-
- const { totalPages, nextPage, previousPage } = this.pageInfo;
-
- switch (text) {
- case SPREAD:
- break;
- case LAST:
- this.change(totalPages);
- break;
- case NEXT:
- this.change(nextPage);
- break;
- case PREV:
- this.change(previousPage);
- break;
- case FIRST:
- this.change(1);
- break;
- default:
- this.change(+text);
- break;
- }
- },
- hideOnSmallScreen(item) {
- return !item.first && !item.last && !item.next && !item.prev && !item.active;
- },
+ hideOnSmallScreen(item) {
+ return !item.first && !item.last && !item.next && !item.prev && !item.active;
},
- };
+ },
+};
</script>
<template>
<div
diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
index 368eeb6c453..d760263929a 100644
--- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
+++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
@@ -11,9 +11,7 @@ export default {
directives: {
tooltip,
},
- mixins: [
- timeagoMixin,
- ],
+ mixins: [timeagoMixin],
props: {
time: {
type: String,
diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue
index 5b9c51786d6..4e9289cbed8 100644
--- a/app/assets/javascripts/vue_shared/components/toggle_button.vue
+++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue
@@ -1,60 +1,60 @@
<script>
- import { s__ } from '../../locale';
- import icon from './icon.vue';
+import { s__ } from '../../locale';
+import icon from './icon.vue';
- const ICON_ON = 'status_success_borderless';
- const ICON_OFF = 'status_failed_borderless';
- const LABEL_ON = s__('ToggleButton|Toggle Status: ON');
- const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF');
+const ICON_ON = 'status_success_borderless';
+const ICON_OFF = 'status_failed_borderless';
+const LABEL_ON = s__('ToggleButton|Toggle Status: ON');
+const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF');
- export default {
- components: {
- icon,
- },
+export default {
+ components: {
+ icon,
+ },
- model: {
- prop: 'value',
- event: 'change',
- },
+ model: {
+ prop: 'value',
+ event: 'change',
+ },
- props: {
- name: {
- type: String,
- required: false,
- default: null,
- },
- value: {
- type: Boolean,
- required: false,
- default: null,
- },
- disabledInput: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
+ props: {
+ name: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ value: {
+ type: Boolean,
+ required: false,
+ default: null,
},
+ disabledInput: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
- computed: {
- toggleIcon() {
- return this.value ? ICON_ON : ICON_OFF;
- },
- ariaLabel() {
- return this.value ? LABEL_ON : LABEL_OFF;
- },
+ computed: {
+ toggleIcon() {
+ return this.value ? ICON_ON : ICON_OFF;
+ },
+ ariaLabel() {
+ return this.value ? LABEL_ON : LABEL_OFF;
},
+ },
- methods: {
- toggleFeature() {
- if (!this.disabledInput) this.$emit('change', !this.value);
- },
+ methods: {
+ toggleFeature() {
+ if (!this.disabledInput) this.$emit('change', !this.value);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
index ee3157bcb1b..14cb44b8619 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
@@ -1,5 +1,4 @@
<script>
-
/* This is a re-usable vue component for rendering a user avatar wrapped in
a clickable link (likely to the user's profile). The link, image, and
tooltip can be configured by props passed to this component.
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
index ef3b16edf5f..8e460566d09 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
@@ -1,5 +1,4 @@
<script>
-
/* This is a re-usable vue component for rendering a user avatar svg (typically
for a blank state). It will receive styles comparable to the user avatar,
but no image is loaded, it isn't wrapped in a link, and tooltips aren't supported.
@@ -42,4 +41,3 @@ export default {
v-html="svg"
/>
</template>
-