Commit a9076d67 authored by Himanshu Kapoor's avatar Himanshu Kapoor

Web IDE: Always show the commit tab

Don't hide the commit tab in the view even if there are no changes.
parent 6123dff4
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { leftSidebarViews } from '../constants'; import { leftSidebarViews } from '../constants';
...@@ -13,7 +13,6 @@ export default { ...@@ -13,7 +13,6 @@ export default {
tooltip, tooltip,
}, },
computed: { computed: {
...mapGetters(['someUncommittedChanges']),
...mapState(['currentActivityView']), ...mapState(['currentActivityView']),
}, },
methods: { methods: {
...@@ -69,7 +68,7 @@ export default { ...@@ -69,7 +68,7 @@ export default {
<icon name="file-modified" /> <icon name="file-modified" />
</button> </button>
</li> </li>
<li v-show="someUncommittedChanges"> <li>
<button <button
v-tooltip v-tooltip
:class="{ :class="{
......
...@@ -40,20 +40,9 @@ export default { ...@@ -40,20 +40,9 @@ export default {
}, },
}, },
watch: { watch: {
currentActivityView() { currentActivityView: 'handleCompactState',
if (this.lastCommitMsg) { someUncommittedChanges: 'handleCompactState',
this.isCompact = false; lastCommitMsg: 'handleCompactState',
} else {
this.isCompact = !(
this.currentViewIsCommitView && window.innerHeight >= MAX_WINDOW_HEIGHT_COMPACT
);
}
},
lastCommitMsg() {
this.isCompact =
this.currentActivityView !== leftSidebarViews.commit.name && this.lastCommitMsg === '';
},
}, },
methods: { methods: {
...mapActions(['updateActivityBarView']), ...mapActions(['updateActivityBarView']),
...@@ -71,19 +60,24 @@ export default { ...@@ -71,19 +60,24 @@ export default {
forceCreateNewBranch() { forceCreateNewBranch() {
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit()); return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit());
}, },
toggleIsCompact() { handleCompactState() {
if (this.currentViewIsCommitView) { if (this.lastCommitMsg) {
this.isCompact = !this.isCompact; this.isCompact = false;
} else { } else {
this.updateActivityBarView(leftSidebarViews.commit.name) this.isCompact =
.then(() => { !this.someUncommittedChanges ||
this.isCompact = false; !this.currentViewIsCommitView ||
}) window.innerHeight < MAX_WINDOW_HEIGHT_COMPACT;
.catch(e => {
throw e;
});
} }
}, },
toggleIsCompact() {
this.isCompact = !this.isCompact;
},
beginCommit() {
return this.updateActivityBarView(leftSidebarViews.commit.name).then(() => {
this.isCompact = false;
});
},
beforeEnterTransition() { beforeEnterTransition() {
const elHeight = this.isCompact const elHeight = this.isCompact
? this.$refs.formEl && this.$refs.formEl.offsetHeight ? this.$refs.formEl && this.$refs.formEl.offsetHeight
...@@ -129,13 +123,14 @@ export default { ...@@ -129,13 +123,14 @@ export default {
:disabled="!someUncommittedChanges" :disabled="!someUncommittedChanges"
type="button" type="button"
class="btn btn-primary btn-sm btn-block qa-begin-commit-button" class="btn btn-primary btn-sm btn-block qa-begin-commit-button"
@click="toggleIsCompact" data-testid="begin-commit-button"
@click="beginCommit"
> >
{{ __('Commit…') }} {{ __('Commit…') }}
</button> </button>
<p class="text-center bold">{{ overviewText }}</p> <p class="text-center bold">{{ overviewText }}</p>
</div> </div>
<form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commit"> <form v-else ref="formEl" @submit.prevent.stop="commit">
<transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition> <transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition>
<commit-message-field <commit-message-field
:text="commitMessage" :text="commitMessage"
......
...@@ -3,7 +3,7 @@ import { mapState, mapActions, mapGetters } from 'vuex'; ...@@ -3,7 +3,7 @@ import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import CommitFilesList from './commit_sidebar/list.vue'; import CommitFilesList from './commit_sidebar/list.vue';
import EmptyState from './commit_sidebar/empty_state.vue'; import EmptyState from './commit_sidebar/empty_state.vue';
import { leftSidebarViews, stageKeys } from '../constants'; import { stageKeys } from '../constants';
export default { export default {
components: { components: {
...@@ -25,28 +25,26 @@ export default { ...@@ -25,28 +25,26 @@ export default {
return this.activeFile ? this.activeFile.key : null; return this.activeFile ? this.activeFile.key : null;
}, },
}, },
watch: {
someUncommittedChanges() {
if (!this.someUncommittedChanges) {
this.updateActivityBarView(leftSidebarViews.edit.name);
}
},
},
mounted() { mounted() {
if (this.lastOpenedFile && this.lastOpenedFile.type !== 'tree') { const file =
this.openPendingTab({ this.lastOpenedFile && this.lastOpenedFile.type !== 'tree'
file: this.lastOpenedFile, ? this.lastOpenedFile
keyPrefix: this.lastOpenedFile.staged ? stageKeys.staged : stageKeys.unstaged, : this.activeFile;
if (!file) return;
this.openPendingTab({
file,
keyPrefix: file.staged ? stageKeys.staged : stageKeys.unstaged,
})
.then(changeViewer => {
if (changeViewer) {
this.updateViewer('diff');
}
}) })
.then(changeViewer => { .catch(e => {
if (changeViewer) { throw e;
this.updateViewer('diff'); });
}
})
.catch(e => {
throw e;
});
}
}, },
methods: { methods: {
...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']), ...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']),
......
...@@ -51,7 +51,6 @@ export default { ...@@ -51,7 +51,6 @@ export default {
'getStagedFile', 'getStagedFile',
'isEditModeActive', 'isEditModeActive',
'isCommitModeActive', 'isCommitModeActive',
'isReviewModeActive',
'currentBranch', 'currentBranch',
]), ]),
...mapGetters('fileTemplates', ['showFileTemplatesBar']), ...mapGetters('fileTemplates', ['showFileTemplatesBar']),
...@@ -231,7 +230,7 @@ export default { ...@@ -231,7 +230,7 @@ export default {
if (this.viewer === viewerTypes.edit) { if (this.viewer === viewerTypes.edit) {
this.editor.createInstance(this.$refs.editor); this.editor.createInstance(this.$refs.editor);
} else { } else {
this.editor.createDiffInstance(this.$refs.editor, !this.isReviewModeActive); this.editor.createDiffInstance(this.$refs.editor);
} }
this.setupEditor(); this.setupEditor();
......
...@@ -37,6 +37,10 @@ export default class Editor { ...@@ -37,6 +37,10 @@ export default class Editor {
...defaultEditorOptions, ...defaultEditorOptions,
...options, ...options,
}; };
this.diffOptions = {
...defaultDiffEditorOptions,
...options,
};
setupThemes(); setupThemes();
registerLanguages(...languages); registerLanguages(...languages);
...@@ -66,18 +70,14 @@ export default class Editor { ...@@ -66,18 +70,14 @@ export default class Editor {
} }
} }
createDiffInstance(domElement, readOnly = true) { createDiffInstance(domElement) {
if (!this.instance) { if (!this.instance) {
clearDomElement(domElement); clearDomElement(domElement);
this.disposable.add( this.disposable.add(
(this.instance = monacoEditor.createDiffEditor(domElement, { (this.instance = monacoEditor.createDiffEditor(domElement, {
...this.options, ...this.diffOptions,
...defaultDiffEditorOptions,
renderSideBySide: Editor.renderSideBySide(domElement), renderSideBySide: Editor.renderSideBySide(domElement),
readOnly,
renderLineHighlight: readOnly ? 'all' : 'none',
hideCursorInOverviewRuler: !readOnly,
})), })),
); );
......
...@@ -14,9 +14,13 @@ export const defaultDiffOptions = { ...@@ -14,9 +14,13 @@ export const defaultDiffOptions = {
}; };
export const defaultDiffEditorOptions = { export const defaultDiffEditorOptions = {
...defaultEditorOptions,
quickSuggestions: false, quickSuggestions: false,
occurrencesHighlight: false, occurrencesHighlight: false,
ignoreTrimWhitespace: false, ignoreTrimWhitespace: false,
readOnly: false,
renderLineHighlight: 'none',
hideCursorInOverviewRuler: true,
}; };
export const defaultModelOptions = { export const defaultModelOptions = {
......
...@@ -27,8 +27,7 @@ ...@@ -27,8 +27,7 @@
z-index: 2; z-index: 2;
} }
.is-readonly, .is-readonly .editor.original {
.editor.original {
.view-lines { .view-lines {
cursor: default; cursor: default;
} }
......
---
title: Don't hide Commit tab in Web IDE when there are no changes yet
merge_request: 32979
author:
type: added
...@@ -30,14 +30,4 @@ describe 'IDE user commits changes', :js do ...@@ -30,14 +30,4 @@ describe 'IDE user commits changes', :js do
expect(project.repository.blob_at('master', 'foo/bar/.gitkeep')).to be_nil expect(project.repository.blob_at('master', 'foo/bar/.gitkeep')).to be_nil
expect(project.repository.blob_at('master', 'foo/bar/lorem_ipsum.md').data).to eql(content) expect(project.repository.blob_at('master', 'foo/bar/lorem_ipsum.md').data).to eql(content)
end end
it 'user adds then deletes new file' do
ide_create_new_file('foo/bar/lorem_ipsum.md')
expect(page).to have_selector(ide_commit_tab_selector)
ide_delete_file('foo/bar/lorem_ipsum.md')
expect(page).not_to have_selector(ide_commit_tab_selector)
end
end end
...@@ -5,11 +5,14 @@ import store from '~/ide/stores'; ...@@ -5,11 +5,14 @@ import store from '~/ide/stores';
import CommitForm from '~/ide/components/commit_sidebar/form.vue'; import CommitForm from '~/ide/components/commit_sidebar/form.vue';
import { leftSidebarViews } from '~/ide/constants'; import { leftSidebarViews } from '~/ide/constants';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
import waitForPromises from 'helpers/wait_for_promises';
describe('IDE commit form', () => { describe('IDE commit form', () => {
const Component = Vue.extend(CommitForm); const Component = Vue.extend(CommitForm);
let vm; let vm;
const beginCommitButton = () => vm.$el.querySelector('[data-testid="begin-commit-button"]');
beforeEach(() => { beforeEach(() => {
store.state.changedFiles.push('test'); store.state.changedFiles.push('test');
store.state.currentProjectId = 'abcproject'; store.state.currentProjectId = 'abcproject';
...@@ -25,8 +28,15 @@ describe('IDE commit form', () => { ...@@ -25,8 +28,15 @@ describe('IDE commit form', () => {
resetStore(vm.$store); resetStore(vm.$store);
}); });
it('enables button when has changes', () => { it('enables begin commit button when there are changes', () => {
expect(vm.$el.querySelector('[disabled]')).toBe(null); expect(beginCommitButton()).not.toHaveAttr('disabled');
});
it('disables begin commit button when there are no changes', async () => {
store.state.changedFiles = [];
await vm.$nextTick();
expect(beginCommitButton()).toHaveAttr('disabled');
}); });
describe('compact', () => { describe('compact', () => {
...@@ -37,8 +47,8 @@ describe('IDE commit form', () => { ...@@ -37,8 +47,8 @@ describe('IDE commit form', () => {
}); });
it('renders commit button in compact mode', () => { it('renders commit button in compact mode', () => {
expect(vm.$el.querySelector('.btn-primary')).not.toBeNull(); expect(beginCommitButton()).not.toBeNull();
expect(vm.$el.querySelector('.btn-primary').textContent).toContain('Commit'); expect(beginCommitButton().textContent).toContain('Commit');
}); });
it('does not render form', () => { it('does not render form', () => {
...@@ -54,7 +64,7 @@ describe('IDE commit form', () => { ...@@ -54,7 +64,7 @@ describe('IDE commit form', () => {
}); });
it('shows form when clicking commit button', () => { it('shows form when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); beginCommitButton().click();
return vm.$nextTick(() => { return vm.$nextTick(() => {
expect(vm.$el.querySelector('form')).not.toBeNull(); expect(vm.$el.querySelector('form')).not.toBeNull();
...@@ -62,7 +72,7 @@ describe('IDE commit form', () => { ...@@ -62,7 +72,7 @@ describe('IDE commit form', () => {
}); });
it('toggles activity bar view when clicking commit button', () => { it('toggles activity bar view when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); beginCommitButton().click();
return vm.$nextTick(() => { return vm.$nextTick(() => {
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name); expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
...@@ -83,6 +93,97 @@ describe('IDE commit form', () => { ...@@ -83,6 +93,97 @@ describe('IDE commit form', () => {
// collapsed when set to empty // collapsed when set to empty
expect(vm.isCompact).toBe(true); expect(vm.isCompact).toBe(true);
}); });
it('collapses if in commit view but there are no changes and vice versa', async () => {
store.state.currentActivityView = leftSidebarViews.commit.name;
await vm.$nextTick();
// expanded by default if there are changes
expect(vm.isCompact).toBe(false);
store.state.changedFiles = [];
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.changedFiles.push('test');
await vm.$nextTick();
// uncollapsed once again
expect(vm.isCompact).toBe(false);
});
it('collapses if switched from commit view to edit view and vice versa', async () => {
store.state.currentActivityView = leftSidebarViews.edit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.currentActivityView = leftSidebarViews.commit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(false);
store.state.currentActivityView = leftSidebarViews.edit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
});
describe('when window height is less than MAX_WINDOW_HEIGHT', () => {
let oldHeight;
beforeEach(() => {
oldHeight = window.innerHeight;
window.innerHeight = 700;
});
afterEach(() => {
window.innerHeight = oldHeight;
});
it('stays collapsed when switching from edit view to commit view and back', async () => {
store.state.currentActivityView = leftSidebarViews.edit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.currentActivityView = leftSidebarViews.commit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.currentActivityView = leftSidebarViews.edit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
});
it('stays uncollapsed if changes are added or removed', async () => {
store.state.currentActivityView = leftSidebarViews.commit.name;
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.changedFiles = [];
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
store.state.changedFiles.push('test');
await vm.$nextTick();
expect(vm.isCompact).toBe(true);
});
it('uncollapses when clicked on Commit button in the edit view', async () => {
store.state.currentActivityView = leftSidebarViews.edit.name;
beginCommitButton().click();
await waitForPromises();
expect(vm.isCompact).toBe(false);
});
});
}); });
describe('full', () => { describe('full', () => {
...@@ -113,7 +214,7 @@ describe('IDE commit form', () => { ...@@ -113,7 +214,7 @@ describe('IDE commit form', () => {
}); });
it('always opens itself in full view current activity view is not commit view when clicking commit button', () => { it('always opens itself in full view current activity view is not commit view when clicking commit button', () => {
vm.$el.querySelector('.btn-primary').click(); beginCommitButton().click();
return vm.$nextTick(() => { return vm.$nextTick(() => {
expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name); expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
......
...@@ -123,6 +123,28 @@ describe('RepoCommitSection', () => { ...@@ -123,6 +123,28 @@ describe('RepoCommitSection', () => {
}); });
}); });
describe('if nothing is changed or staged', () => {
beforeEach(() => {
setupDefaultState();
store.state.openFiles = [...Object.values(store.state.entries)];
store.state.openFiles[0].active = true;
store.state.stagedFiles = [];
createComponent();
});
it('opens currently active file', () => {
expect(store.state.openFiles.length).toBe(1);
expect(store.state.openFiles[0].pending).toBe(true);
expect(store.dispatch).toHaveBeenCalledWith('openPendingTab', {
file: store.state.entries[store.getters.activeFile.path],
keyPrefix: stageKeys.unstaged,
});
});
});
describe('with unstaged file', () => { describe('with unstaged file', () => {
beforeEach(() => { beforeEach(() => {
setupDefaultState(); setupDefaultState();
......
...@@ -81,9 +81,9 @@ describe('Multi-file editor library', () => { ...@@ -81,9 +81,9 @@ describe('Multi-file editor library', () => {
quickSuggestions: false, quickSuggestions: false,
occurrencesHighlight: false, occurrencesHighlight: false,
renderSideBySide: false, renderSideBySide: false,
readOnly: true, readOnly: false,
renderLineHighlight: 'all', renderLineHighlight: 'none',
hideCursorInOverviewRuler: false, hideCursorInOverviewRuler: true,
}); });
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment