diff options
Diffstat (limited to 'app/assets')
-rw-r--r-- | app/assets/javascripts/ide/components/commit_sidebar/list_item.vue | 56 | ||||
-rw-r--r-- | app/assets/javascripts/ide/components/ide.vue | 86 | ||||
-rw-r--r-- | app/assets/javascripts/ide/components/repo_tab.vue | 103 | ||||
-rw-r--r-- | app/assets/javascripts/ide/components/repo_tabs.vue | 67 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/actions.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/actions/file.js | 56 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/getters.js | 8 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/mutation_types.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/mutations/file.js | 14 | ||||
-rw-r--r-- | app/assets/javascripts/ide/stores/state.js | 1 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/repo.scss | 8 |
11 files changed, 209 insertions, 203 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 18934af004a..e443bd4e3fa 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue @@ -1,38 +1,36 @@ <script> - import { mapActions } from 'vuex'; - import icon from '~/vue_shared/components/icon.vue'; - import router from '../../ide_router'; +import { mapActions } from 'vuex'; +import icon from '~/vue_shared/components/icon.vue'; +import router from '../../ide_router'; - export default { - components: { - icon, +export default { + components: { + icon, + }, + props: { + file: { + type: Object, + required: true, }, - props: { - file: { - type: Object, - required: true, - }, + }, + computed: { + iconName() { + return this.file.tempFile ? 'file-addition' : 'file-modified'; }, - computed: { - iconName() { - return this.file.tempFile ? 'file-addition' : 'file-modified'; - }, - iconClass() { - return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`; - }, + iconClass() { + return `multi-file-${this.file.tempFile ? 'addition' : 'modified'} append-right-8`; }, - methods: { - ...mapActions([ - 'discardFileChanges', - 'updateViewer', - ]), - openFileInEditor(file) { - this.updateViewer('diff'); - - router.push(`/project${file.url}`); - }, + }, + methods: { + ...mapActions(['discardFileChanges', 'updateViewer', 'openPendingTab']), + openFileInEditor(file) { + return this.updateViewer('diff').then(() => { + this.openPendingTab(file); + router.push(`/project/${file.projectId}/tree/master/`); + }); }, - }; + }, +}; </script> <template> diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 015e750525a..7048f5fab43 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -1,51 +1,51 @@ <script> - import { mapState, mapGetters } from 'vuex'; - import ideSidebar from './ide_side_bar.vue'; - import ideContextbar from './ide_context_bar.vue'; - import repoTabs from './repo_tabs.vue'; - import repoFileButtons from './repo_file_buttons.vue'; - import ideStatusBar from './ide_status_bar.vue'; - import repoEditor from './repo_editor.vue'; +import { mapState, mapGetters } from 'vuex'; +import ideSidebar from './ide_side_bar.vue'; +import ideContextbar from './ide_context_bar.vue'; +import repoTabs from './repo_tabs.vue'; +import repoFileButtons from './repo_file_buttons.vue'; +import ideStatusBar from './ide_status_bar.vue'; +import repoEditor from './repo_editor.vue'; - export default { - components: { - ideSidebar, - ideContextbar, - repoTabs, - repoFileButtons, - ideStatusBar, - repoEditor, +export default { + components: { + ideSidebar, + ideContextbar, + repoTabs, + repoFileButtons, + ideStatusBar, + repoEditor, + }, + props: { + emptyStateSvgPath: { + type: String, + required: true, }, - props: { - emptyStateSvgPath: { - type: String, - required: true, - }, - noChangesStateSvgPath: { - type: String, - required: true, - }, - committedStateSvgPath: { - type: String, - required: true, - }, + noChangesStateSvgPath: { + type: String, + required: true, }, - computed: { - ...mapState(['changedFiles', 'openFiles', 'viewer']), - ...mapGetters(['activeFile', 'hasChanges']), + committedStateSvgPath: { + type: String, + required: true, }, - mounted() { - const returnValue = 'Are you sure you want to lose unsaved changes?'; - window.onbeforeunload = e => { - if (!this.changedFiles.length) return undefined; + }, + computed: { + ...mapState(['changedFiles', 'openFiles', 'viewer']), + ...mapGetters(['activeFile', 'hasChanges', 'tabs']), + }, + mounted() { + const returnValue = 'Are you sure you want to lose unsaved changes?'; + window.onbeforeunload = e => { + if (!this.changedFiles.length) return undefined; - Object.assign(e, { - returnValue, - }); - return returnValue; - }; - }, - }; + Object.assign(e, { + returnValue, + }); + return returnValue; + }; + }, +}; </script> <template> @@ -60,7 +60,7 @@ v-if="activeFile" > <repo-tabs - :files="openFiles" + :files="tabs" :viewer="viewer" :has-changes="hasChanges" /> diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue index c337bc813e6..b36fb6b4830 100644 --- a/app/assets/javascripts/ide/components/repo_tab.vue +++ b/app/assets/javascripts/ide/components/repo_tab.vue @@ -1,60 +1,58 @@ <script> - import { mapActions } from 'vuex'; +import { mapActions } from 'vuex'; - import fileIcon from '~/vue_shared/components/file_icon.vue'; - import icon from '~/vue_shared/components/icon.vue'; - import fileStatusIcon from './repo_file_status_icon.vue'; - import changedFileIcon from './changed_file_icon.vue'; +import fileIcon from '~/vue_shared/components/file_icon.vue'; +import icon from '~/vue_shared/components/icon.vue'; +import fileStatusIcon from './repo_file_status_icon.vue'; +import changedFileIcon from './changed_file_icon.vue'; - export default { - components: { - fileStatusIcon, - fileIcon, - icon, - changedFileIcon, +export default { + components: { + fileStatusIcon, + fileIcon, + icon, + changedFileIcon, + }, + props: { + tab: { + type: Object, + required: true, }, - props: { - tab: { - type: Object, - required: true, - }, + }, + data() { + return { + tabMouseOver: false, + }; + }, + computed: { + closeLabel() { + if (this.tab.changed || this.tab.tempFile) { + return `${this.tab.name} changed`; + } + return `Close ${this.tab.name}`; }, - data() { - return { - tabMouseOver: false, - }; - }, - computed: { - closeLabel() { - if (this.tab.changed || this.tab.tempFile) { - return `${this.tab.name} changed`; - } - return `Close ${this.tab.name}`; - }, - showChangedIcon() { - return this.tab.changed ? !this.tabMouseOver : false; - }, + showChangedIcon() { + return this.tab.changed ? !this.tabMouseOver : false; }, + }, - methods: { - ...mapActions([ - 'closeFile', - ]), - clickFile(tab) { - this.$router.push(`/project${tab.url}`); - }, - mouseOverTab() { - if (this.tab.changed) { - this.tabMouseOver = true; - } - }, - mouseOutTab() { - if (this.tab.changed) { - this.tabMouseOver = false; - } - }, + methods: { + ...mapActions(['closeFile']), + 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> @@ -66,7 +64,7 @@ <button type="button" class="multi-file-tab-close" - @click.stop.prevent="closeFile(tab.path)" + @click.stop.prevent="closeFile(tab)" :aria-label="closeLabel" > <icon @@ -82,7 +80,10 @@ <div class="multi-file-tab" - :class="{active : tab.active }" + :class="{ + active: tab.active, + pending: tab.pending + }" :title="tab.url" > <file-icon diff --git a/app/assets/javascripts/ide/components/repo_tabs.vue b/app/assets/javascripts/ide/components/repo_tabs.vue index 8ea64ddf84a..dcb2ff80ce1 100644 --- a/app/assets/javascripts/ide/components/repo_tabs.vue +++ b/app/assets/javascripts/ide/components/repo_tabs.vue @@ -1,42 +1,41 @@ <script> - import { mapActions } from 'vuex'; - import RepoTab from './repo_tab.vue'; - import EditorMode from './editor_mode_dropdown.vue'; +import { mapActions } from 'vuex'; +import RepoTab from './repo_tab.vue'; +import EditorMode from './editor_mode_dropdown.vue'; - export default { - components: { - RepoTab, - EditorMode, +export default { + components: { + RepoTab, + EditorMode, + }, + props: { + files: { + type: Array, + required: true, }, - props: { - files: { - type: Array, - required: true, - }, - viewer: { - type: String, - required: true, - }, - hasChanges: { - type: Boolean, - required: true, - }, + viewer: { + type: String, + required: true, }, - data() { - return { - showShadow: false, - }; + hasChanges: { + type: Boolean, + required: true, }, - updated() { - if (!this.$refs.tabsScroller) return; + }, + data() { + return { + showShadow: false, + }; + }, + updated() { + if (!this.$refs.tabsScroller) return; - this.showShadow = - this.$refs.tabsScroller.scrollWidth > this.$refs.tabsScroller.offsetWidth; - }, - methods: { - ...mapActions(['updateViewer']), - }, - }; + this.showShadow = this.$refs.tabsScroller.scrollWidth > this.$refs.tabsScroller.offsetWidth; + }, + methods: { + ...mapActions(['updateViewer']), + }, +}; </script> <template> @@ -47,7 +46,7 @@ > <repo-tab v-for="tab in files" - :key="tab.key" + :key="`${tab.key}${tab.pending ? '-pending' : ''}`" :tab="tab" /> </ul> diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 7e920aa9f30..1300ea8e520 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -6,8 +6,7 @@ import FilesDecoratorWorker from './workers/files_decorator_worker'; export const redirectToUrl = (_, url) => visitUrl(url); -export const setInitialData = ({ commit }, data) => - commit(types.SET_INITIAL_DATA, data); +export const setInitialData = ({ commit }, data) => commit(types.SET_INITIAL_DATA, data); export const discardAllChanges = ({ state, commit, dispatch }) => { state.changedFiles.forEach(file => { @@ -43,14 +42,11 @@ export const createTempEntry = ( ) => new Promise(resolve => { const worker = new FilesDecoratorWorker(); - const fullName = - name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name; + const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name; if (state.entries[name]) { flash( - `The name "${name - .split('/') - .pop()}" is already taken in this directory.`, + `The name "${name.split('/').pop()}" is already taken in this directory.`, 'alert', document, null, diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js index ddc4b757bf9..5a39bfb02c4 100644 --- a/app/assets/javascripts/ide/stores/actions/file.js +++ b/app/assets/javascripts/ide/stores/actions/file.js @@ -6,21 +6,26 @@ import * as types from '../mutation_types'; import router from '../../ide_router'; import { setPageTitle } from '../utils'; -export const closeFile = ({ commit, state, getters, dispatch }, path) => { - const indexOfClosedFile = state.openFiles.findIndex(f => f.path === path); - const file = state.entries[path]; - const fileWasActive = file.active; +export const closeFile = ({ commit, state, getters, dispatch }, file) => { + const path = file.path; + + if (file.pending) { + commit(types.REMOVE_PENDING_TAB, file); + } else { + const indexOfClosedFile = state.openFiles.findIndex(f => f.path === path); + const fileWasActive = file.active; - commit(types.TOGGLE_FILE_OPEN, path); - commit(types.SET_FILE_ACTIVE, { path, active: false }); + commit(types.TOGGLE_FILE_OPEN, path); + commit(types.SET_FILE_ACTIVE, { path, active: false }); - if (state.openFiles.length > 0 && fileWasActive) { - const nextIndexToOpen = indexOfClosedFile === 0 ? 0 : indexOfClosedFile - 1; - const nextFileToOpen = state.entries[state.openFiles[nextIndexToOpen].path]; + if (state.openFiles.length > 0 && fileWasActive) { + const nextIndexToOpen = indexOfClosedFile === 0 ? 0 : indexOfClosedFile - 1; + const nextFileToOpen = state.entries[state.openFiles[nextIndexToOpen].path]; - router.push(`/project${nextFileToOpen.url}`); - } else if (!state.openFiles.length) { - router.push(`/project/${file.projectId}/tree/${file.branchId}/`); + router.push(`/project${nextFileToOpen.url}`); + } else if (!state.openFiles.length) { + router.push(`/project/${file.projectId}/tree/${file.branchId}/`); + } } eventHub.$emit(`editor.update.model.dispose.${file.path}`); @@ -66,14 +71,7 @@ export const getFileData = ({ state, commit, dispatch }, file) => { }) .catch(() => { commit(types.TOGGLE_LOADING, { entry: file }); - flash( - 'Error loading file data. Please try again.', - 'alert', - document, - null, - false, - true, - ); + flash('Error loading file data. Please try again.', 'alert', document, null, false, true); }); }; @@ -84,14 +82,7 @@ export const getRawFileData = ({ commit, dispatch }, file) => commit(types.SET_FILE_RAW_DATA, { file, raw }); }) .catch(() => - flash( - 'Error loading file content. Please try again.', - 'alert', - document, - null, - false, - true, - ), + flash('Error loading file content. Please try again.', 'alert', document, null, false, true), ); export const changeFileContent = ({ state, commit }, { path, content }) => { @@ -119,10 +110,7 @@ export const setFileEOL = ({ getters, commit }, { eol }) => { } }; -export const setEditorPosition = ( - { getters, commit }, - { editorRow, editorColumn }, -) => { +export const setEditorPosition = ({ getters, commit }, { editorRow, editorColumn }) => { if (getters.activeFile) { commit(types.SET_FILE_POSITION, { file: getters.activeFile, @@ -144,3 +132,7 @@ export const discardFileChanges = ({ state, commit }, path) => { eventHub.$emit(`editor.update.model.content.${file.path}`, file.raw); }; + +export const openPendingTab = ({ commit }, file) => { + commit(types.ADD_PENDING_TAB, file); +}; diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index eba325a31df..28006d3ddf8 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -1,10 +1,10 @@ -export const activeFile = state => - state.openFiles.find(file => file.active) || null; +export const tabs = state => state.openFiles.concat(state.pendingTabs); + +export const activeFile = state => tabs(state).find(file => file.active) || null; export const addedFiles = state => state.changedFiles.filter(f => f.tempFile); -export const modifiedFiles = state => - state.changedFiles.filter(f => !f.tempFile); +export const modifiedFiles = state => state.changedFiles.filter(f => !f.tempFile); export const projectsWithTrees = state => Object.keys(state.projects).map(projectId => { diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index e28f190897c..fa2fbaf8683 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -41,3 +41,6 @@ export const SET_ENTRIES = 'SET_ENTRIES'; export const CREATE_TMP_ENTRY = 'CREATE_TMP_ENTRY'; export const UPDATE_VIEWER = 'UPDATE_VIEWER'; export const UPDATE_DELAY_VIEWER_CHANGE = 'UPDATE_DELAY_VIEWER_CHANGE'; + +export const ADD_PENDING_TAB = 'ADD_PENDING_TAB'; +export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB'; diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js index 2500f13db7c..915126f10eb 100644 --- a/app/assets/javascripts/ide/stores/mutations/file.js +++ b/app/assets/javascripts/ide/stores/mutations/file.js @@ -80,4 +80,18 @@ export default { changed, }); }, + [types.ADD_PENDING_TAB](state, file) { + Object.assign(state, { + pendingTabs: state.pendingTabs.concat({ + ...file, + active: true, + pending: true, + }), + }); + }, + [types.REMOVE_PENDING_TAB](state, file) { + Object.assign(state, { + pendingTabs: state.pendingTabs.filter(f => f.path !== file.path), + }); + }, }; diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 6110f54951c..52a2400ec42 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -16,4 +16,5 @@ export default () => ({ entries: {}, viewer: 'editor', delayViewerUpdated: false, + pendingTabs: [], }); diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 65046f6665e..94aa5130f28 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -177,6 +177,10 @@ background-color: $white-light; border-bottom-color: $white-light; } + + &.pending { + font-style: italic; + } } .multi-file-tab-close { @@ -720,9 +724,7 @@ } .ide-view { - height: calc( - 100vh - #{$header-height + $performance-bar-height + $flash-height} - ); + height: calc(100vh - #{$header-height + $performance-bar-height + $flash-height}); } } } |