diff options
15 files changed, 169 insertions, 61 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue index 6424b93ce54..1f6bbca13b5 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue @@ -15,17 +15,10 @@ export default { type: String, required: true, }, - committedStateSvgPath: { - type: String, - required: true, - }, }, computed: { - ...mapState(['lastCommitMsg', 'rightPanelCollapsed']), + ...mapState(['lastCommitMsg', 'rightPanelCollapsed', 'changedFiles', 'stagedFiles']), ...mapGetters(['collapseButtonIcon', 'collapseButtonTooltip']), - statusSvg() { - return this.lastCommitMsg ? this.committedStateSvgPath : this.noChangesStateSvgPath; - }, }, methods: { ...mapActions(['toggleRightPanelCollapsed']), @@ -35,6 +28,7 @@ export default { <template> <div + v-if="!lastCommitMsg" class="multi-file-commit-panel-section ide-commit-empty-state js-empty-state" > <header @@ -64,12 +58,11 @@ export default { v-if="!rightPanelCollapsed" > <div class="svg-content svg-80"> - <img :src="statusSvg" /> + <img :src="noChangesStateSvgPath" /> </div> <div class="append-right-default prepend-left-default"> <div class="text-content text-center" - v-if="!lastCommitMsg" > <h4> {{ __('No changes') }} @@ -78,15 +71,6 @@ export default { {{ __('Edit files in the editor and commit changes here') }} </p> </div> - <div - class="text-content text-center" - v-else - > - <h4> - {{ __('All changes are committed') }} - </h4> - <p v-html="lastCommitMsg"></p> - </div> </div> </div> </div> diff --git a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue new file mode 100644 index 00000000000..628a17eddca --- /dev/null +++ b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue @@ -0,0 +1,39 @@ +<script> +import { mapState } from 'vuex'; + +export default { + props: { + committedStateSvgPath: { + type: String, + required: true, + }, + }, + computed: { + ...mapState(['lastCommitMsg']), + }, +}; +</script> + +<template> + <div + class="multi-file-commit-panel-success-message" + aria-live="assertive" + > + <div class="svg-content svg-80"> + <img + :src="committedStateSvgPath" + alt="" + /> + </div> + <div class="append-right-default prepend-left-default"> + <div + class="text-content text-center" + > + <h4> + {{ __('All changes are committed') }} + </h4> + <p v-html="lastCommitMsg"></p> + </div> + </div> + </div> +</template> diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue index 877d1b5e026..fa929381744 100644 --- a/app/assets/javascripts/ide/components/repo_commit_section.vue +++ b/app/assets/javascripts/ide/components/repo_commit_section.vue @@ -7,6 +7,7 @@ import LoadingButton from '~/vue_shared/components/loading_button.vue'; import CommitFilesList from './commit_sidebar/list.vue'; import EmptyState from './commit_sidebar/empty_state.vue'; import CommitMessageField from './commit_sidebar/message_field.vue'; +import SuccessMessage from './commit_sidebar/success_message.vue'; import * as consts from '../stores/modules/commit/constants'; import Actions from './commit_sidebar/actions.vue'; @@ -16,6 +17,7 @@ export default { Icon, CommitFilesList, EmptyState, + SuccessMessage, Actions, LoadingButton, CommitMessageField, @@ -34,9 +36,15 @@ export default { }, }, computed: { - ...mapState(['changedFiles', 'stagedFiles', 'rightPanelCollapsed']), + showStageUnstageArea() { + return !!(this.someUncommitedChanges || this.lastCommitMsg || !this.unusedSeal); + }, + someUncommitedChanges() { + return !!(this.changedFiles.length || this.stagedFiles.length); + }, + ...mapState(['changedFiles', 'stagedFiles', 'rightPanelCollapsed', 'lastCommitMsg', 'unusedSeal']), ...mapState('commit', ['commitMessage', 'submitCommitLoading']), - ...mapGetters('commit', ['commitButtonDisabled', 'discardDraftButtonDisabled', 'branchName']), + ...mapGetters('commit', ['commitButtonDisabled', 'discardDraftButtonDisabled']), }, methods: { ...mapActions('commit', [ @@ -69,7 +77,7 @@ export default { </template> </deprecated-modal> <template - v-if="changedFiles.length || stagedFiles.length" + v-if="showStageUnstageArea" > <commit-files-list icon-name="unstaged" @@ -89,11 +97,23 @@ export default { :show-toggle="false" :staged-list="true" /> + </template> + <empty-state + v-if="unusedSeal" + :no-changes-state-svg-path="noChangesStateSvgPath" + /> + <div + class="multi-file-commit-panel-bottom" + > <form class="form-horizontal multi-file-commit-form" @submit.prevent.stop="commitChanges" v-if="!rightPanelCollapsed" > + <success-message + v-if="lastCommitMsg && !someUncommitedChanges" + :committed-state-svg-path="committedStateSvgPath" + /> <commit-message-field :text="commitMessage" @input="updateCommitMessage" @@ -117,11 +137,6 @@ export default { </button> </div> </form> - </template> - <empty-state - v-else - :no-changes-state-svg-path="noChangesStateSvgPath" - :committed-state-svg-path="committedStateSvgPath" - /> + </div> </div> </template> diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 4c8c997e376..7358dd9ef92 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -149,6 +149,12 @@ export const updateTempFlagForEntry = ({ commit, dispatch, state }, { file, temp export const toggleFileFinder = ({ commit }, fileFindVisible) => commit(types.TOGGLE_FILE_FINDER, fileFindVisible); +export const burstUnusedSeal = ({ state, commit }) => { + if (state.unusedSeal) { + commit(types.BURST_UNUSED_SEAL); + } +}; + export * from './actions/tree'; export * from './actions/file'; export * from './actions/project'; diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index fcdb3b753b2..861830badee 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -117,7 +117,7 @@ export const getRawFileData = ({ state, commit, dispatch }, { path, baseSha }) = }); }; -export const changeFileContent = ({ state, commit }, { path, content }) => { +export const changeFileContent = ({ commit, dispatch, state }, { path, content }) => { const file = state.entries[path]; commit(types.UPDATE_FILE_CONTENT, { path, content }); @@ -128,6 +128,8 @@ export const changeFileContent = ({ state, commit }, { path, content }) => { } else if (!file.changed && indexOfChangedFile !== -1) { commit(types.REMOVE_FILE_FROM_CHANGED, path); } + + dispatch('burstUnusedSeal', {}, { root: true }); }; export const setFileLanguage = ({ getters, commit }, { fileLanguage }) => { diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js index 349ff68f1e3..4fbc97d053e 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/actions.js +++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js @@ -182,6 +182,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState }) = } commit(rootTypes.CLEAR_STAGED_CHANGES, null, { root: true }); + + setTimeout(() => { + commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true }); + }, 5000); }) .then(() => dispatch('updateCommitAction', consts.COMMIT_TO_CURRENT_BRANCH)); }) diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index f5c12db6db0..87b39379338 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -61,3 +61,4 @@ export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB'; export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG'; export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER'; +export const BURST_UNUSED_SEAL = 'BURST_UNUSED_SEAL'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 0c1d720df09..539a07116b3 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -128,6 +128,11 @@ export default { }), }); }, + [types.BURST_UNUSED_SEAL](state) { + Object.assign(state, { + unusedSeal: false, + }); + }, ...projectMutations, ...mergeRequestMutation, ...fileMutations, diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 3470bb9aec0..0976d278559 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -18,5 +18,6 @@ export default () => ({ entries: {}, viewer: 'editor', delayViewerUpdated: false, + unusedSeal: true, fileFindVisible: false, }); diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 6342042374f..2c0b20809ba 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -549,6 +549,7 @@ margin-bottom: 0; border-bottom: 1px solid $white-dark; padding: $gl-btn-padding 0; + min-height: 56px; } .multi-file-commit-panel-header-title { @@ -673,6 +674,24 @@ } } +.multi-file-commit-panel-bottom { + position: relative; + + .multi-file-commit-panel-success-message { + position: absolute; + top: 1px; + left: 3px; + bottom: 0; + right: 0; + z-index: 10; + background: $gray-light; + overflow: auto; + display: flex; + flex-direction: column; + justify-content: center; + } +} + .dirty-diff { // !important need to override monaco inline style width: 4px !important; diff --git a/changelogs/unreleased/ide-improve-commit-panel.yml b/changelogs/unreleased/ide-improve-commit-panel.yml new file mode 100644 index 00000000000..f6237db3039 --- /dev/null +++ b/changelogs/unreleased/ide-improve-commit-panel.yml @@ -0,0 +1,5 @@ +--- +title: Improve interaction on WebIDE commit panel +merge_request: +author: +type: changed diff --git a/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js index b80d08de7b1..53275b78da5 100644 --- a/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/empty_state_spec.js @@ -24,42 +24,10 @@ describe('IDE commit panel empty state', () => { resetStore(vm.$store); }); - describe('statusSvg', () => { - it('uses noChangesStateSvgPath when commit message is empty', () => { - expect(vm.statusSvg).toBe('no-changes'); - expect(vm.$el.querySelector('img').getAttribute('src')).toBe( - 'no-changes', - ); - }); - - it('uses committedStateSvgPath when commit message exists', done => { - vm.$store.state.lastCommitMsg = 'testing'; - - Vue.nextTick(() => { - expect(vm.statusSvg).toBe('committed-state'); - expect(vm.$el.querySelector('img').getAttribute('src')).toBe( - 'committed-state', - ); - - done(); - }); - }); - }); - it('renders no changes text when last commit message is empty', () => { expect(vm.$el.textContent).toContain('No changes'); }); - it('renders last commit message when it exists', done => { - vm.$store.state.lastCommitMsg = 'testing commit message'; - - Vue.nextTick(() => { - expect(vm.$el.textContent).toContain('testing commit message'); - - done(); - }); - }); - describe('toggle button', () => { it('calls store action', () => { spyOn(vm, 'toggleRightPanelCollapsed'); diff --git a/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js b/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js new file mode 100644 index 00000000000..e1a432b81be --- /dev/null +++ b/spec/javascripts/ide/components/commit_sidebar/success_message_spec.js @@ -0,0 +1,35 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import successMessage from '~/ide/components/commit_sidebar/success_message.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { resetStore } from '../../helpers'; + +describe('IDE commit panel successful commit state', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(successMessage); + + vm = createComponentWithStore(Component, store, { + committedStateSvgPath: 'committed-state', + }); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('renders last commit message when it exists', done => { + vm.$store.state.lastCommitMsg = 'testing commit message'; + + Vue.nextTick(() => { + expect(vm.$el.textContent).toContain('testing commit message'); + + done(); + }); + }); +}); diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js index ce5c525bed7..3ee11bd2f03 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/javascripts/ide/stores/actions/file_spec.js @@ -398,6 +398,20 @@ describe('IDE store file actions', () => { }) .catch(done.fail); }); + + it('bursts unused seal', done => { + store + .dispatch('changeFileContent', { + path: tmpFile.path, + content: 'content', + }) + .then(() => { + expect(store.state.unusedSeal).toBe(false); + + done(); + }) + .catch(done.fail); + }); }); describe('discardFileChanges', () => { diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js index 997711d1e19..61efb6372c9 100644 --- a/spec/javascripts/ide/stores/mutations_spec.js +++ b/spec/javascripts/ide/stores/mutations_spec.js @@ -116,4 +116,14 @@ describe('Multi-file store mutations', () => { expect(localState.fileFindVisible).toBe(true); }); }); + + describe('BURST_UNUSED_SEAL', () => { + it('updates unusedSeal', () => { + expect(localState.unusedSeal).toBe(true); + + mutations.BURST_UNUSED_SEAL(localState); + + expect(localState.unusedSeal).toBe(false); + }); + }); }); |