diff options
author | Clement Ho <ClemMakesApps@gmail.com> | 2018-04-23 08:51:42 -0500 |
---|---|---|
committer | Clement Ho <ClemMakesApps@gmail.com> | 2018-04-23 08:51:42 -0500 |
commit | 8bd38fdc254a4ce9fb760c9b5fa8e4237f9f805b (patch) | |
tree | 72a352e2cc9dc1aa7b01e010dc034c879650ac91 /app/assets/javascripts | |
parent | f9410cb9dd7f7633e271948a4e485307a60ad9cc (diff) | |
parent | 627eba55d63daf7e725edc5425debfc3890f2f9f (diff) | |
download | gitlab-ce-8bd38fdc254a4ce9fb760c9b5fa8e4237f9f805b.tar.gz |
Merge branch 'master' into bootstrap4
Diffstat (limited to 'app/assets/javascripts')
19 files changed, 529 insertions, 551 deletions
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js index e210d69895e..7144f4190e7 100644 --- a/app/assets/javascripts/boards/models/list.js +++ b/app/assets/javascripts/boards/models/list.js @@ -113,6 +113,8 @@ class List { issue.id = data.id; issue.iid = data.iid; issue.project = data.project; + issue.path = data.real_path; + issue.referencePath = data.reference_path; if (this.issuesSize > 1) { const moveBeforeId = this.issues[1].id; diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index cd46e94b5ae..09d490106df 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -84,20 +84,21 @@ export default class CreateMergeRequestDropdown { if (data.can_create_branch) { this.available(); this.enable(); + this.updateBranchName(data.suggested_branch_name); if (!this.droplabInitialized) { this.droplabInitialized = true; this.initDroplab(); this.bindEvents(); } - } else if (data.has_related_branch) { + } else { this.hide(); } }) .catch(() => { this.unavailable(); this.disable(); - Flash('Failed to check if a new branch can be created.'); + Flash(__('Failed to check related branches.')); }); } @@ -409,13 +410,16 @@ export default class CreateMergeRequestDropdown { this.unavailableButton.classList.remove('hidden'); } + updateBranchName(suggestedBranchName) { + this.branchInput.value = suggestedBranchName; + this.updateCreatePaths('branch', suggestedBranchName); + } + updateInputState(target, ref, result) { // target - 'branch' or 'ref' - which the input field we are searching a ref for. // ref - string - what a user typed. // result - string - what has been found on backend. - const pathReplacement = `$1${ref}`; - // If a found branch equals exact the same text a user typed, // that means a new branch cannot be created as it already exists. if (ref === result) { @@ -426,18 +430,12 @@ export default class CreateMergeRequestDropdown { this.refIsValid = true; this.refInput.dataset.value = ref; this.showAvailableMessage('ref'); - this.createBranchPath = this.createBranchPath.replace(this.regexps.ref.createBranchPath, - pathReplacement); - this.createMrPath = this.createMrPath.replace(this.regexps.ref.createMrPath, - pathReplacement); + this.updateCreatePaths(target, ref); } } else if (target === 'branch') { this.branchIsValid = true; this.showAvailableMessage('branch'); - this.createBranchPath = this.createBranchPath.replace(this.regexps.branch.createBranchPath, - pathReplacement); - this.createMrPath = this.createMrPath.replace(this.regexps.branch.createMrPath, - pathReplacement); + this.updateCreatePaths(target, ref); } else { this.refIsValid = false; this.refInput.dataset.value = ref; @@ -457,4 +455,15 @@ export default class CreateMergeRequestDropdown { this.disableCreateAction(); } } + + // target - 'branch' or 'ref' + // ref - string - the new value to use as branch or ref + updateCreatePaths(target, ref) { + const pathReplacement = `$1${ref}`; + + this.createBranchPath = this.createBranchPath.replace(this.regexps[target].createBranchPath, + pathReplacement); + this.createMrPath = this.createMrPath.replace(this.regexps[target].createMrPath, + pathReplacement); + } } diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 5bd616b5ed3..b2c1a26bbae 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -1427,7 +1427,7 @@ export default class Notes { const { discussion_html } = data; const lines = $(discussion_html).find('.line_holder'); lines.addClass('fade-in'); - $container.find('tbody').prepend(lines); + $container.find('.diff-content > table > tbody').prepend(lines); const fileHolder = $container.find('.file-holder'); $container.find('.line-holder-placeholder').remove(); syntaxHighlight(fileHolder); diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue index e99d949801f..29ee73a2a6f 100644 --- a/app/assets/javascripts/pipelines/components/graph/action_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue @@ -32,26 +32,38 @@ export default { required: true, }, - buttonDisabled: { + requestFinishedFor: { type: String, required: false, - default: null, + default: '', }, }, + data() { + return { + isDisabled: false, + linkRequested: '', + }; + }, + computed: { cssClass() { const actionIconDash = dasherize(this.actionIcon); return `${actionIconDash} js-icon-${actionIconDash}`; }, - isDisabled() { - return this.buttonDisabled === this.link; + }, + watch: { + requestFinishedFor() { + if (this.requestFinishedFor === this.linkRequested) { + this.isDisabled = false; + } }, }, - methods: { onClickAction() { $(this.$el).tooltip('hide'); eventHub.$emit('graphAction', this.link); + this.linkRequested = this.link; + this.isDisabled = true; }, }, }; @@ -62,7 +74,8 @@ export default { @click="onClickAction" v-tooltip :title="tooltipText" - class="btn btn-blank btn-transparent ci-action-icon-container ci-action-icon-wrapper" + class="js-ci-action btn btn-blank +btn-transparent ci-action-icon-container ci-action-icon-wrapper" :class="cssClass" data-container="body" :disabled="isDisabled" diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue deleted file mode 100644 index 7c4fd65e36f..00000000000 --- a/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue +++ /dev/null @@ -1,53 +0,0 @@ -<script> - import icon from '../../../vue_shared/components/icon.vue'; - import tooltip from '../../../vue_shared/directives/tooltip'; - - /** - * Renders either a cancel, retry or play icon pointing to the given path. - * TODO: Remove UJS from here and use an async request instead. - */ - export default { - components: { - icon, - }, - - directives: { - tooltip, - }, - props: { - tooltipText: { - type: String, - required: true, - }, - - link: { - type: String, - required: true, - }, - - actionMethod: { - type: String, - required: true, - }, - - actionIcon: { - type: String, - required: true, - }, - }, - }; -</script> -<template> - <a - v-tooltip - :data-method="actionMethod" - :title="tooltipText" - :href="link" - rel="nofollow" - class="ci-action-icon-wrapper js-ci-status-icon" - data-container="body" - aria-label="Job's action" - > - <icon :name="actionIcon" /> - </a> -</template> diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue index be213c2ee78..43121dd38f3 100644 --- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue @@ -1,77 +1,83 @@ <script> - import $ from 'jquery'; - import jobNameComponent from './job_name_component.vue'; - import jobComponent from './job_component.vue'; - import tooltip from '../../../vue_shared/directives/tooltip'; +import $ from 'jquery'; +import JobNameComponent from './job_name_component.vue'; +import JobComponent from './job_component.vue'; +import tooltip from '../../../vue_shared/directives/tooltip'; - /** - * Renders the dropdown for the pipeline graph. - * - * The following object should be provided as `job`: - * - * { - * "id": 4256, - * "name": "test", - * "status": { - * "icon": "icon_status_success", - * "text": "passed", - * "label": "passed", - * "group": "success", - * "details_path": "/root/ci-mock/builds/4256", - * "action": { - * "icon": "retry", - * "title": "Retry", - * "path": "/root/ci-mock/builds/4256/retry", - * "method": "post" - * } - * } - * } - */ - export default { - directives: { - tooltip, - }, +/** + * Renders the dropdown for the pipeline graph. + * + * The following object should be provided as `job`: + * + * { + * "id": 4256, + * "name": "test", + * "status": { + * "icon": "icon_status_success", + * "text": "passed", + * "label": "passed", + * "group": "success", + * "details_path": "/root/ci-mock/builds/4256", + * "action": { + * "icon": "retry", + * "title": "Retry", + * "path": "/root/ci-mock/builds/4256/retry", + * "method": "post" + * } + * } + * } + */ +export default { + directives: { + tooltip, + }, - components: { - jobComponent, - jobNameComponent, - }, + components: { + JobComponent, + JobNameComponent, + }, - props: { - job: { - type: Object, - required: true, - }, + props: { + job: { + type: Object, + required: true, }, - - computed: { - tooltipText() { - return `${this.job.name} - ${this.job.status.label}`; - }, + requestFinishedFor: { + type: String, + required: false, + default: '', }, + }, - mounted() { - this.stopDropdownClickPropagation(); + computed: { + tooltipText() { + return `${this.job.name} - ${this.job.status.label}`; }, + }, + + mounted() { + this.stopDropdownClickPropagation(); + }, - methods: { - /** - * When the user right clicks or cmd/ctrl + click in the job name - * the dropdown should not be closed and the link should open in another tab, - * so we stop propagation of the click event inside the dropdown. + methods: { + /** + * When the user right clicks or cmd/ctrl + click in the job name or the action icon + * the dropdown should not be closed so we stop propagation + * of the click event inside the dropdown. * * Since this component is rendered multiple times per page we need to guarantee we only * target the click event of this component. */ - stopDropdownClickPropagation() { - $(this.$el - .querySelectorAll('.js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item')) - .on('click', (e) => { - e.stopPropagation(); - }); - }, + stopDropdownClickPropagation() { + $( + '.js-grouped-pipeline-dropdown button, .js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item', + this.$el, + ).on('click', e => { + e.stopPropagation(); + }); }, - }; + }, +}; </script> <template> <div class="ci-job-dropdown-container"> @@ -101,8 +107,8 @@ :key="i"> <job-component :job="item" - :is-dropdown="true" css-class-job-name="mini-pipeline-graph-dropdown-item" + :request-finished-for="requestFinishedFor" /> </li> </ul> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index ac9ce7e47d6..7b8a5edcbff 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -7,7 +7,6 @@ export default { StageColumnComponent, LoadingIcon, }, - props: { isLoading: { type: Boolean, @@ -17,10 +16,10 @@ export default { type: Object, required: true, }, - actionDisabled: { + requestFinishedFor: { type: String, required: false, - default: null, + default: '', }, }, @@ -75,7 +74,7 @@ export default { :key="stage.name" :stage-connector-class="stageConnectorClass(index, stage)" :is-first-column="isFirstColumn(index)" - :action-disabled="actionDisabled" + :request-finished-for="requestFinishedFor" /> </ul> </div> diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue index c6e5ae6df41..4fcd4b79f4a 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue @@ -1,6 +1,5 @@ <script> import ActionComponent from './action_component.vue'; -import DropdownActionComponent from './dropdown_action_component.vue'; import JobNameComponent from './job_name_component.vue'; import tooltip from '../../../vue_shared/directives/tooltip'; @@ -32,10 +31,8 @@ import tooltip from '../../../vue_shared/directives/tooltip'; export default { components: { ActionComponent, - DropdownActionComponent, JobNameComponent, }, - directives: { tooltip, }, @@ -44,26 +41,17 @@ export default { type: Object, required: true, }, - cssClassJobName: { type: String, required: false, default: '', }, - - isDropdown: { - type: Boolean, - required: false, - default: false, - }, - - actionDisabled: { + requestFinishedFor: { type: String, required: false, - default: null, + default: '', }, }, - computed: { status() { return this.job && this.job.status ? this.job.status : {}; @@ -134,19 +122,11 @@ export default { </div> <action-component - v-if="hasAction && !isDropdown" - :tooltip-text="status.action.title" - :link="status.action.path" - :action-icon="status.action.icon" - :button-disabled="actionDisabled" - /> - - <dropdown-action-component - v-if="hasAction && isDropdown" + v-if="hasAction" :tooltip-text="status.action.title" :link="status.action.path" :action-icon="status.action.icon" - :action-method="status.action.method" + :request-finished-for="requestFinishedFor" /> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue index f6e6569e15b..5461fdbbadd 100644 --- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue @@ -29,10 +29,11 @@ export default { required: false, default: '', }, - actionDisabled: { + + requestFinishedFor: { type: String, required: false, - default: null, + default: '', }, }, @@ -74,12 +75,12 @@ export default { v-if="job.size === 1" :job="job" css-class-job-name="build-content" - :action-disabled="actionDisabled" /> <dropdown-job-component v-if="job.size > 1" :job="job" + :request-finished-for="requestFinishedFor" /> </li> diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index 900eb7855f4..6584f96130b 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -25,7 +25,7 @@ export default () => { data() { return { mediator, - actionDisabled: null, + requestFinishedFor: null, }; }, created() { @@ -36,15 +36,17 @@ export default () => { }, methods: { postAction(action) { - this.actionDisabled = action; + // Click was made, reset this variable + this.requestFinishedFor = null; - this.mediator.service.postAction(action) + this.mediator.service + .postAction(action) .then(() => { this.mediator.refreshPipeline(); - this.actionDisabled = null; + this.requestFinishedFor = action; }) .catch(() => { - this.actionDisabled = null; + this.requestFinishedFor = action; Flash(__('An error occurred while making the request.')); }); }, @@ -54,7 +56,7 @@ export default () => { props: { isLoading: this.mediator.state.isLoading, pipeline: this.mediator.store.state.pipeline, - actionDisabled: this.actionDisabled, + requestFinishedFor: this.requestFinishedFor, }, }); }, @@ -79,7 +81,8 @@ export default () => { }, methods: { postAction(action) { - this.mediator.service.postAction(action.path) + this.mediator.service + .postAction(action.path) .then(() => this.mediator.refreshPipeline()) .catch(() => Flash(__('An error occurred while making the request.'))); }, 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 5324d5dc797..0d64efcbf68 100644 --- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue +++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue @@ -1,52 +1,52 @@ <script> - import ciIcon from './ci_icon.vue'; - import tooltip from '../directives/tooltip'; - /** - * Renders CI Badge link with CI icon and status text based on - * API response shared between all places where it is used. - * - * Receives status object containing: - * status: { - * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url - * group:"running" // used for CSS class - * icon: "icon_status_running" // used to render the icon - * label:"running" // used for potential tooltip - * text:"running" // text rendered - * } - * - * Used in: - * - Pipelines table - first column - * - Jobs table - first column - * - Pipeline show view - header - * - Job show view - header - * - MR widget - */ +import CiIcon from './ci_icon.vue'; +import tooltip from '../directives/tooltip'; +/** + * Renders CI Badge link with CI icon and status text based on + * API response shared between all places where it is used. + * + * Receives status object containing: + * status: { + * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url + * group:"running" // used for CSS class + * icon: "icon_status_running" // used to render the icon + * label:"running" // used for potential tooltip + * text:"running" // text rendered + * } + * + * Used in: + * - Pipelines table - first column + * - Jobs table - first column + * - Pipeline show view - header + * - Job show view - header + * - MR widget + */ - export default { - components: { - ciIcon, +export default { + components: { + CiIcon, + }, + directives: { + tooltip, + }, + props: { + status: { + type: Object, + required: true, }, - directives: { - tooltip, + showText: { + type: Boolean, + required: false, + default: true, }, - props: { - status: { - type: Object, - required: true, - }, - showText: { - type: Boolean, - required: false, - default: true, - }, + }, + computed: { + cssClass() { + const className = this.status.group; + return className ? `ci-status ci-${className}` : 'ci-status'; }, - computed: { - cssClass() { - const className = this.status.group; - return className ? `ci-status ci-${className}` : 'ci-status'; - }, - }, - }; + }, +}; </script> <template> <a diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue index 8fea746f4de..fcab8f571dd 100644 --- a/app/assets/javascripts/vue_shared/components/ci_icon.vue +++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue @@ -1,45 +1,44 @@ <script> - import icon from '../../vue_shared/components/icon.vue'; +import Icon from '../../vue_shared/components/icon.vue'; - /** - * Renders CI icon based on API response shared between all places where it is used. - * - * Receives status object containing: - * status: { - * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url - * group:"running" // used for CSS class - * icon: "icon_status_running" // used to render the icon - * label:"running" // used for potential tooltip - * text:"running" // text rendered - * } - * - * Used in: - * - Pipelines table Badge - * - Pipelines table mini graph - * - Pipeline graph - * - Pipeline show view badge - * - Jobs table - * - Jobs show view header - * - Jobs show view sidebar - */ - export default { - components: { - icon, +/** + * Renders CI icon based on API response shared between all places where it is used. + * + * Receives status object containing: + * status: { + * details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url + * group:"running" // used for CSS class + * icon: "icon_status_running" // used to render the icon + * label:"running" // used for potential tooltip + * text:"running" // text rendered + * } + * + * Used in: + * - Pipelines table Badge + * - Pipelines table mini graph + * - Pipeline graph + * - Pipeline show view badge + * - Jobs table + * - Jobs show view header + * - Jobs show view sidebar + */ +export default { + components: { + Icon, + }, + props: { + status: { + type: Object, + required: true, }, - props: { - status: { - type: Object, - required: true, - }, + }, + computed: { + cssClass() { + const status = this.status.group; + return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`; }, - - computed: { - cssClass() { - const status = this.status.group; - return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`; - }, - }, - }; + }, +}; </script> <template> <span :class="cssClass"> diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue index 01e54c87ad1..901c349cdcb 100644 --- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue +++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue @@ -1,40 +1,50 @@ <script> - /** - * Falls back to the code used in `copy_to_clipboard.js` - */ - import tooltip from '../directives/tooltip'; +/** + * Falls back to the code used in `copy_to_clipboard.js` + * + * Renders a button with a clipboard icon that copies the content of `data-clipboard-text` + * when clicked. + * + * @example + * <clipboard-button + * title="Copy to clipbard" + * text="Content to be copied" + * css-class="btn-transparent" + * /> + */ +import tooltip from '../directives/tooltip'; - export default { - name: 'ClipboardButton', - directives: { - tooltip, +export default { + name: 'ClipboardButton', + directives: { + tooltip, + }, + props: { + text: { + type: String, + required: true, }, - props: { - text: { - type: String, - required: true, - }, - title: { - type: String, - required: true, - }, - tooltipPlacement: { - type: String, - required: false, - default: 'top', - }, - tooltipContainer: { - type: [String, Boolean], - required: false, - default: false, - }, - cssClass: { - type: String, - required: false, - default: 'btn-secondary', - }, + title: { + type: String, + required: true, }, - }; + tooltipPlacement: { + type: String, + required: false, + default: 'top', + }, + tooltipContainer: { + type: [String, Boolean], + required: false, + default: false, + }, + cssClass: { + type: String, + required: false, + default: 'btn-secondary', + }, + }, +}; </script> <template> diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue index b8875d04488..8f250a6c989 100644 --- a/app/assets/javascripts/vue_shared/components/commit.vue +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -1,119 +1,111 @@ <script> - 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 UserAvatarLink from './user_avatar/user_avatar_link.vue'; +import tooltip from '../directives/tooltip'; +import Icon from '../../vue_shared/components/icon.vue'; - export default { - directives: { - tooltip, +export default { + directives: { + tooltip, + }, + components: { + UserAvatarLink, + Icon, + }, + props: { + /** + * Indicates the existance of a tag. + * Used to render the correct icon, if true will render `fa-tag` icon, + * if false will render a svg sprite fork icon + */ + tag: { + type: Boolean, + required: false, + default: false, }, - components: { - userAvatarLink, - icon, + /** + * If provided is used to render the branch name and url. + * Should contain the following properties: + * name + * ref_url + */ + commitRef: { + type: Object, + required: false, + default: () => ({}), + }, + /** + * Used to link to the commit sha. + */ + commitUrl: { + type: String, + required: false, + default: '', }, - props: { - /** - * Indicates the existance of a tag. - * Used to render the correct icon, if true will render `fa-tag` icon, - * if false will render a svg sprite fork icon - */ - tag: { - type: Boolean, - required: false, - default: false, - }, - /** - * If provided is used to render the branch name and url. - * Should contain the following properties: - * name - * ref_url - */ - commitRef: { - type: Object, - required: false, - default: () => ({}), - }, - /** - * Used to link to the commit sha. - */ - commitUrl: { - type: String, - required: false, - default: '', - }, - /** - * Used to show the commit short sha that links to the commit url. - */ - shortSha: { - type: String, - required: false, - default: '', - }, - /** - * If provided shows the commit tile. - */ - title: { - type: String, - required: false, - default: '', - }, - /** - * If provided renders information about the author of the commit. - * When provided should include: - * `avatar_url` to render the avatar icon - * `web_url` to link to user profile - * `username` to render alt and title tags - */ - author: { - type: Object, - required: false, - default: () => ({}), - }, - showBranch: { - type: Boolean, - required: false, - default: true, - }, + /** + * Used to show the commit short sha that links to the commit url. + */ + shortSha: { + type: String, + required: false, + default: '', + }, + /** + * If provided shows the commit tile. + */ + title: { + type: String, + required: false, + default: '', + }, + /** + * If provided renders information about the author of the commit. + * When provided should include: + * `avatar_url` to render the avatar icon + * `web_url` to link to user profile + * `username` to render alt and title tags + */ + author: { + type: Object, + required: false, + default: () => ({}), + }, + showBranch: { + type: Boolean, + required: false, + default: true, }, - computed: { - /** - * Used to verify if all the properties needed to render the commit - * ref section were provided. - * - * @returns {Boolean} - */ - hasCommitRef() { - return this.commitRef && this.commitRef.name && this.commitRef.ref_url; - }, - /** - * Used to verify if all the properties needed to render the commit - * author section were provided. - * - * @returns {Boolean} - */ - hasAuthor() { - return this.author && - this.author.avatar_url && - this.author.path && - this.author.username; - }, - /** - * If information about the author is provided will return a string - * to be rendered as the alt attribute of the img tag. - * - * @returns {String} - */ - userImageAltDescription() { - return this.author && - this.author.username ? `${this.author.username}'s avatar` : null; - }, + }, + computed: { + /** + * Used to verify if all the properties needed to render the commit + * ref section were provided. + * + * @returns {Boolean} + */ + hasCommitRef() { + return this.commitRef && this.commitRef.name && this.commitRef.ref_url; }, - created() { - this.commitIconSvg = commitIconSvg; + /** + * Used to verify if all the properties needed to render the commit + * author section were provided. + * + * @returns {Boolean} + */ + hasAuthor() { + return this.author && this.author.avatar_url && this.author.path && this.author.username; }, - }; + /** + * If information about the author is provided will return a string + * to be rendered as the alt attribute of the img tag. + * + * @returns {String} + */ + userImageAltDescription() { + return this.author && this.author.username ? `${this.author.username}'s avatar` : null; + }, + }, +}; </script> <template> <div class="branch-commit"> @@ -141,11 +133,10 @@ {{ commitRef.name }} </a> </template> - <div - v-html="commitIconSvg" + <icon + name="commit" class="commit-icon js-commit-icon" - > - </div> + /> <a class="commit-sha" diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue index c943c8d98a4..9295be3e2b2 100644 --- a/app/assets/javascripts/vue_shared/components/expand_button.vue +++ b/app/assets/javascripts/vue_shared/components/expand_button.vue @@ -1,33 +1,33 @@ <script> - import { __ } from '~/locale'; - /** - * Port of detail_behavior expand button. - * - * @example - * <expand-button> - * <template slot="expanded"> - * Text goes here. - * </template> - * </expand-button> - */ - export default { - name: 'ExpandButton', - data() { - return { - isCollapsed: true, - }; +import { __ } from '~/locale'; +/** + * Port of detail_behavior expand button. + * + * @example + * <expand-button> + * <template slot="expanded"> + * Text goes here. + * </template> + * </expand-button> + */ +export default { + name: 'ExpandButton', + data() { + return { + isCollapsed: true, + }; + }, + computed: { + ariaLabel() { + return __('Click to expand text'); }, - computed: { - ariaLabel() { - return __('Click to expand text'); - }, + }, + methods: { + onClick() { + this.isCollapsed = !this.isCollapsed; }, - methods: { - onClick() { - this.isCollapsed = !this.isCollapsed; - }, - }, - }; + }, +}; </script> <template> <span> 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 23a8697cc0b..474be04db31 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -1,78 +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'; +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, +/** + * 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, + }, + directives: { + tooltip, + }, + props: { + status: { + type: Object, + required: true, }, - directives: { - tooltip, + itemName: { + type: String, + required: true, }, - 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, - }, + 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, + }, + }, - 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> diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue index 6a2e05000e1..1a0df49bc29 100644 --- a/app/assets/javascripts/vue_shared/components/icon.vue +++ b/app/assets/javascripts/vue_shared/components/icon.vue @@ -1,76 +1,75 @@ <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]; - */ - // only allow classes in images.scss e.g. s12 - const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; - - export default { - props: { - name: { - type: String, - required: true, - }, +export default { + props: { + name: { + type: String, + required: true, + }, - size: { - type: Number, - required: false, - default: 16, - validator(value) { - return validSizes.includes(value); - }, + size: { + type: Number, + required: false, + default: 16, + validator(value) { + return validSizes.includes(value); }, + }, - cssClasses: { - type: String, - required: false, - default: '', - }, + cssClasses: { + type: String, + required: false, + default: '', + }, - width: { - type: Number, - required: false, - default: null, - }, + width: { + type: Number, + required: false, + default: null, + }, - height: { - type: Number, - required: false, - default: null, - }, + height: { + type: Number, + required: false, + default: null, + }, - y: { - type: Number, - required: false, - default: null, - }, + y: { + type: Number, + required: false, + default: null, + }, - x: { - type: Number, - required: false, - default: null, - }, + x: { + type: Number, + required: false, + default: null, }, + }, - computed: { - spriteHref() { - return `${gon.sprite_icons}#${this.name}`; - }, - iconSizeClass() { - return this.size ? `s${this.size}` : ''; - }, + computed: { + spriteHref() { + return `${gon.sprite_icons}#${this.name}`; + }, + iconSizeClass() { + return this.size ? `s${this.size}` : ''; }, - }; + }, +}; </script> <template> @@ -79,7 +78,8 @@ :width="width" :height="height" :x="x" - :y="y"> + :y="y" + > <use v-bind="{ 'xlink:href':spriteHref }" /> </svg> </template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue index 5ede53d8d01..70b46a9c2bb 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue @@ -1,4 +1,5 @@ <script> +import $ from 'jquery'; import { __ } from '~/locale'; import LabelsSelect from '~/labels_select'; import LoadingIcon from '../../loading_icon.vue'; @@ -98,11 +99,18 @@ export default { this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, { handleClick: this.handleClick, }); + $(this.$refs.dropdown).on('hidden.gl.dropdown', this.handleDropdownHidden); }, methods: { handleClick(label) { this.$emit('onLabelClick', label); }, + handleCollapsedValueClick() { + this.$emit('toggleCollapse'); + }, + handleDropdownHidden() { + this.$emit('onDropdownClose'); + }, }, }; </script> @@ -112,6 +120,7 @@ export default { <dropdown-value-collapsed v-if="showCreate" :labels="context.labels" + @onValueClick="handleCollapsedValueClick" /> <dropdown-title :can-edit="canEdit" @@ -133,7 +142,10 @@ export default { :name="hiddenInputName" :label="label" /> - <div class="dropdown"> + <div + class="dropdown" + ref="dropdown" + > <dropdown-button :ability-name="abilityName" :field-name="hiddenInputName" diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue index 5cf728fe050..68fa2ab8d01 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue @@ -26,6 +26,11 @@ export default { return labelsString; }, }, + methods: { + handleClick() { + this.$emit('onValueClick'); + }, + }, }; </script> @@ -36,6 +41,7 @@ export default { data-placement="left" data-container="body" :title="labelsList" + @click="handleClick" > <i aria-hidden="true" |