diff options
author | Phil Hughes <me@iamphill.com> | 2018-01-25 08:49:05 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2018-01-25 08:49:05 +0000 |
commit | aff9ecefb8a2c0e3b6816a4632c8433940dd6e88 (patch) | |
tree | 79a67e68244b23bf264cd45d1d5d54974442fbe4 | |
parent | 8f5d1d1371b47ab810a9e5ddff483f669d149363 (diff) | |
parent | 09babc575473eadc4ffabe3d469f95d4347cf76c (diff) | |
download | gitlab-ce-aff9ecefb8a2c0e3b6816a4632c8433940dd6e88.tar.gz |
Merge branch 'fl-mr-widget-refactor' into 'master'
Moves more mr widget components into vue files
See merge request gitlab-org/gitlab-ce!16677
11 files changed, 267 insertions, 256 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js deleted file mode 100644 index 09561694939..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.js +++ /dev/null @@ -1,18 +0,0 @@ -import statusIcon from '../mr_widget_status_icon'; - -export default { - name: 'MRWidgetChecking', - components: { - statusIcon, - }, - template: ` - <div class="mr-widget-body media"> - <status-icon status="loading" :show-disabled-button="true" /> - <div class="media-body space-children"> - <span class="bold"> - Checking ability to merge automatically - </span> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue new file mode 100644 index 00000000000..04e1766b8c7 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue @@ -0,0 +1,23 @@ +<script> + import statusIcon from '../mr_widget_status_icon'; + + export default { + name: 'MRWidgetChecking', + components: { + statusIcon, + }, + }; +</script> +<template> + <div class="mr-widget-body media"> + <status-icon + status="loading" + :show-disabled-button="true" + /> + <div class="media-body space-children"> + <span class="bold"> + {{ s__("mrWidget|Checking ability to merge automatically") }} + </span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js deleted file mode 100644 index dc19b20aa11..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.js +++ /dev/null @@ -1,35 +0,0 @@ -import mrWidgetAuthorTime from '../../components/mr_widget_author_time'; -import statusIcon from '../mr_widget_status_icon'; - -export default { - name: 'MRWidgetClosed', - props: { - mr: { type: Object, required: true }, - }, - components: { - 'mr-widget-author-and-time': mrWidgetAuthorTime, - statusIcon, - }, - template: ` - <div class="mr-widget-body media"> - <status-icon status="warning" /> - <div class="media-body"> - <mr-widget-author-and-time - actionText="Closed by" - :author="mr.metrics.closedBy" - :dateTitle="mr.metrics.closedAt" - :dateReadable="mr.metrics.readableClosedAt" - /> - <section class="mr-info-list"> - <p> - The changes were not merged into - <a - :href="mr.targetBranchPath" - class="label-branch"> - {{mr.targetBranch}}</a> - </p> - </section> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue new file mode 100644 index 00000000000..8c0ce43c76c --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue @@ -0,0 +1,48 @@ +<script> + import mrWidgetAuthorTime from '../../components/mr_widget_author_time'; + import statusIcon from '../mr_widget_status_icon'; + + export default { + name: 'MRWidgetClosed', + components: { + mrWidgetAuthorTime, + statusIcon, + }, + props: { + /* TODO: This is providing all store and service down when it + only needs metrics and targetBranch */ + mr: { + type: Object, + required: true, + default: () => ({}), + }, + }, + }; +</script> +<template> + <div class="mr-widget-body media"> + <status-icon + status="warning" + /> + <div class="media-body"> + <mr-widget-author-time + :action-text="s__('mrWidget|Closed by')" + :author="mr.metrics.closedBy" + :date-title="mr.metrics.closedAt" + :date-readable="mr.metrics.readableClosedAt" + /> + + <section class="mr-info-list"> + <p> + {{ s__("mrWidget|The changes were not merged into") }} + <a + :href="mr.targetBranchPath" + class="label-branch" + > + {{ mr.targetBranch }} + </a> + </p> + </section> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js deleted file mode 100644 index 7a887bacfa7..00000000000 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js +++ /dev/null @@ -1,47 +0,0 @@ -import statusIcon from '../mr_widget_status_icon'; - -export default { - name: 'MRWidgetConflicts', - props: { - mr: { type: Object, required: true }, - }, - components: { - statusIcon, - }, - template: ` - <div class="mr-widget-body media"> - <status-icon - status="warning" - :show-disabled-button="true" /> - <div class="media-body space-children"> - <span - v-if="mr.shouldBeRebased" - class="bold"> - Fast-forward merge is not possible. - To merge this request, first rebase locally. - </span> - <template v-else> - <span class="bold"> - There are merge conflicts<span v-if="!mr.canMerge">.</span> - <span v-if="!mr.canMerge"> - Resolve these conflicts or ask someone with write access to this repository to merge it locally - </span> - </span> - <a - v-if="mr.canMerge && mr.conflictResolutionPath" - :href="mr.conflictResolutionPath" - class="js-resolve-conflicts-button btn btn-default btn-xs"> - Resolve conflicts - </a> - <a - v-if="mr.canMerge" - class="js-merge-locally-button btn btn-default btn-xs" - data-toggle="modal" - href="#modal_merge_info"> - Merge locally - </a> - </template> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue new file mode 100644 index 00000000000..13b07f82330 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue @@ -0,0 +1,61 @@ +<script> + import statusIcon from '../mr_widget_status_icon'; + + export default { + name: 'MRWidgetConflicts', + components: { + statusIcon, + }, + props: { + /* TODO: This is providing all store and service down when it + only needs a few props */ + mr: { + type: Object, + required: true, + default: () => ({}), + }, + }, + }; +</script> +<template> + <div class="mr-widget-body media"> + <status-icon + status="warning" + :show-disabled-button="true" + /> + + <div class="media-body space-children"> + <span + v-if="mr.shouldBeRebased" + class="bold" + > + {{ s__(`mrWidget|Fast-forward merge is not possible. +To merge this request, first rebase locally.`) }} + </span> + <template v-else> + <span class="bold"> + {{ s__("mrWidget|There are merge conflicts") }}<span v-if="!mr.canMerge">.</span> + <span v-if="!mr.canMerge"> + {{ s__(`mrWidget|Resolve these conflicts or ask someone + with write access to this repository to merge it locally`) }} + </span> + </span> + <a + v-if="mr.canMerge && mr.conflictResolutionPath" + :href="mr.conflictResolutionPath" + class="js-resolve-conflicts-button btn btn-default btn-xs" + > + {{ s__("mrWidget|Resolve conflicts") }} + </a> + <button + v-if="mr.canMerge" + class="js-merge-locally-button btn btn-default btn-xs" + data-toggle="modal" + data-target="#modal_merge_info" + > + {{ s__("mrWidget|Merge locally") }} + </button> + </template> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index 2dd3b2c2f98..5e8e251428a 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -18,11 +18,11 @@ export { default as WidgetDeployment } from './components/mr_widget_deployment'; export { default as WidgetRelatedLinks } from './components/mr_widget_related_links'; export { default as MergedState } from './components/states/mr_widget_merged'; export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge'; -export { default as ClosedState } from './components/states/mr_widget_closed'; +export { default as ClosedState } from './components/states/mr_widget_closed.vue'; export { default as MergingState } from './components/states/mr_widget_merging'; export { default as WipState } from './components/states/mr_widget_wip'; export { default as ArchivedState } from './components/states/mr_widget_archived.vue'; -export { default as ConflictsState } from './components/states/mr_widget_conflicts'; +export { default as ConflictsState } from './components/states/mr_widget_conflicts.vue'; export { default as NothingToMergeState } from './components/states/mr_widget_nothing_to_merge'; export { default as MissingBranchState } from './components/states/mr_widget_missing_branch'; export { default as NotAllowedState } from './components/states/mr_widget_not_allowed'; @@ -34,7 +34,7 @@ export { default as PipelineFailedState } from './components/states/mr_widget_pi export { default as MergeWhenPipelineSucceedsState } from './components/states/mr_widget_merge_when_pipeline_succeeds'; export { default as RebaseState } from './components/states/mr_widget_rebase.vue'; export { default as AutoMergeFailed } from './components/states/mr_widget_auto_merge_failed.vue'; -export { default as CheckingState } from './components/states/mr_widget_checking'; +export { default as CheckingState } from './components/states/mr_widget_checking.vue'; export { default as MRWidgetStore } from './stores/mr_widget_store'; export { default as MRWidgetService } from './services/mr_widget_service'; export { default as eventHub } from './event_hub'; diff --git a/changelogs/unreleased/fl-mr-widget-refactor.yml b/changelogs/unreleased/fl-mr-widget-refactor.yml new file mode 100644 index 00000000000..d59cca68409 --- /dev/null +++ b/changelogs/unreleased/fl-mr-widget-refactor.yml @@ -0,0 +1,5 @@ +--- +title: Refactors mr widget components into vue files and adds i18n +merge_request: +author: +type: other diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js index 6b7aa935ad3..658cadddb81 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js @@ -1,19 +1,29 @@ import Vue from 'vue'; -import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking'; +import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue'; +import mountComponent from '../../../helpers/vue_mount_component_helper'; describe('MRWidgetChecking', () => { - describe('template', () => { - it('should have correct elements', () => { - const Component = Vue.extend(checkingComponent); - const el = new Component({ - el: document.createElement('div'), - }).$el; + let Component; + let vm; - expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.querySelector('button').classList.contains('btn-success')).toBeTruthy(); - expect(el.querySelector('button').disabled).toBeTruthy(); - expect(el.innerText).toContain('Checking ability to merge automatically'); - expect(el.querySelector('i')).toBeDefined(); - }); + beforeEach(() => { + Component = Vue.extend(checkingComponent); + vm = mountComponent(Component); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders disabled button', () => { + expect(vm.$el.querySelector('button').getAttribute('disabled')).toEqual('disabled'); + }); + + it('renders loading icon', () => { + expect(vm.$el.querySelector('.mr-widget-icon i').classList).toContain('fa-spinner'); + }); + + it('renders information about merging', () => { + expect(vm.$el.querySelector('.media-body').textContent.trim()).toEqual('Checking ability to merge automatically'); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js index 1bf97bbf093..51a34739ee9 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_closed_spec.js @@ -1,74 +1,58 @@ import Vue from 'vue'; -import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed'; - -const mr = { - targetBranch: 'good-branch', - targetBranchPath: '/good-branch', - metrics: { - mergedBy: {}, - mergedAt: 'mergedUpdatedAt', - closedBy: { - name: 'Fatih Acet', - username: 'fatihacet', - }, - closedAt: 'closedEventUpdatedAt', - readableMergedAt: '', - readableClosedAt: '', - }, - updatedAt: 'mrUpdatedAt', - closedAt: '1 day ago', -}; - -const createComponent = () => { - const Component = Vue.extend(closedComponent); - - return new Component({ - el: document.createElement('div'), - propsData: { mr }, - }); -}; +import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue'; +import mountComponent from '../../../helpers/vue_mount_component_helper'; describe('MRWidgetClosed', () => { - describe('props', () => { - it('should have props', () => { - const mrProp = closedComponent.props.mr; - - expect(mrProp.type instanceof Object).toBeTruthy(); - expect(mrProp.required).toBeTruthy(); - }); + let vm; + + beforeEach(() => { + const Component = Vue.extend(closedComponent); + vm = mountComponent(Component, { mr: { + metrics: { + mergedBy: {}, + closedBy: { + name: 'Administrator', + username: 'root', + webUrl: 'http://localhost:3000/root', + avatarUrl: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + }, + mergedAt: 'Jan 24, 2018 1:02pm GMT+0000', + closedAt: 'Jan 24, 2018 1:02pm GMT+0000', + readableMergedAt: '', + readableClosedAt: 'less than a minute ago', + }, + targetBranchPath: '/twitter/flight/commits/so_long_jquery', + targetBranch: 'so_long_jquery', + } }); }); - describe('components', () => { - it('should have components added', () => { - expect(closedComponent.components['mr-widget-author-and-time']).toBeDefined(); - }); + afterEach(() => { + vm.$destroy(); }); - describe('template', () => { - let vm; - let el; + it('renders warning icon', () => { + expect(vm.$el.querySelector('.js-ci-status-icon-warning')).not.toBeNull(); + }); - beforeEach(() => { - vm = createComponent(); - el = vm.$el; - }); + it('renders closed by information with author and time', () => { + expect( + vm.$el.querySelector('.js-mr-widget-author').textContent.trim().replace(/\s\s+/g, ' '), + ).toContain( + 'Closed by Administrator less than a minute ago', + ); + }); - afterEach(() => { - vm.$destroy(); - }); + it('links to the user that closed the MR', () => { + expect(vm.$el.querySelector('.author-link').getAttribute('href')).toEqual('http://localhost:3000/root'); + }); - it('should have correct elements', () => { - expect(el.querySelector('h4').textContent).toContain('Closed by'); - expect(el.querySelector('h4').textContent).toContain(mr.metrics.closedBy.name); - expect(el.textContent).toContain('The changes were not merged into'); - expect(el.querySelector('.label-branch').getAttribute('href')).toEqual(mr.targetBranchPath); - expect(el.querySelector('.label-branch').textContent).toContain(mr.targetBranch); - }); + it('renders information about the changes not being merged', () => { + expect( + vm.$el.querySelector('.mr-info-list').textContent.trim().replace(/\s\s+/g, ' '), + ).toContain('The changes were not merged into so_long_jquery'); + }); - it('should use closedEvent updatedAt as tooltip title', () => { - expect( - el.querySelector('time').getAttribute('title'), - ).toBe('closedEventUpdatedAt'); - }); + it('renders link for target branch', () => { + expect(vm.$el.querySelector('.label-branch').getAttribute('href')).toEqual('/twitter/flight/commits/so_long_jquery'); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js index 5d4c7ec09dc..a7d69fdcdb9 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js @@ -1,105 +1,85 @@ import Vue from 'vue'; -import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts'; +import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; import mountComponent from '../../../helpers/vue_mount_component_helper'; -const ConflictsComponent = Vue.extend(conflictsComponent); -const path = '/conflicts'; - describe('MRWidgetConflicts', () => { - describe('props', () => { - it('should have props', () => { - const { mr } = conflictsComponent.props; + let Component; + let vm; + const path = '/conflicts'; - expect(mr.type instanceof Object).toBeTruthy(); - expect(mr.required).toBeTruthy(); - }); + beforeEach(() => { + Component = Vue.extend(conflictsComponent); }); - describe('template', () => { - describe('when allowed to merge', () => { - let vm; - - beforeEach(() => { - vm = mountComponent(ConflictsComponent, { - mr: { - canMerge: true, - conflictResolutionPath: path, - }, - }); - }); - - afterEach(() => { - vm.$destroy(); - }); - - it('should tell you about conflicts without bothering other people', () => { - expect(vm.$el.textContent).toContain('There are merge conflicts'); - expect(vm.$el.textContent).not.toContain('ask someone with write access'); - }); - - it('should allow you to resolve the conflicts', () => { - const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button'); + afterEach(() => { + vm.$destroy(); + }); - expect(resolveButton.textContent).toContain('Resolve conflicts'); - expect(resolveButton.getAttribute('href')).toEqual(path); + describe('when allowed to merge', () => { + beforeEach(() => { + vm = mountComponent(Component, { + mr: { + canMerge: true, + conflictResolutionPath: path, + }, }); + }); - it('should have merge buttons', () => { - const mergeButton = vm.$el.querySelector('.js-disabled-merge-button'); - const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button'); - - expect(mergeButton.textContent).toContain('Merge'); - expect(mergeButton.disabled).toBeTruthy(); - expect(mergeButton.classList.contains('btn-success')).toEqual(true); - expect(mergeLocallyButton.textContent).toContain('Merge locally'); - }); + it('should tell you about conflicts without bothering other people', () => { + expect(vm.$el.textContent).toContain('There are merge conflicts'); + expect(vm.$el.textContent).not.toContain('ask someone with write access'); }); - describe('when user does not have permission to merge', () => { - let vm; + it('should allow you to resolve the conflicts', () => { + const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button'); - beforeEach(() => { - vm = mountComponent(ConflictsComponent, { - mr: { - canMerge: false, - }, - }); - }); + expect(resolveButton.textContent).toContain('Resolve conflicts'); + expect(resolveButton.getAttribute('href')).toEqual(path); + }); - afterEach(() => { - vm.$destroy(); - }); + it('should have merge buttons', () => { + const mergeButton = vm.$el.querySelector('.js-disabled-merge-button'); + const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button'); - it('should show proper message', () => { - expect(vm.$el.textContent).toContain('ask someone with write access'); - }); + expect(mergeButton.textContent).toContain('Merge'); + expect(mergeButton.disabled).toBeTruthy(); + expect(mergeButton.classList.contains('btn-success')).toEqual(true); + expect(mergeLocallyButton.textContent).toContain('Merge locally'); + }); + }); - it('should not have action buttons', () => { - expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined(); - expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull(); - expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull(); + describe('when user does not have permission to merge', () => { + beforeEach(() => { + vm = mountComponent(Component, { + mr: { + canMerge: false, + }, }); }); - describe('when fast-forward or semi-linear merge enabled', () => { - let vm; + it('should show proper message', () => { + expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('ask someone with write access'); + }); - beforeEach(() => { - vm = mountComponent(ConflictsComponent, { - mr: { - shouldBeRebased: true, - }, - }); - }); + it('should not have action buttons', () => { + expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined(); + expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull(); + expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull(); + }); + }); - afterEach(() => { - vm.$destroy(); + describe('when fast-forward or semi-linear merge enabled', () => { + beforeEach(() => { + vm = mountComponent(Component, { + mr: { + shouldBeRebased: true, + }, }); + }); - it('should tell you to rebase locally', () => { - expect(vm.$el.textContent).toContain('Fast-forward merge is not possible.'); - expect(vm.$el.textContent).toContain('To merge this request, first rebase locally'); - }); + it('should tell you to rebase locally', () => { + expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('Fast-forward merge is not possible.'); + expect(vm.$el.textContent.trim().replace(/\s\s+/g, ' ')).toContain('To merge this request, first rebase locally'); }); }); }); |