Improve Web IDE Commit Panel
This commit is contained in:
parent
0108cdf953
commit
7a8af42923
15 changed files with 169 additions and 61 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -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));
|
||||
})
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -128,6 +128,11 @@ export default {
|
|||
}),
|
||||
});
|
||||
},
|
||||
[types.BURST_UNUSED_SEAL](state) {
|
||||
Object.assign(state, {
|
||||
unusedSeal: false,
|
||||
});
|
||||
},
|
||||
...projectMutations,
|
||||
...mergeRequestMutation,
|
||||
...fileMutations,
|
||||
|
|
|
@ -18,5 +18,6 @@ export default () => ({
|
|||
entries: {},
|
||||
viewer: 'editor',
|
||||
delayViewerUpdated: false,
|
||||
unusedSeal: true,
|
||||
fileFindVisible: false,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
5
changelogs/unreleased/ide-improve-commit-panel.yml
Normal file
5
changelogs/unreleased/ide-improve-commit-panel.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve interaction on WebIDE commit panel
|
||||
merge_request:
|
||||
author:
|
||||
type: changed
|
|
@ -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');
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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', () => {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue