diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared')
35 files changed, 928 insertions, 851 deletions
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 fc795936abf..5324d5dc797 100644 --- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue +++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue index 2a018f38366..8fea746f4de 100644 --- a/app/assets/javascripts/vue_shared/components/ci_icon.vue +++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue index 3a7143c450e..e18852af6e9 100644 --- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue +++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue @@ -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"> - <i - aria-hidden="true" - class="fa fa-clipboard"> - </i> + :data-clipboard-text="text" + > + <i + aria-hidden="true" + class="fa fa-clipboard" + > + </i> </button> </template> diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue index 59ca9a0a6d4..6d1fe7ee8ca 100644 --- a/app/assets/javascripts/vue_shared/components/commit.vue +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue index 05e48ed297f..3595a9389e9 100644 --- a/app/assets/javascripts/vue_shared/components/expand_button.vue +++ b/app/assets/javascripts/vue_shared/components/expand_button.vue @@ -11,7 +11,7 @@ * </expand-button> */ export default { - name: 'expandButton', + name: 'ExpandButton', data() { return { isCollapsed: true, diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 65c64967fdc..c9d7c0f4999 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -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" 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 2209bc0f9cf..1f72dea1b33 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -1,80 +1,78 @@ <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'; - -/** - * Renders header component for job and pipeline page based on UI mockups - * - * Used in: - * - job show page - * - pipeline show page - */ -export default { - props: { - status: { - type: Object, - required: true, - }, - itemName: { - type: String, - required: true, - }, - itemId: { - type: Number, - required: true, - }, - time: { - type: String, - required: true, - }, - user: { - type: Object, - required: false, - default: () => ({}), + 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 { + components: { + ciIconBadge, + loadingIcon, + timeagoTooltip, + userAvatarImage, }, - actions: { - type: Array, - required: false, - default: () => [], + directives: { + tooltip, }, - hasSidebarButton: { - type: Boolean, - required: false, - default: false, + props: { + status: { + type: Object, + required: true, + }, + itemName: { + type: String, + required: true, + }, + itemId: { + type: Number, + required: true, + }, + time: { + type: String, + required: true, + }, + user: { + type: Object, + required: false, + default: () => ({}), + }, + actions: { + type: Array, + required: false, + default: () => [], + }, + hasSidebarButton: { + type: Boolean, + required: false, + default: false, + }, + shouldRenderTriggeredLabel: { + type: Boolean, + required: false, + default: true, + }, }, - shouldRenderTriggeredLabel: { - type: Boolean, - required: false, - default: true, - }, - }, - - directives: { - tooltip, - }, - - components: { - ciIconBadge, - loadingIcon, - timeagoTooltip, - userAvatarImage, - }, - computed: { - userAvatarAltText() { - return `${this.user.name}'s avatar`; + computed: { + userAvatarAltText() { + return `${this.user.name}'s avatar`; + }, }, - }, - methods: { - onClickAction(action) { - this.$emit('actionClicked', action); + methods: { + onClickAction(action) { + this.$emit('actionClicked', action); + }, }, - }, -}; + }; </script> <template> @@ -84,7 +82,7 @@ export default { <ci-icon-badge :status="status" /> <strong> - {{itemName}} #{{itemId}} + {{ itemName }} #{{ itemId }} </strong> <template v-if="shouldRenderTriggeredLabel"> @@ -103,16 +101,17 @@ 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" :img-alt="userAvatarAltText" :tooltip-text="user.name" :img-size="24" - /> + /> - {{user.name}} + {{ user.name }} </a> </template> </section> @@ -121,12 +120,15 @@ export default { class="header-action-buttons" 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 @@ -134,8 +136,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 @@ -143,25 +147,31 @@ 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> <button v-if="hasSidebarButton" type="button" - class="btn btn-default visible-xs-block visible-sm-block sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header" + class="btn btn-default visible-xs-block +visible-sm-block sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header" aria-label="Toggle Sidebar" - id="toggleSidebar"> + id="toggleSidebar" + > <i class="fa fa-angle-double-left" aria-hidden="true" - aria-labelledby="toggleSidebar"> + aria-labelledby="toggleSidebar" + > </i> </button> </section> diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue index 365229ea274..6a2e05000e1 100644 --- a/app/assets/javascripts/vue_shared/components/icon.vue +++ b/app/assets/javascripts/vue_shared/components/icon.vue @@ -1,17 +1,17 @@ <script> -/* This is a re-usable vue component for rendering a svg sprite - icon + /* This is a re-usable vue component for rendering a svg sprite + icon - Sample configuration: + Sample configuration: - <icon - name="retry" - :size="32" - css-classes="top" - /> + <icon + name="retry" + :size="32" + 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> diff --git a/app/assets/javascripts/vue_shared/components/identicon.vue b/app/assets/javascripts/vue_shared/components/identicon.vue index 7cf2e029cf6..0a30f467b08 100644 --- a/app/assets/javascripts/vue_shared/components/identicon.vue +++ b/app/assets/javascripts/vue_shared/components/identicon.vue @@ -46,6 +46,6 @@ export default { class="avatar identicon" :class="sizeClass" :style="identiconStyles"> - {{identiconTitle}} + {{ identiconTitle }} </div> </template> 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 564fc5029af..b48828ae81f 100644 --- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue +++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue @@ -1,7 +1,10 @@ <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'; @@ -37,16 +36,17 @@ <template> <div class="issuable-note-warning"> <icon - :name="warningIcon" - :size="16" - class="icon inline" - aria-hidden="true" - v-if="!isLockedAndConfidential"> - </icon> + :name="warningIcon" + :size="16" + class="icon inline" + aria-hidden="true" + v-if="!isLockedAndConfidential" + /> <span v-if="isLockedAndConfidential"> {{ __('This issue is confidential and locked.') }} - {{ __('People without permission will never get a notification and won\'t be able to comment.') }} + {{ __(`People without permission will never +get a notification and won't be able to comment.`) }} </span> <span v-else-if="isConfidential"> diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue index 247943f83e6..ff8c0f7c1d2 100644 --- a/app/assets/javascripts/vue_shared/components/loading_button.vue +++ b/app/assets/javascripts/vue_shared/components/loading_button.vue @@ -1,55 +1,56 @@ <script> + /* 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 - know the action of the button yet by setting - `loading: true, label: undefined`. + /* 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 + know the action of the button yet by setting + `loading: true, label: undefined`. - Sample configuration: + Sample configuration: - <loading-button - :loading="true" - :label="Hello" - @click="..." - /> + <loading-button + :loading="true" + :label="Hello" + @click="..." + /> -*/ + */ -import loadingIcon from './loading_icon.vue'; + import loadingIcon from './loading_icon.vue'; -export default { - props: { - loading: { - type: Boolean, - required: false, - default: false, + export default { + components: { + loadingIcon, }, - disabled: { - type: Boolean, - required: false, - default: false, + props: { + loading: { + type: Boolean, + required: false, + default: false, + }, + disabled: { + type: Boolean, + required: false, + default: false, + }, + label: { + type: String, + required: false, + }, + containerClass: { + type: String, + required: false, + default: 'btn btn-align-content', + }, }, - label: { - type: String, - required: false, + methods: { + onClick(e) { + this.$emit('click', e); + }, }, - containerClass: { - type: String, - required: false, - default: 'btn btn-align-content', - }, - }, - components: { - loadingIcon, - }, - methods: { - onClick(e) { - this.$emit('click', e); - }, - }, -}; + }; </script> <template> @@ -59,23 +60,23 @@ export default { :class="containerClass" :disabled="loading || disabled" > - <transition name="fade"> - <loading-icon - v-if="loading" - :inline="true" - class="js-loading-button-icon" - :class="{ - 'append-right-5': label - }" - /> - </transition> - <transition name="fade"> - <span - v-if="label" - class="js-loading-button-label" - > - {{ label }} - </span> - </transition> + <transition name="fade"> + <loading-icon + v-if="loading" + :inline="true" + class="js-loading-button-icon" + :class="{ + 'append-right-5': label + }" + /> + </transition> + <transition name="fade"> + <span + v-if="label" + class="js-loading-button-label" + > + {{ label }} + </span> + </transition> </button> </template> diff --git a/app/assets/javascripts/vue_shared/components/loading_icon.vue b/app/assets/javascripts/vue_shared/components/loading_icon.vue index 15581d5c2a0..1eba117b18f 100644 --- a/app/assets/javascripts/vue_shared/components/loading_icon.vue +++ b/app/assets/javascripts/vue_shared/components/loading_icon.vue @@ -32,13 +32,14 @@ </script> <template> <component - :is="this.rootElementType" + :is="rootElementType" class="text-center"> <i class="fa fa-spin fa-spinner" :class="cssClass" aria-hidden="true" - :aria-label="label"> + :aria-label="label" + > </i> </component> </template> diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 15e3d713448..1371dca0c35 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -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,34 +122,39 @@ <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" :quick-actions-docs-path="quickActionsDocsPath" :can-attach-file="canAttachFile" - /> + /> </div> </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,23 +164,27 @@ <div v-if="referencedCommands" v-html="referencedCommands" - class="referenced-commands"></div> + class="referenced-commands" + > + </div> <div v-if="shouldShowReferencedUsers" - class="referenced-users"> - <span> - <i - class="fa fa-exclamation-triangle" - aria-hidden="true"> - </i> - You are about to add - <strong> - <span class="js-referenced-users-count"> - {{referencedUsers.length}} - </span> - </strong> people to the discussion. Proceed with caution. - </span> - </div> + class="referenced-users" + > + <span> + <i + class="fa fa-exclamation-triangle" + aria-hidden="true" + > + </i> + You are about to add + <strong> + <span class="js-referenced-users-count"> + {{ referencedUsers.length }} + </span> + </strong> people to the discussion. Proceed with caution. + </span> + </div> </template> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 36d2d1dc164..f65eab11a27 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue index ea2509d2839..c0ee88bbf72 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue @@ -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"> - <a + <template v-if="hasQuickActionsDocsPath && markdownDocsPath"> + <a :href="markdownDocsPath" target="_blank" - tabindex="-1"> + tabindex="-1" + > Markdown </a> and - <a + <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"> - Try again + 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> 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 e3e41f8f0ca..2d2d69ebeb2 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue @@ -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> diff --git a/app/assets/javascripts/vue_shared/components/modal.vue b/app/assets/javascripts/vue_shared/components/modal.vue index 00089dfef38..c103c45c7dd 100644 --- a/app/assets/javascripts/vue_shared/components/modal.vue +++ b/app/assets/javascripts/vue_shared/components/modal.vue @@ -1,143 +1,153 @@ <script> -export default { - name: 'modal', + /* eslint-disable vue/require-default-prop */ + export default { + name: 'Modal', - props: { - id: { - type: String, - required: 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: '', + }, + submitDisabled: { + type: Boolean, + required: false, + default: 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: '', - }, - submitDisabled: { - type: Boolean, - required: false, - default: false, - }, - }, - computed: { - btnKindClass() { - return { - [`btn-${this.kind}`]: true, - }; + computed: { + btnKindClass() { + return { + [`btn-${this.kind}`]: true, + }; + }, + btnCancelKindClass() { + return { + [`btn-${this.closeKind}`]: 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> -<div class="modal-open"> - <div - :id="id" - class="modal" - :class="id ? '' : 'show'" - role="dialog" - tabindex="-1" - > + <div class="modal-open"> <div - :class="modalDialogClass" - class="modal-dialog" - role="document" + :id="id" + class="modal" + :class="id ? '' : 'show'" + role="dialog" + tabindex="-1" > - <div class="modal-content"> - <div class="modal-header"> - <slot name="header"> - <h4 class="modal-title pull-left"> - {{this.title}} - </h4> + <div + :class="modalDialogClass" + class="modal-dialog" + role="document" + > + <div class="modal-content"> + <div class="modal-header"> + <slot name="header"> + <h4 class="modal-title pull-left"> + {{ title }} + </h4> + <button + type="button" + class="close pull-right" + @click="emitCancel($event)" + data-dismiss="modal" + aria-label="Close" + > + <span aria-hidden="true">×</span> + </button> + </slot> + </div> + <div class="modal-body"> + <slot + name="body" + :text="text" + > + <p>{{ text }}</p> + </slot> + </div> + <div + class="modal-footer" + v-if="!hideFooter" + > <button type="button" - class="close pull-right" + class="btn pull-left" + :class="btnCancelKindClass" @click="emitCancel($event)" data-dismiss="modal" - aria-label="Close" > - <span aria-hidden="true">×</span> + {{ closeButtonLabel }} </button> - </slot> - </div> - <div class="modal-body"> - <slot name="body" :text="text"> - <p>{{this.text}}</p> - </slot> - </div> - <div class="modal-footer" v-if="!hideFooter"> - <button - type="button" - class="btn pull-left" - :class="btnCancelKindClass" - @click="emitCancel($event)" - data-dismiss="modal"> - {{ closeButtonLabel }} - </button> - <button - v-if="primaryButtonLabel" - type="button" - class="btn pull-right js-primary-button" - :disabled="submitDisabled" - :class="btnKindClass" - @click="emitSubmit($event)" - data-dismiss="modal"> - {{ primaryButtonLabel }} - </button> + <button + v-if="primaryButtonLabel" + type="button" + class="btn pull-right js-primary-button" + :disabled="submitDisabled" + :class="btnKindClass" + @click="emitSubmit($event)" + data-dismiss="modal" + > + {{ primaryButtonLabel }} + </button> + </div> </div> </div> </div> + <div + v-if="!id" + class="modal-backdrop fade in" + > + </div> </div> - <div - v-if="!id" - class="modal-backdrop fade in"> - </div> -</div> </template> diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue index a2ddd565170..cb8e6072a9b 100644 --- a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue +++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue @@ -45,7 +45,7 @@ this.$emit('onChangeTab', tab.scope); }, }, -}; + }; </script> <template> <ul class="nav-links scrolling-tabs"> @@ -55,21 +55,20 @@ :class="{ active: tab.isActive, }" - > + > <a role="button" @click="onTabClick(tab)" :class="`js-${scope}-tab-${tab.scope}`" - > + > {{ tab.name }} <span v-if="shouldRenderBadge(tab.count)" class="badge" - > - {{tab.count}} + > + {{ tab.count }} </span> - </a> </li> </ul> 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 e467ca56704..50b1508691b 100644 --- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue @@ -20,16 +20,16 @@ import userAvatarLink from '../user_avatar/user_avatar_link.vue'; export default { - name: 'placeholderNote', + name: 'PlaceholderNote', + components: { + userAvatarLink, + }, props: { note: { type: Object, required: true, }, }, - components: { - userAvatarLink, - }, computed: { ...mapGetters([ 'getUserData', @@ -46,7 +46,7 @@ :link-href="getUserData.path" :img-src="getUserData.avatar_url" :img-size="40" - /> + /> </div> <div :class="{ discussion: !note.individual_note }" @@ -54,14 +54,14 @@ <div class="note-header"> <div class="note-header-info"> <a :href="getUserData.path"> - <span class="hidden-xs">{{getUserData.name}}</span> - <span class="note-headline-light">@{{getUserData.username}}</span> + <span class="hidden-xs">{{ getUserData.name }}</span> + <span class="note-headline-light">@{{ getUserData.username }}</span> </a> </div> </div> <div class="note-body"> <div class="note-text"> - <p>{{note.body}}</p> + <p>{{ note.body }}</p> </div> </div> </div> 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 d805fea8006..95e2b38e292 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 @@ -8,7 +8,7 @@ * /> */ export default { - name: 'placeholderSystemNote', + name: 'PlaceholderSystemNote', props: { note: { type: Object, @@ -20,10 +20,10 @@ <template> <li class="note system-note timeline-entry being-posted fade-in-half"> - <div class="timeline-entry-inner"> - <div class="timeline-content"> - <em>{{note.body}}</em> - </div> - </div> + <div class="timeline-entry-inner"> + <div class="timeline-content"> + <em>{{ note.body }}</em> + </div> + </div> </li> </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 2248699c399..aac10f84087 100644 --- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue +++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue @@ -21,16 +21,16 @@ import { spriteIcon } from '../../../lib/utils/common_utils'; export default { - name: 'systemNote', + name: 'SystemNote', + components: { + noteHeader, + }, props: { note: { type: Object, required: true, }, }, - components: { - noteHeader, - }, computed: { ...mapGetters([ 'targetNoteHash', diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue index 4371534d345..abbe9a22717 100644 --- a/app/assets/javascripts/vue_shared/components/panel_resizer.vue +++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue @@ -1,87 +1,87 @@ <script> -export default { - props: { - startSize: { - type: Number, - required: true, + 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, + }, }, - side: { - type: String, - required: true, + data() { + return { + size: this.startSize, + }; }, - minSize: { - type: Number, - required: false, - default: 0, + computed: { + className() { + return `drag${this.side}`; + }, + cursorStyle() { + if (this.enabled) { + return { cursor: 'ew-resize' }; + } + return {}; + }, }, - 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.size = this.startSize; - this.$emit('update:size', this.size); - }, - startDrag(e) { - if (this.enabled) { + methods: { + resetSize(e) { 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) { - 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.size = this.startSize; + this.$emit('update:size', 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) { + 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> - <div + <div class="dragHandle" :class="className" :style="cursorStyle" diff --git a/app/assets/javascripts/vue_shared/components/pikaday.vue b/app/assets/javascripts/vue_shared/components/pikaday.vue index d8d974a2ff7..bfeece12077 100644 --- a/app/assets/javascripts/vue_shared/components/pikaday.vue +++ b/app/assets/javascripts/vue_shared/components/pikaday.vue @@ -3,7 +3,7 @@ import { parsePikadayDate, pikadayToString } from '../../lib/utils/datefix'; export default { - name: 'datePicker', + name: 'DatePicker', props: { label: { type: String, @@ -13,22 +13,17 @@ selectedDate: { type: Date, required: false, + default: null, }, minDate: { type: Date, required: false, + default: null, }, maxDate: { type: Date, required: false, - }, - }, - methods: { - selected(dateText) { - this.$emit('newDateSelected', this.calendar.toString(dateText)); - }, - toggled() { - this.$emit('hidePicker'); + default: null, }, }, mounted() { @@ -53,6 +48,14 @@ beforeDestroy() { this.calendar.destroy(); }, + methods: { + selected(dateText) { + this.$emit('newDateSelected', this.calendar.toString(dateText)); + }, + toggled() { + this.$emit('hidePicker'); + }, + }, }; </script> @@ -66,7 +69,7 @@ @click="toggled" > <span class="dropdown-toggle-text"> - {{label}} + {{ label }} </span> <i class="fa fa-chevron-down" 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 dce23bd65f6..279cc1de5bb 100644 --- a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue +++ b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue @@ -1,85 +1,85 @@ <script> -/* 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. + /* 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. - Sample configuration: + Sample configuration: - <project-avatar-image - :lazy="true" - :img-src="projectAvatarSrc" - :img-alt="tooltipText" - :tooltip-text="tooltipText" - tooltip-placement="top" - /> + <project-avatar-image + :lazy="true" + :img-src="projectAvatarSrc" + :img-alt="tooltipText" + :tooltip-text="tooltipText" + tooltip-placement="top" + /> -*/ + */ -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', - 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', - }, - }, - directives: { - tooltip, - }, - 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; + export default { + name: 'ProjectAvatarImage', + directives: { + tooltip, }, - tooltipContainer() { - return this.tooltipText ? 'body' : null; + 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', + }, }, - avatarSizeClass() { - return `s${this.size}`; + 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}`; + }, }, - }, -}; + }; </script> <template> @@ -87,7 +87,7 @@ export default { v-tooltip class="avatar" :class="{ - lazy, + lazy: lazy, [avatarSizeClass]: true, [cssClasses]: true }" diff --git a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue index 16d60bb2876..c35621c9ef3 100644 --- a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue +++ b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue @@ -1,85 +1,86 @@ <script> -import modal from './modal.vue'; + import modal from './modal.vue'; -export default { - name: 'recaptcha-modal', + export default { + name: 'RecaptchaModal', - props: { - html: { - type: String, - required: false, - default: '', + components: { + modal, }, - }, - data() { - return { - script: {}, - scriptSrc: 'https://www.google.com/recaptcha/api.js', - }; - }, + props: { + html: { + type: String, + required: false, + default: '', + }, + }, - components: { - modal, - }, + data() { + return { + script: {}, + scriptSrc: 'https://www.google.com/recaptcha/api.js', + }; + }, - methods: { - appendRecaptchaScript() { - this.removeRecaptchaScript(); + watch: { + html() { + this.appendRecaptchaScript(); + }, + }, - const script = document.createElement('script'); - script.src = this.scriptSrc; - script.classList.add('js-recaptcha-script'); - script.async = true; - script.defer = true; + mounted() { + window.recaptchaDialogCallback = this.submit.bind(this); + }, - this.script = script; + methods: { + appendRecaptchaScript() { + this.removeRecaptchaScript(); - document.body.appendChild(script); - }, + const script = document.createElement('script'); + script.src = this.scriptSrc; + script.classList.add('js-recaptcha-script'); + script.async = true; + script.defer = true; - removeRecaptchaScript() { - if (this.script instanceof Element) this.script.remove(); - }, + this.script = script; - close() { - this.removeRecaptchaScript(); - this.$emit('close'); - }, + document.body.appendChild(script); + }, - submit() { - this.$el.querySelector('form').submit(); - }, - }, + removeRecaptchaScript() { + if (this.script instanceof Element) this.script.remove(); + }, - watch: { - html() { - this.appendRecaptchaScript(); - }, - }, + close() { + this.removeRecaptchaScript(); + this.$emit('close'); + }, - mounted() { - window.recaptchaDialogCallback = this.submit.bind(this); - }, -}; + submit() { + this.$el.querySelector('form').submit(); + }, + }, + }; </script> <template> -<modal - kind="warning" - class="recaptcha-modal js-recaptcha-modal" - :hide-footer="true" - :title="__('Please solve the reCAPTCHA')" - @cancel="close" -> - <div slot="body"> - <p> - {{__('We want to be sure it is you, please confirm you are not a robot.')}} - </p> - <div - ref="recaptcha" - v-html="html" - ></div> - </div> -</modal> + <modal + kind="warning" + class="recaptcha-modal js-recaptcha-modal" + :hide-footer="true" + :title="__('Please solve the reCAPTCHA')" + @cancel="close" + > + <div slot="body"> + <p> + {{ __('We want to be sure it is you, please confirm you are not a robot.') }} + </p> + <div + ref="recaptcha" + v-html="html" + > + </div> + </div> + </modal> </template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue index a88e1310131..7f1eb6bcec4 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue @@ -1,6 +1,6 @@ <script> export default { - name: 'collapsedCalendarIcon', + name: 'CollapsedCalendarIcon', props: { containerClass: { type: String, diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue index 9ede5553bc5..dac438a702d 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue @@ -4,7 +4,11 @@ import collapsedCalendarIcon from './collapsed_calendar_icon.vue'; export default { - name: 'sidebarCollapsedGroupedDatePicker', + name: 'SidebarCollapsedGroupedDatePicker', + components: { + toggleSidebar, + collapsedCalendarIcon, + }, props: { collapsed: { type: Boolean, @@ -19,10 +23,12 @@ minDate: { type: Date, required: false, + default: null, }, maxDate: { type: Date, required: false, + default: null, }, disableClickableIcons: { type: Boolean, @@ -30,10 +36,6 @@ default: false, }, }, - components: { - toggleSidebar, - collapsedCalendarIcon, - }, computed: { hasMinAndMaxDates() { return this.minDate && this.maxDate; 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 9c3413377a3..1413dd69f24 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue @@ -6,7 +6,13 @@ import { dateInWords } from '../../../lib/utils/datetime_utility'; export default { - name: 'sidebarDatePicker', + name: 'SidebarDatePicker', + components: { + datePicker, + toggleSidebar, + loadingIcon, + collapsedCalendarIcon, + }, props: { collapsed: { type: Boolean, @@ -36,14 +42,17 @@ selectedDate: { type: Date, required: false, + default: null, }, minDate: { type: Date, required: false, + default: null, }, maxDate: { type: Date, required: false, + default: null, }, }, data() { @@ -51,12 +60,6 @@ editing: false, }; }, - components: { - datePicker, - toggleSidebar, - loadingIcon, - collapsedCalendarIcon, - }, computed: { selectedAndEditable() { return this.selectedDate && this.editable; diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue index 5ae76adad71..8211d425b1f 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue @@ -1,6 +1,6 @@ <script> export default { - name: 'toggleSidebar', + name: 'ToggleSidebar', props: { collapsed: { type: Boolean, @@ -24,7 +24,11 @@ <i aria-label="toggle collapse" class="fa" - :class="{ 'fa-angle-double-right': !collapsed, 'fa-angle-double-left': collapsed }" - ></i> + :class="{ + 'fa-angle-double-right': !collapsed, + 'fa-angle-double-left': collapsed + }" + > + </i> </button> </template> diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue index 33096b53cf8..c44c606a8b2 100644 --- a/app/assets/javascripts/vue_shared/components/table_pagination.vue +++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue @@ -1,132 +1,125 @@ <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: { - /** - This function will take the information given by the pagination component - - Here is an example `change` method: - - change(pagenum) { - gl.utils.visitUrl(`?page=${pagenum}`); + 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 + */ + 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 - - This is an example: - - const pageInfo = headers => ({ - perPage: +headers['X-Per-Page'], - page: +headers['X-Page'], - total: +headers['X-Total'], - totalPages: +headers['X-Total-Pages'], - nextPage: +headers['X-Next-Page'], - previousPage: +headers['X-Prev-Page'], - }); - */ - pageInfo: { - type: Object, - required: true, - }, - }, - methods: { - changePage(e) { - if (e.target.parentElement.classList.contains('disabled')) return; - - const text = e.target.innerText; - 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; - } - }, - }, - computed: { - prev() { - return this.pageInfo.previousPage; - }, - next() { - return this.pageInfo.nextPage; + /** + 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 + + This is an example: + + const pageInfo = headers => ({ + perPage: +headers['X-Per-Page'], + page: +headers['X-Page'], + total: +headers['X-Total'], + totalPages: +headers['X-Total-Pages'], + nextPage: +headers['X-Next-Page'], + previousPage: +headers['X-Prev-Page'], + }); + */ + pageInfo: { + type: Object, + required: true, + }, }, - getItems() { - const total = this.pageInfo.totalPages; - const page = this.pageInfo.page; - 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; + computed: { + prev() { + return this.pageInfo.previousPage; + }, + next() { + return this.pageInfo.nextPage; + }, + getItems() { + const total = this.pageInfo.totalPages; + const page = this.pageInfo.page; + 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; + }, }, - 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; + } + }, }, - }, -}; + }; </script> <template> <div @@ -135,7 +128,8 @@ export default { > <ul class="pagination clearfix"> <li - v-for="item in getItems" + v-for="(item, index) in getItems" + :key="index" :class="{ page: item.page, 'js-previous-button': item.prev, @@ -145,8 +139,11 @@ export default { separator: item.separator, active: item.active, disabled: item.disabled - }"> - <a @click.prevent="changePage($event)">{{item.title}}</a> + }" + > + <a @click.prevent="changePage(item.title, item.disabled)"> + {{ item.title }} + </a> </li> </ul> </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 3ff7f6e2c4e..bec4e7c99b6 100644 --- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue +++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue @@ -8,6 +8,12 @@ import '../../lib/utils/datetime_utility'; */ export default { + directives: { + tooltip, + }, + mixins: [ + timeagoMixin, + ], props: { time: { type: String, @@ -26,14 +32,6 @@ export default { default: '', }, }, - - mixins: [ - timeagoMixin, - ], - - directives: { - tooltip, - }, }; </script> <template> @@ -43,6 +41,6 @@ export default { :title="tooltipTitle(time)" :data-placement="tooltipPlacement" data-container="body"> - {{timeFormated(time)}} + {{ timeFormated(time) }} </time> </template> diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue index 4277d9281a0..2b12718ae96 100644 --- a/app/assets/javascripts/vue_shared/components/toggle_button.vue +++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue @@ -9,6 +9,16 @@ const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF'); export default { + components: { + icon, + loadingIcon, + }, + + model: { + prop: 'value', + event: 'change', + }, + props: { name: { type: String, @@ -31,16 +41,6 @@ }, }, - components: { - icon, - loadingIcon, - }, - - model: { - prop: 'value', - event: 'change', - }, - computed: { toggleIcon() { return this.value ? ICON_ON : ICON_OFF; diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue index 1ac61a3c39b..cc9cc46bb4c 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue @@ -22,6 +22,9 @@ import tooltip from '../../directives/tooltip'; export default { name: 'UserAvatarImage', + directives: { + tooltip, + }, props: { lazy: { type: Boolean, @@ -59,9 +62,6 @@ export default { default: 'top', }, }, - directives: { - tooltip, - }, computed: { // API response sends null when gravatar is disabled and // we provide an empty string when we use it inside user avatar link. @@ -87,7 +87,7 @@ export default { v-tooltip class="avatar" :class="{ - lazy, + lazy: lazy, [avatarSizeClass]: true, [cssClasses]: true }" 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 dc32e783258..6955d164def 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 @@ -26,6 +26,9 @@ export default { components: { userAvatarImage, }, + directives: { + tooltip, + }, props: { linkHref: { type: String, @@ -76,9 +79,6 @@ export default { return this.shouldShowUsername ? '' : this.tooltipText; }, }, - directives: { - tooltip, - }, }; </script> @@ -98,6 +98,6 @@ export default { v-tooltip :title="tooltipText" :tooltip-placement="tooltipPlacement" - >{{username}}</span> + >{{ username }}</span> </a> </template> 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 d2ff2ac006e..ef3b16edf5f 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 @@ -39,7 +39,7 @@ export default { :class="avatarSizeClass" :height="size" :width="size" - v-html="svg"> - </svg> + v-html="svg" + /> </template> |