diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 77b35078e56..d479b705e35 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -65,61 +65,63 @@ export default { + - + + diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index c13eeeace3f..70c6d53c3ab 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -1,11 +1,14 @@ diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js index 971a15a4036..eff9bc03651 100644 --- a/app/assets/javascripts/ide/stores/actions/project.js +++ b/app/assets/javascripts/ide/stores/actions/project.js @@ -72,3 +72,26 @@ export const getBranchData = ( resolve(state.projects[`${projectId}`].branches[branchId]); } }); + +export const refreshLastCommitData = ( + { commit, state, dispatch }, + { projectId, branchId } = {}, +) => service + .getBranchData(projectId, branchId) + .then(({ data }) => { + commit(types.SET_BRANCH_COMMIT, { + projectId, + branchId, + commit: data.commit, + }); + }) + .catch(() => { + flash( + 'Error loading last commit.', + 'alert', + document, + null, + false, + true, + ); + }); diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index 75286ed0cd2..b239a605371 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -81,5 +81,11 @@ export const getUnstagedFilesCountForPath = state => path => export const getStagedFilesCountForPath = state => path => getChangesCountForFiles(state.stagedFiles, path); +export const lastCommit = (state, getters) => { + const branch = getters.currentProject && getters.currentProject.branches[state.currentBranchId]; + + return branch ? branch.commit : null; +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index ab00d12089d..b85246b2502 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -210,7 +210,11 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ); } }) - .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)); + .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)) + .then(() => dispatch('refreshLastCommitData', { + projectId: rootState.currentProjectId, + branchId: rootState.currentBranchId, + }, { root: true })); }) .catch(err => { let errMsg = __('Error committing changes. Please try again.'); diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 08e22e5ad7e..a3fb3232f1d 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -20,6 +20,7 @@ export const SET_MERGE_REQUEST_VERSIONS = 'SET_MERGE_REQUEST_VERSIONS'; // Branch Mutation Types export const SET_BRANCH = 'SET_BRANCH'; +export const SET_BRANCH_COMMIT = 'SET_BRANCH_COMMIT'; export const SET_BRANCH_WORKING_REFERENCE = 'SET_BRANCH_WORKING_REFERENCE'; export const TOGGLE_BRANCH_OPEN = 'TOGGLE_BRANCH_OPEN'; diff --git a/app/assets/javascripts/ide/stores/mutations/branch.js b/app/assets/javascripts/ide/stores/mutations/branch.js index 2972ba5e38e..e09f88878f4 100644 --- a/app/assets/javascripts/ide/stores/mutations/branch.js +++ b/app/assets/javascripts/ide/stores/mutations/branch.js @@ -23,4 +23,9 @@ export default { workingReference: reference, }); }, + [types.SET_BRANCH_COMMIT](state, { projectId, branchId, commit }) { + Object.assign(state.projects[projectId].branches[branchId], { + commit, + }); + }, }; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 8d43bb32175..cbf99e411cd 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -230,6 +230,7 @@ $row-hover: $blue-50; $row-hover-border: $blue-200; $progress-color: #c0392b; $header-height: 40px; +$ide-statusbar-height: 27px; $fixed-layout-width: 1280px; $limited-layout-width: 990px; $limited-layout-width-sm: 790px; diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 7f1f0c1f5f1..00457717f00 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -23,6 +23,7 @@ margin-top: 0; border-top: 1px solid $white-dark; border-bottom: 1px solid $white-dark; + padding-bottom: $ide-statusbar-height; &.is-collapsed { .ide-file-list { @@ -375,7 +376,13 @@ padding: $gl-bar-padding $gl-padding; background: $white-light; display: flex; - justify-content: flex-end; + justify-content: space-between; + height: $ide-statusbar-height; + + position: absolute; + bottom: 0; + left: 0; + width: 100%; > div + div { padding-left: $gl-padding; @@ -386,6 +393,14 @@ } } +.ide-status-file { + text-align: right; + + .ide-status-branch + &, + &:first-child { + margin-left: auto; + } +} // Not great, but this is to deal with our current output .multi-file-preview-holder { height: 100%; diff --git a/changelogs/unreleased/44833-ide-clean-up-status-bar.yml b/changelogs/unreleased/44833-ide-clean-up-status-bar.yml new file mode 100644 index 00000000000..4c827e57195 --- /dev/null +++ b/changelogs/unreleased/44833-ide-clean-up-status-bar.yml @@ -0,0 +1,5 @@ +--- +title: Clean up WebIDE status bar and add useful info +merge_request: +author: +type: changed diff --git a/spec/javascripts/ide/components/ide_status_bar_spec.js b/spec/javascripts/ide/components/ide_status_bar_spec.js new file mode 100644 index 00000000000..770dca9cb0f --- /dev/null +++ b/spec/javascripts/ide/components/ide_status_bar_spec.js @@ -0,0 +1,63 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import ideStatusBar from '~/ide/components/ide_status_bar.vue'; +import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; +import { resetStore } from '../helpers'; +import { projectData } from '../mock_data'; + +describe('ideStatusBar', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(ideStatusBar); + + store.state.currentProjectId = 'abcproject'; + store.state.projects.abcproject = projectData; + + vm = createComponentWithStore(Component, store).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders the statusbar', () => { + expect(vm.$el.className).toBe('ide-status-bar'); + }); + + describe('mounted', () => { + it('triggers a setInterval', () => { + expect(vm.intervalId).not.toBe(null); + }); + }); + + describe('commitAgeUpdate', () => { + beforeEach(function() { + jasmine.clock().install(); + spyOn(vm, 'commitAgeUpdate').and.callFake(() => {}); + vm.startTimer(); + }); + + afterEach(function() { + jasmine.clock().uninstall(); + }); + + it('gets called every second', () => { + expect(vm.commitAgeUpdate).not.toHaveBeenCalled(); + + jasmine.clock().tick(1100); + expect(vm.commitAgeUpdate.calls.count()).toEqual(1); + + jasmine.clock().tick(1000); + expect(vm.commitAgeUpdate.calls.count()).toEqual(2); + }); + }); + + describe('getCommitPath', () => { + it('returns the path to the commit details', () => { + expect(vm.getCommitPath('abc123de')).toBe('/commit/abc123de'); + }); + }); +}); diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js new file mode 100644 index 00000000000..ebd08d95810 --- /dev/null +++ b/spec/javascripts/ide/stores/actions/project_spec.js @@ -0,0 +1,71 @@ +import { + refreshLastCommitData, +} from '~/ide/stores/actions'; +import store from '~/ide/stores'; +import service from '~/ide/services'; +import { resetStore } from '../../helpers'; +import testAction from '../../../helpers/vuex_action_helper'; + +describe('IDE store project actions', () => { + beforeEach(() => { + store.state.projects.abcproject = {}; + }); + + afterEach(() => { + resetStore(store); + }); + + describe('refreshLastCommitData', () => { + beforeEach(() => { + store.state.currentProjectId = 'abcproject'; + store.state.currentBranchId = 'master'; + store.state.projects.abcproject = { + branches: { + master: { + commit: null, + }, + }, + }; + }); + + it('calls the service', done => { + spyOn(service, 'getBranchData').and.returnValue( + Promise.resolve({ + data: { + commit: { id: '123' }, + }, + }), + ); + + store + .dispatch('refreshLastCommitData', { + projectId: store.state.currentProjectId, + branchId: store.state.currentBranchId, + }) + .then(() => { + expect(service.getBranchData).toHaveBeenCalledWith('abcproject', 'master'); + + done(); + }) + .catch(done.fail); + }); + + it('commits getBranchData', done => { + testAction( + refreshLastCommitData, + {}, + {}, + [{ + type: 'SET_BRANCH_COMMIT', + payload: { + projectId: 'abcproject', + branchId: 'master', + commit: { id: '123' }, + }, + }], // mutations + [], // action + done, + ); + }); + }); +}); diff --git a/spec/javascripts/ide/stores/getters_spec.js b/spec/javascripts/ide/stores/getters_spec.js index 67a848e8edd..4833ba3edfd 100644 --- a/spec/javascripts/ide/stores/getters_spec.js +++ b/spec/javascripts/ide/stores/getters_spec.js @@ -141,4 +141,24 @@ describe('IDE store getters', () => { expect(getters.getChangesInFolder(localState)('test')).toBe(2); }); }); + + describe('lastCommit', () => { + it('returns the last commit of the current branch on the current project', () => { + const commitTitle = 'Example commit title'; + const localGetters = { + currentProject: { + branches: { + 'example-branch': { + commit: { + title: commitTitle, + }, + }, + }, + }, + }; + localState.currentBranchId = 'example-branch'; + + expect(getters.lastCommit(localState, localGetters).title).toBe(commitTitle); + }); + }); }); diff --git a/spec/javascripts/ide/stores/mutations/branch_spec.js b/spec/javascripts/ide/stores/mutations/branch_spec.js index a7167537ef2..29eb859ddaf 100644 --- a/spec/javascripts/ide/stores/mutations/branch_spec.js +++ b/spec/javascripts/ide/stores/mutations/branch_spec.js @@ -15,4 +15,26 @@ describe('Multi-file store branch mutations', () => { expect(localState.currentBranchId).toBe('master'); }); }); + + describe('SET_BRANCH_COMMIT', () => { + it('sets the last commit on current project', () => { + localState.projects = { + Example: { + branches: { + master: {}, + }, + }, + }; + + mutations.SET_BRANCH_COMMIT(localState, { + projectId: 'Example', + branchId: 'master', + commit: { + title: 'Example commit', + }, + }); + + expect(localState.projects.Example.branches.master.commit.title).toBe('Example commit'); + }); + }); });