diff options
author | Phil Hughes <me@iamphill.com> | 2018-01-10 12:52:30 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2018-02-07 09:10:01 +0000 |
commit | f9be0a48e9292b0234be06ab9765e6d3b524db65 (patch) | |
tree | 1e616eb9cbd142c0a5f555269690c5b3a1e12dd2 | |
parent | 826105dfda91081e92dfd5ca7f85a1343893e049 (diff) | |
download | gitlab-ce-f9be0a48e9292b0234be06ab9765e6d3b524db65.tar.gz |
Added changed state to IDE
28 files changed, 361 insertions, 238 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue index 742f746e02f..6421f3b8681 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue @@ -1,4 +1,5 @@ <script> + import { mapActions } from 'vuex'; import icon from '../../../vue_shared/components/icon.vue'; export default { @@ -19,6 +20,11 @@ return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`; }, }, + methods: { + ...mapActions([ + 'discardFileChanges', + ]), + }, }; </script> @@ -32,5 +38,12 @@ <span class="multi-file-commit-list-path"> {{ file.path }} </span> + <button + type="button" + class="btn btn-blank multi-file-discard-btn" + @click="discardFileChanges(file)" + > + Discard + </button> </div> </template> diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 89981ab2c65..74ac4be5b3c 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -28,9 +28,9 @@ ...mapState([ 'currentBlobView', 'selectedFile', + 'changedFiles', ]), ...mapGetters([ - 'changedFiles', 'activeFile', ]), }, diff --git a/app/assets/javascripts/ide/components/ide_context_bar.vue b/app/assets/javascripts/ide/components/ide_context_bar.vue index dd947f66969..dd792ba87d7 100644 --- a/app/assets/javascripts/ide/components/ide_context_bar.vue +++ b/app/assets/javascripts/ide/components/ide_context_bar.vue @@ -1,5 +1,5 @@ <script> - import { mapGetters, mapState, mapActions } from 'vuex'; + import { mapState, mapActions } from 'vuex'; import repoCommitSection from './repo_commit_section.vue'; import icon from '../../vue_shared/components/icon.vue'; import panelResizer from '../../vue_shared/components/panel_resizer.vue'; @@ -18,8 +18,6 @@ computed: { ...mapState([ 'rightPanelCollapsed', - ]), - ...mapGetters([ 'changedFiles', ]), currentIcon() { diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue index 96b1bb78c1d..8cdd34857a9 100644 --- a/app/assets/javascripts/ide/components/repo_commit_section.vue +++ b/app/assets/javascripts/ide/components/repo_commit_section.vue @@ -1,5 +1,5 @@ <script> -import { mapGetters, mapState, mapActions } from 'vuex'; +import { mapState, mapActions } from 'vuex'; import tooltip from '../../vue_shared/directives/tooltip'; import icon from '../../vue_shared/components/icon.vue'; import modal from '../../vue_shared/components/modal.vue'; @@ -27,8 +27,6 @@ export default { 'currentProjectId', 'currentBranchId', 'rightPanelCollapsed', - ]), - ...mapGetters([ 'changedFiles', ]), commitButtonDisabled() { diff --git a/app/assets/javascripts/ide/components/repo_edit_button.vue b/app/assets/javascripts/ide/components/repo_edit_button.vue index c43e9163340..280da6efae1 100644 --- a/app/assets/javascripts/ide/components/repo_edit_button.vue +++ b/app/assets/javascripts/ide/components/repo_edit_button.vue @@ -9,7 +9,6 @@ export default { computed: { ...mapState([ 'editMode', - 'discardPopupOpen', ]), ...mapGetters([ 'canEditFile', @@ -21,7 +20,6 @@ export default { methods: { ...mapActions([ 'toggleEditMode', - 'closeDiscardPopup', ]), }, }; @@ -43,15 +41,5 @@ export default { {{ buttonLabel }} </span> </button> - <modal - v-if="discardPopupOpen" - class="text-left" - :primary-button-label="__('Discard changes')" - kind="warning" - :title="__('Are you sure?')" - :text="__('Are you sure you want to discard your changes?')" - @cancel="closeDiscardPopup" - @submit="toggleEditMode(true)" - /> </div> </template> diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index f99228012f4..8aeb64027b9 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -19,6 +19,9 @@ export default { shouldHideEditor() { return this.activeFile.binary && !this.activeFile.raw; }, + activeFileChanged() { + return this.activeFile && this.activeFile.changed; + }, }, watch: { activeFile(oldVal, newVal) { @@ -26,6 +29,13 @@ export default { this.initMonaco(); } }, + activeFileChanged(newVal) { + if (!this.editor) return; + + if (!newVal && this.model) { + this.model.setValue(this.model.getOriginalModel().getValue()); + } + }, leftPanelCollapsed() { this.editor.updateDimensions(); }, @@ -78,11 +88,11 @@ export default { setupEditor() { if (!this.activeFile) return; - const model = this.editor.createModel(this.activeFile); + this.model = this.editor.createModel(this.activeFile); - this.editor.attachModel(model); + this.editor.attachModel(this.model); - model.onChange((m) => { + this.model.onChange((m) => { this.changeFileContent({ file: this.activeFile, content: m.getValue(), @@ -104,12 +114,12 @@ export default { // Handle File Language this.setFileLanguage({ - fileLanguage: model.language, + fileLanguage: this.model.language, }); // Get File eol this.setFileEOL({ - eol: model.eol, + eol: this.model.eol, }); }, }, diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue index 5ed7bddf6ae..006987ffaf6 100644 --- a/app/assets/javascripts/ide/components/repo_tab.vue +++ b/app/assets/javascripts/ide/components/repo_tab.vue @@ -12,6 +12,11 @@ required: true, }, }, + data() { + return { + tabMouseOver: false, + }; + }, computed: { closeLabel() { if (this.tab.changed || this.tab.tempFile) { @@ -19,12 +24,8 @@ } return `Close ${this.tab.name}`; }, - changedClass() { - const tabChangedObj = { - 'fa-times close-icon': !this.tab.changed && !this.tab.tempFile, - 'fa-circle unsaved-icon': this.tab.changed || this.tab.tempFile, - }; - return tabChangedObj; + showChangedIcon() { + return this.tab.changed ? !this.tabMouseOver : false; }, }, @@ -35,25 +36,44 @@ clickFile(tab) { this.$router.push(`/project${tab.url}`); }, + mouseOverTab() { + if (this.tab.changed) { + this.tabMouseOver = true; + } + }, + mouseOutTab() { + if (this.tab.changed) { + this.tabMouseOver = false; + } + }, }, }; </script> <template> - <li @click="clickFile(tab)"> + <li + @click="clickFile(tab)" + @mouseover="mouseOverTab" + @mouseout="mouseOutTab" + > <button type="button" class="multi-file-tab-close" - @click.stop.prevent="closeFile({ file: tab })" + @click.stop.prevent="closeFile(tab)" :aria-label="closeLabel" :class="{ 'modified': tab.changed, }" - :disabled="tab.changed" > <i - class="fa" - :class="changedClass" + v-if="!showChangedIcon" + class="fa fa-times close-icon" + aria-hidden="true" + > + </i> + <i + v-else + class="fa fa-circle unsaved-icon" aria-hidden="true" > </i> diff --git a/app/assets/javascripts/ide/lib/common/model.js b/app/assets/javascripts/ide/lib/common/model.js index 14d9fe4771e..f4e1b14e258 100644 --- a/app/assets/javascripts/ide/lib/common/model.js +++ b/app/assets/javascripts/ide/lib/common/model.js @@ -48,6 +48,10 @@ export default class Model { return this.originalModel; } + setValue(value) { + this.getModel().setValue(value); + } + onChange(cb) { this.events.set( this.path, diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index d007d0ae78f..385349e8219 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -10,42 +10,23 @@ export const redirectToUrl = (_, url) => visitUrl(url); export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data); -export const closeDiscardPopup = ({ commit }) => - commit(types.TOGGLE_DISCARD_POPUP, false); - -export const discardAllChanges = ({ commit, getters, dispatch }) => { - const changedFiles = getters.changedFiles; - - changedFiles.forEach((file) => { +export const discardAllChanges = ({ state, commit, dispatch }) => { + state.changedFiles.forEach((file) => { commit(types.DISCARD_FILE_CHANGES, file); if (file.tempFile) { - dispatch('closeFile', { file, force: true }); + dispatch('closeFile', file); } }); }; export const closeAllFiles = ({ state, dispatch }) => { - state.openFiles.forEach(file => dispatch('closeFile', { file })); + state.openFiles.forEach(file => dispatch('closeFile', file)); }; -export const toggleEditMode = ( - { state, commit, getters, dispatch }, - force = false, -) => { - const changedFiles = getters.changedFiles; - - if (changedFiles.length && !force) { - commit(types.TOGGLE_DISCARD_POPUP, true); - } else { - commit(types.TOGGLE_EDIT_MODE); - commit(types.TOGGLE_DISCARD_POPUP, false); - dispatch('toggleBlobView'); - - if (!state.editMode) { - dispatch('discardAllChanges'); - } - } +export const toggleEditMode = ({ commit, dispatch }) => { + commit(types.TOGGLE_EDIT_MODE); + dispatch('toggleBlobView'); }; export const toggleBlobView = ({ commit, state }) => { @@ -85,7 +66,7 @@ export const checkCommitStatus = ({ state }) => .catch(() => flash('Error checking branch data. Please try again.', 'alert', document, null, false, true)); export const commitChanges = ( - { commit, state, dispatch, getters }, + { commit, state, dispatch }, { payload, newMr }, ) => service @@ -133,7 +114,7 @@ export const commitChanges = ( reference: data.id, }); - getters.changedFiles.forEach((entry) => { + state.changedFiles.forEach((entry) => { commit(types.SET_LAST_COMMIT_DATA, { entry, lastCommit, diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index 670af2fb89e..d1b3a6ce374 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -10,9 +10,7 @@ import { findIndexOfFile, } from '../utils'; -export const closeFile = ({ commit, state, dispatch }, { file, force = false }) => { - if ((file.changed || file.tempFile) && !force) return; - +export const closeFile = ({ commit, state, dispatch }, file) => { const indexOfClosedFile = findIndexOfFile(state.openFiles, file); const fileWasActive = file.active; @@ -79,8 +77,16 @@ export const getRawFileData = ({ commit, dispatch }, file) => service.getRawFile }) .catch(() => flash('Error loading file content. Please try again.', 'alert', document, null, false, true)); -export const changeFileContent = ({ commit }, { file, content }) => { +export const changeFileContent = ({ state, commit }, { file, content }) => { commit(types.UPDATE_FILE_CONTENT, { file, content }); + + const indexOfChangedFile = findIndexOfFile(state.changedFiles, file); + + if (file.changed && indexOfChangedFile === -1) { + commit(types.ADD_FILE_TO_CHANGED, file); + } else if (!file.changed && indexOfChangedFile !== -1) { + commit(types.REMOVE_FILE_FROM_CHANGED, file); + } }; export const setFileLanguage = ({ state, commit }, { fileLanguage }) => { @@ -125,6 +131,7 @@ export const createTempFile = ({ state, commit, dispatch }, { projectId, branchI file, }); commit(types.TOGGLE_FILE_OPEN, file); + commit(types.ADD_FILE_TO_CHANGED, file); dispatch('setFileActive', file); if (!state.editMode && !file.base64) { @@ -135,3 +142,12 @@ export const createTempFile = ({ state, commit, dispatch }, { projectId, branchI return Promise.resolve(file); }; + +export const discardFileChanges = ({ commit }, file) => { + commit(types.DISCARD_FILE_CHANGES, file); + commit(types.REMOVE_FILE_FROM_CHANGED, file); + + if (file.tempFile && file.opened) { + commit(types.TOGGLE_FILE_OPEN, file); + } +}; diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index 6b51ccff817..4073aafe979 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -1,4 +1,4 @@ -export const changedFiles = state => state.openFiles.filter(file => file.changed); +export const changedFiles = state => state.changedFiles; export const activeFile = state => state.openFiles.find(file => file.active) || null; diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 69b218a5e7d..ea38084fd3c 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -35,12 +35,12 @@ export const SET_FILE_POSITION = 'SET_FILE_POSITION'; export const SET_FILE_EOL = 'SET_FILE_EOL'; export const DISCARD_FILE_CHANGES = 'DISCARD_FILE_CHANGES'; export const CREATE_TMP_FILE = 'CREATE_TMP_FILE'; +export const ADD_FILE_TO_CHANGED = 'ADD_FILE_TO_CHANGED'; +export const REMOVE_FILE_FROM_CHANGED = 'REMOVE_FILE_FROM_CHANGED'; // Viewer mutation types export const SET_PREVIEW_MODE = 'SET_PREVIEW_MODE'; export const SET_EDIT_MODE = 'SET_EDIT_MODE'; export const TOGGLE_EDIT_MODE = 'TOGGLE_EDIT_MODE'; -export const TOGGLE_DISCARD_POPUP = 'TOGGLE_DISCARD_POPUP'; export const SET_CURRENT_BRANCH = 'SET_CURRENT_BRANCH'; - diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 03d81be10a1..22b0086af79 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -28,11 +28,6 @@ export default { editMode: !state.editMode, }); }, - [types.TOGGLE_DISCARD_POPUP](state, discardPopupOpen) { - Object.assign(state, { - discardPopupOpen, - }); - }, [types.SET_ROOT](state, isRoot) { Object.assign(state, { isRoot, diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js index 72db1c180c9..5c10c8f624e 100644 --- a/app/assets/javascripts/ide/stores/mutations/file.js +++ b/app/assets/javascripts/ide/stores/mutations/file.js @@ -71,4 +71,12 @@ export default { [types.CREATE_TMP_FILE](state, { file, parent }) { parent.tree.push(file); }, + [types.ADD_FILE_TO_CHANGED](state, file) { + state.changedFiles.push(file); + }, + [types.REMOVE_FILE_FROM_CHANGED](state, file) { + const indexOfChangedFile = findIndexOfFile(state.changedFiles, file); + + state.changedFiles.splice(indexOfChangedFile, 1); + }, }; diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 61d12096946..d9c49ec81e3 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -3,7 +3,7 @@ export default () => ({ currentProjectId: '', currentBranchId: '', currentBlobView: 'repo-editor', - discardPopupOpen: false, + changedFiles: [], editMode: true, endpoints: {}, isRoot: false, diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 8265b8370f7..4eb8b21404b 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -395,7 +395,24 @@ table.table tr td.multi-file-table-name { .multi-file-commit-list-item { display: flex; + margin-bottom: $grid-size; align-items: center; + + > svg { + min-width: 16px; + } + + .multi-file-discard-btn { + display: none; + margin-left: auto; + color: $gl-link-color; + } + + &:hover { + .multi-file-discard-btn { + display: block; + } + } } .multi-file-addition { diff --git a/spec/javascripts/repo/components/commit_sidebar/list_collapsed_spec.js b/spec/javascripts/repo/components/commit_sidebar/list_collapsed_spec.js index debde1bb357..357ab6010ea 100644 --- a/spec/javascripts/repo/components/commit_sidebar/list_collapsed_spec.js +++ b/spec/javascripts/repo/components/commit_sidebar/list_collapsed_spec.js @@ -12,13 +12,8 @@ describe('Multi-file editor commit sidebar list collapsed', () => { vm = createComponentWithStore(Component, store); - vm.$store.state.openFiles.push(file('file1'), file('file2')); - vm.$store.state.openFiles[0].tempFile = true; - vm.$store.state.openFiles.forEach((f) => { - Object.assign(f, { - changed: true, - }); - }); + vm.$store.state.changedFiles.push(file('file1'), file('file2')); + vm.$store.state.changedFiles[0].tempFile = true; vm.$mount(); }); diff --git a/spec/javascripts/repo/components/commit_sidebar/list_item_spec.js b/spec/javascripts/repo/components/commit_sidebar/list_item_spec.js index 4b20fdf70d6..5a17e3a10a9 100644 --- a/spec/javascripts/repo/components/commit_sidebar/list_item_spec.js +++ b/spec/javascripts/repo/components/commit_sidebar/list_item_spec.js @@ -25,6 +25,14 @@ describe('Multi-file editor commit sidebar list item', () => { expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent.trim()).toBe(f.path); }); + it('calls discardFileChanges when clicking discard button', () => { + spyOn(vm, 'discardFileChanges'); + + vm.$el.querySelector('.multi-file-discard-btn').click(); + + expect(vm.discardFileChanges).toHaveBeenCalled(); + }); + describe('computed', () => { describe('iconName', () => { it('returns modified when not a tempFile', () => { diff --git a/spec/javascripts/repo/components/repo_commit_section_spec.js b/spec/javascripts/repo/components/repo_commit_section_spec.js index 93e94b4f24c..0a1b8259009 100644 --- a/spec/javascripts/repo/components/repo_commit_section_spec.js +++ b/spec/javascripts/repo/components/repo_commit_section_spec.js @@ -29,8 +29,8 @@ describe('RepoCommitSection', () => { comp.$store.state.rightPanelCollapsed = false; comp.$store.state.currentBranch = 'master'; - comp.$store.state.openFiles = [file('file1'), file('file2')]; - comp.$store.state.openFiles.forEach(f => Object.assign(f, { + comp.$store.state.changedFiles = [file('file1'), file('file2')]; + comp.$store.state.changedFiles.forEach(f => Object.assign(f, { changed: true, content: 'testing', })); @@ -72,7 +72,7 @@ describe('RepoCommitSection', () => { expect(changedFileElements.length).toEqual(2); changedFileElements.forEach((changedFile, i) => { - expect(changedFile.textContent.trim()).toEqual(vm.$store.getters.changedFiles[i].path); + expect(changedFile.textContent.trim()).toEqual(vm.$store.state.changedFiles[i].path); }); expect(submitCommit.disabled).toBeTruthy(); @@ -84,7 +84,7 @@ describe('RepoCommitSection', () => { beforeEach(() => { vm.commitMessage = 'testing'; - changedFiles = JSON.parse(JSON.stringify(vm.$store.getters.changedFiles)); + changedFiles = JSON.parse(JSON.stringify(vm.$store.state.changedFiles)); spyOn(service, 'commit').and.returnValue(Promise.resolve({ data: { diff --git a/spec/javascripts/repo/components/repo_edit_button_spec.js b/spec/javascripts/repo/components/repo_edit_button_spec.js index 2895b794506..7979765c2a3 100644 --- a/spec/javascripts/repo/components/repo_edit_button_spec.js +++ b/spec/javascripts/repo/components/repo_edit_button_spec.js @@ -55,29 +55,4 @@ describe('RepoEditButton', () => { done(); }); }); - - describe('discardPopupOpen', () => { - beforeEach(() => { - vm.$store.state.discardPopupOpen = true; - vm.$store.state.editMode = true; - vm.$store.state.openFiles[0].changed = true; - - vm.$mount(); - }); - - it('renders popup', () => { - expect(vm.$el.querySelector('.modal')).not.toBeNull(); - }); - - it('removes all changed files', (done) => { - vm.$el.querySelector('.btn-warning').click(); - - vm.$nextTick(() => { - expect(vm.$store.getters.changedFiles.length).toBe(0); - expect(vm.$el.querySelector('.modal')).toBeNull(); - - done(); - }); - }); - }); }); diff --git a/spec/javascripts/repo/components/repo_editor_spec.js b/spec/javascripts/repo/components/repo_editor_spec.js index e7b2ed08acd..6d47fecacc9 100644 --- a/spec/javascripts/repo/components/repo_editor_spec.js +++ b/spec/javascripts/repo/components/repo_editor_spec.js @@ -57,4 +57,18 @@ describe('RepoEditor', () => { expect(vm.$el.textContent).toContain('testing'); }); }); + + describe('computed', () => { + describe('activeFileChanged', () => { + it('returns false when file has no changes', () => { + expect(vm.activeFileChanged).toBeFalsy(); + }); + + it('returns true when file has changes', () => { + vm.$store.getters.activeFile.changed = true; + + expect(vm.activeFileChanged).toBeTruthy(); + }); + }); + }); }); diff --git a/spec/javascripts/repo/components/repo_tab_spec.js b/spec/javascripts/repo/components/repo_tab_spec.js index 933e8d3a06a..866c7eb83c2 100644 --- a/spec/javascripts/repo/components/repo_tab_spec.js +++ b/spec/javascripts/repo/components/repo_tab_spec.js @@ -52,7 +52,7 @@ describe('RepoTab', () => { vm.$el.querySelector('.multi-file-tab-close').click(); - expect(vm.closeFile).toHaveBeenCalledWith({ file: vm.tab }); + expect(vm.closeFile).toHaveBeenCalledWith(vm.tab); }); it('renders an fa-circle icon if tab is changed', () => { @@ -65,22 +65,50 @@ describe('RepoTab', () => { expect(vm.$el.querySelector('.multi-file-tab-close .fa-circle')).not.toBeNull(); }); + it('changes icon on hover', (done) => { + const tab = file(); + tab.changed = true; + vm = createComponent({ + tab, + }); + + vm.$el.dispatchEvent(new Event('mouseover')); + + Vue.nextTick() + .then(() => { + expect(vm.$el.querySelector('.unsaved-icon')).toBeNull(); + expect(vm.$el.querySelector('.close-icon')).not.toBeNull(); + + vm.$el.dispatchEvent(new Event('mouseout')); + }) + .then(Vue.nextTick) + .then(() => { + expect(vm.$el.querySelector('.close-icon')).toBeNull(); + expect(vm.$el.querySelector('.unsaved-icon')).not.toBeNull(); + + done(); + }) + .catch(done.fail); + }); + describe('methods', () => { describe('closeTab', () => { - it('does not close tab if is changed', (done) => { - const tab = file('closeFile'); + it('closes tab if file has changed', (done) => { + const tab = file(); tab.changed = true; tab.opened = true; vm = createComponent({ tab, }); vm.$store.state.openFiles.push(tab); + vm.$store.state.changedFiles.push(tab); vm.$store.dispatch('setFileActive', tab); vm.$el.querySelector('.multi-file-tab-close').click(); vm.$nextTick(() => { - expect(tab.opened).toBeTruthy(); + expect(tab.opened).toBeFalsy(); + expect(vm.$store.state.changedFiles.length).toBe(1); done(); }); diff --git a/spec/javascripts/repo/lib/common/model_spec.js b/spec/javascripts/repo/lib/common/model_spec.js index 878a4a3f3fe..9f23b9a435d 100644 --- a/spec/javascripts/repo/lib/common/model_spec.js +++ b/spec/javascripts/repo/lib/common/model_spec.js @@ -41,6 +41,14 @@ describe('Multi-file editor library model', () => { }); }); + describe('setValue', () => { + it('updates models value', () => { + model.setValue('testing 123'); + + expect(model.getModel().getValue()).toBe('testing 123'); + }); + }); + describe('onChange', () => { it('caches event by path', () => { model.onChange(() => {}); diff --git a/spec/javascripts/repo/stores/actions/file_spec.js b/spec/javascripts/repo/stores/actions/file_spec.js index e2d8f002e27..419844bb5b4 100644 --- a/spec/javascripts/repo/stores/actions/file_spec.js +++ b/spec/javascripts/repo/stores/actions/file_spec.js @@ -31,7 +31,7 @@ describe('Multi-file store file actions', () => { }); it('closes open files', (done) => { - store.dispatch('closeFile', { file: localFile }) + store.dispatch('closeFile', localFile) .then(() => { expect(localFile.opened).toBeFalsy(); expect(localFile.active).toBeFalsy(); @@ -41,43 +41,18 @@ describe('Multi-file store file actions', () => { }).catch(done.fail); }); - it('does not close file if has changed', (done) => { - localFile.changed = true; + it('closes file even if file has changes', (done) => { + store.state.changedFiles.push(localFile); - store.dispatch('closeFile', { file: localFile }) - .then(() => { - expect(localFile.opened).toBeTruthy(); - expect(localFile.active).toBeTruthy(); - expect(store.state.openFiles.length).toBe(1); - - done(); - }).catch(done.fail); - }); - - it('does not close file if temp file', (done) => { - localFile.tempFile = true; - - store.dispatch('closeFile', { file: localFile }) - .then(() => { - expect(localFile.opened).toBeTruthy(); - expect(localFile.active).toBeTruthy(); - expect(store.state.openFiles.length).toBe(1); - - done(); - }).catch(done.fail); - }); - - it('force closes a changed file', (done) => { - localFile.changed = true; - - store.dispatch('closeFile', { file: localFile, force: true }) + store.dispatch('closeFile', localFile) + .then(Vue.nextTick) .then(() => { - expect(localFile.opened).toBeFalsy(); - expect(localFile.active).toBeFalsy(); expect(store.state.openFiles.length).toBe(0); + expect(store.state.changedFiles.length).toBe(1); done(); - }).catch(done.fail); + }) + .catch(done.fail); }); it('sets next file as active', (done) => { @@ -86,7 +61,7 @@ describe('Multi-file store file actions', () => { expect(f.active).toBeFalsy(); - store.dispatch('closeFile', { file: localFile }) + store.dispatch('closeFile', localFile) .then(() => { expect(f.active).toBeTruthy(); @@ -95,7 +70,7 @@ describe('Multi-file store file actions', () => { }); it('calls getLastCommitData', (done) => { - store.dispatch('closeFile', { file: localFile }) + store.dispatch('closeFile', localFile) .then(() => { expect(getLastCommitDataSpy).toHaveBeenCalled(); @@ -315,6 +290,50 @@ describe('Multi-file store file actions', () => { done(); }).catch(done.fail); }); + + it('adds file into changedFiles array', (done) => { + store.dispatch('changeFileContent', { + file: tmpFile, + content: 'content', + }) + .then(() => { + expect(store.state.changedFiles.length).toBe(1); + + done(); + }).catch(done.fail); + }); + + it('adds file once into changedFiles array', (done) => { + store.dispatch('changeFileContent', { + file: tmpFile, + content: 'content', + }) + .then(() => store.dispatch('changeFileContent', { + file: tmpFile, + content: 'content 123', + })) + .then(() => { + expect(store.state.changedFiles.length).toBe(1); + + done(); + }).catch(done.fail); + }); + + it('removes file from changedFiles array if not changed', (done) => { + store.dispatch('changeFileContent', { + file: tmpFile, + content: 'content', + }) + .then(() => store.dispatch('changeFileContent', { + file: tmpFile, + content: '', + })) + .then(() => { + expect(store.state.changedFiles.length).toBe(0); + + done(); + }).catch(done.fail); + }); }); describe('createTempFile', () => { @@ -372,6 +391,20 @@ describe('Multi-file store file actions', () => { }).catch(done.fail); }); + it('adds tmp file to changed files', (done) => { + store.dispatch('createTempFile', { + name: 'test', + projectId: 'abcproject', + branchId: 'mybranch', + parent: projectTree, + }).then((f) => { + expect(store.state.changedFiles.length).toBe(1); + expect(store.state.changedFiles[0].name).toBe(f.name); + + done(); + }).catch(done.fail); + }); + it('sets tmp file as active', (done) => { store.dispatch('createTempFile', { name: 'test', @@ -428,4 +461,62 @@ describe('Multi-file store file actions', () => { }).catch(done.fail); }); }); + + describe('discardFileChanges', () => { + let tmpFile; + + beforeEach(() => { + tmpFile = file(); + tmpFile.content = 'testing'; + + store.state.changedFiles.push(tmpFile); + }); + + it('resets file content', (done) => { + store.dispatch('discardFileChanges', tmpFile) + .then(() => { + expect(tmpFile.content).not.toBe('testing'); + + done(); + }) + .catch(done.fail); + }); + + it('removes file from changedFiles array', (done) => { + store.dispatch('discardFileChanges', tmpFile) + .then(() => { + expect(store.state.changedFiles.length).toBe(0); + + done(); + }) + .catch(done.fail); + }); + + it('closes temp file', (done) => { + tmpFile.tempFile = true; + tmpFile.opened = true; + + store.dispatch('discardFileChanges', tmpFile) + .then(() => { + expect(tmpFile.opened).toBeFalsy(); + + done(); + }) + .catch(done.fail); + }); + + it('does not re-open a closed temp file', (done) => { + tmpFile.tempFile = true; + + expect(tmpFile.opened).toBeFalsy(); + + store.dispatch('discardFileChanges', tmpFile) + .then(() => { + expect(tmpFile.opened).toBeFalsy(); + + done(); + }) + .catch(done.fail); + }); + }); }); diff --git a/spec/javascripts/repo/stores/actions_spec.js b/spec/javascripts/repo/stores/actions_spec.js index f678967b092..bae84960d8d 100644 --- a/spec/javascripts/repo/stores/actions_spec.js +++ b/spec/javascripts/repo/stores/actions_spec.js @@ -34,18 +34,6 @@ describe('Multi-file store actions', () => { }); }); - describe('closeDiscardPopup', () => { - it('closes the discard popup', (done) => { - store.dispatch('closeDiscardPopup', false) - .then(() => { - expect(store.state.discardPopupOpen).toBeFalsy(); - - done(); - }) - .catch(done.fail); - }); - }); - describe('discardAllChanges', () => { beforeEach(() => { store.state.openFiles.push(file('discardAll')); @@ -94,49 +82,6 @@ describe('Multi-file store actions', () => { done(); }).catch(done.fail); }); - - it('opens discard popup if there are changed files', (done) => { - store.state.editMode = true; - store.state.openFiles.push(file('discardChanges')); - store.state.openFiles[0].changed = true; - - store.dispatch('toggleEditMode') - .then(() => { - expect(store.state.discardPopupOpen).toBeTruthy(); - - done(); - }).catch(done.fail); - }); - - it('can force closed if there are changed files', (done) => { - store.state.editMode = true; - - store.state.openFiles.push(file('forceClose')); - store.state.openFiles[0].changed = true; - - store.dispatch('toggleEditMode', true) - .then(() => { - expect(store.state.discardPopupOpen).toBeFalsy(); - expect(store.state.editMode).toBeFalsy(); - - done(); - }).catch(done.fail); - }); - - it('discards file changes', (done) => { - const f = file('discard'); - store.state.editMode = true; - store.state.openFiles.push(f); - f.changed = true; - - store.dispatch('toggleEditMode', true) - .then(Vue.nextTick) - .then(() => { - expect(f.changed).toBeFalsy(); - - done(); - }).catch(done.fail); - }); }); describe('toggleBlobView', () => { @@ -293,16 +238,19 @@ describe('Multi-file store actions', () => { }); it('adds commit data to changed files', (done) => { +<<<<<<< HEAD const changedFile = file('changed'); const f = file('newfile'); changedFile.changed = true; +======= + const changedFile = file(); +>>>>>>> Added changed state to IDE - store.state.openFiles.push(changedFile, f); + store.state.changedFiles.push(changedFile); store.dispatch('commitChanges', { payload, newMr: false }) .then(() => { expect(changedFile.lastCommit.message).toBe('test message'); - expect(f.lastCommit.message).not.toBe('test message'); done(); }).catch(done.fail); diff --git a/spec/javascripts/repo/stores/getters_spec.js b/spec/javascripts/repo/stores/getters_spec.js index d0d5934f29a..5f78b99d7b1 100644 --- a/spec/javascripts/repo/stores/getters_spec.js +++ b/spec/javascripts/repo/stores/getters_spec.js @@ -9,19 +9,6 @@ describe('Multi-file store getters', () => { localState = state(); }); - describe('changedFiles', () => { - it('returns a list of changed opened files', () => { - localState.openFiles.push(file()); - localState.openFiles.push(file('changed')); - localState.openFiles[1].changed = true; - - const changedFiles = getters.changedFiles(localState); - - expect(changedFiles.length).toBe(1); - expect(changedFiles[0].name).toBe('changed'); - }); - }); - describe('activeFile', () => { it('returns the current active file', () => { localState.openFiles.push(file()); @@ -88,8 +75,8 @@ describe('Multi-file store getters', () => { describe('modifiedFiles', () => { it('returns a list of modified files', () => { localState.openFiles.push(file()); - localState.openFiles.push(file('changed')); - localState.openFiles[1].changed = true; + localState.changedFiles.push(file('changed')); + localState.changedFiles[0].changed = true; const modifiedFiles = getters.modifiedFiles(localState); @@ -101,9 +88,9 @@ describe('Multi-file store getters', () => { describe('addedFiles', () => { it('returns a list of added files', () => { localState.openFiles.push(file()); - localState.openFiles.push(file('added')); - localState.openFiles[1].changed = true; - localState.openFiles[1].tempFile = true; + localState.changedFiles.push(file('added')); + localState.changedFiles[0].changed = true; + localState.changedFiles[0].tempFile = true; const modifiedFiles = getters.addedFiles(localState); diff --git a/spec/javascripts/repo/stores/mutations/file_spec.js b/spec/javascripts/repo/stores/mutations/file_spec.js index 6e204ef0404..b908153dfa9 100644 --- a/spec/javascripts/repo/stores/mutations/file_spec.js +++ b/spec/javascripts/repo/stores/mutations/file_spec.js @@ -99,6 +99,17 @@ describe('Multi-file store file mutations', () => { expect(localFile.content).toBe('testing'); expect(localFile.changed).toBeTruthy(); }); + + it('sets changed if file is a temp file', () => { + localFile.tempFile = true; + + mutations.UPDATE_FILE_CONTENT(localState, { + file: localFile, + content: '', + }); + + expect(localFile.changed).toBeTruthy(); + }); }); describe('DISCARD_FILE_CHANGES', () => { @@ -128,4 +139,26 @@ describe('Multi-file store file mutations', () => { expect(localFile.tree[0].name).toBe(f.name); }); }); + + describe('ADD_FILE_TO_CHANGED', () => { + it('adds file into changed files array', () => { + const f = file(); + + mutations.ADD_FILE_TO_CHANGED(localState, f); + + expect(localState.changedFiles.length).toBe(1); + }); + }); + + describe('REMOVE_FILE_FROM_CHANGED', () => { + it('removes files from changed files array', () => { + const f = file(); + + localState.changedFiles.push(f); + + mutations.REMOVE_FILE_FROM_CHANGED(localState, f); + + expect(localState.changedFiles.length).toBe(0); + }); + }); }); diff --git a/spec/javascripts/repo/stores/mutations_spec.js b/spec/javascripts/repo/stores/mutations_spec.js index 5fd8ad94972..bed97415187 100644 --- a/spec/javascripts/repo/stores/mutations_spec.js +++ b/spec/javascripts/repo/stores/mutations_spec.js @@ -73,18 +73,6 @@ describe('Multi-file store mutations', () => { }); }); - describe('TOGGLE_DISCARD_POPUP', () => { - it('sets discardPopupOpen', () => { - mutations.TOGGLE_DISCARD_POPUP(localState, true); - - expect(localState.discardPopupOpen).toBeTruthy(); - - mutations.TOGGLE_DISCARD_POPUP(localState, false); - - expect(localState.discardPopupOpen).toBeFalsy(); - }); - }); - describe('SET_ROOT', () => { it('sets isRoot & initialRoot', () => { mutations.SET_ROOT(localState, true); |