diff options
author | Paul Slaughter <pslaughter@gitlab.com> | 2018-09-27 16:57:30 -0500 |
---|---|---|
committer | Paul Slaughter <pslaughter@gitlab.com> | 2018-09-28 15:03:39 -0500 |
commit | adbf6149cf1778cd48a9bbf8e97332669dbcb7cb (patch) | |
tree | 01f53873bc7dbe0b04d8de8182af359e21ecc2b4 /app/assets | |
parent | 1eefdf5da50030fbc342a08155ed4aa56805aea9 (diff) | |
download | gitlab-ce-adbf6149cf1778cd48a9bbf8e97332669dbcb7cb.tar.gz |
Keep IDE RightPane views aliveide-keep-right-pane-tabs-alive
**Why?**
- This is needed for the Web Terminal feature.
https://gitlab.com/gitlab-org/gitlab-ee/issues/5426
**Notes:**
- Introduces a `pane` Vuex module.
- Some views should not be kept alive (i.e. job details).
This is why a `keepAlive` flag was introduced for views.
Diffstat (limited to 'app/assets')
16 files changed, 130 insertions, 42 deletions
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue index 715dc1bfb42..a04d09ef374 100644 --- a/app/assets/javascripts/ide/components/ide_status_bar.vue +++ b/app/assets/javascripts/ide/components/ide_status_bar.vue @@ -50,7 +50,9 @@ export default { this.stopPipelinePolling(); }, methods: { - ...mapActions(['setRightPane']), + ...mapActions('rightPane', { + openRightPane: 'open', + }), ...mapActions('pipelines', ['fetchLatestPipeline', 'stopPipelinePolling']), startTimer() { this.intervalId = setInterval(() => { @@ -88,7 +90,7 @@ export default { <button type="button" class="p-0 border-0 h-50" - @click="setRightPane($options.rightSidebarViews.pipelines)" + @click="openRightPane($options.rightSidebarViews.pipelines)" > <ci-icon v-tooltip diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue index 75a9a9e9b8f..bd07f372177 100644 --- a/app/assets/javascripts/ide/components/panes/right.vue +++ b/app/assets/javascripts/ide/components/panes/right.vue @@ -1,5 +1,6 @@ <script> import { mapActions, mapState, mapGetters } from 'vuex'; +import _ from 'underscore'; import { __ } from '~/locale'; import tooltip from '../../../vue_shared/directives/tooltip'; import Icon from '../../../vue_shared/components/icon.vue'; @@ -30,14 +31,10 @@ export default { }, }, computed: { - ...mapState(['rightPane', 'currentMergeRequestId', 'clientsidePreviewEnabled']), + ...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled']), + ...mapState('rightPane', ['isOpen', 'currentView']), ...mapGetters(['packageJson']), - pipelinesActive() { - return ( - this.rightPane === rightSidebarViews.pipelines || - this.rightPane === rightSidebarViews.jobsDetail - ); - }, + ...mapGetters('rightPane', ['isActiveView', 'isAliveView']), showLivePreview() { return this.packageJson && this.clientsidePreviewEnabled; }, @@ -46,22 +43,26 @@ export default { { show: this.currentMergeRequestId, title: __('Merge Request'), - isActive: this.rightPane === rightSidebarViews.mergeRequestInfo, - view: rightSidebarViews.mergeRequestInfo, + views: [ + rightSidebarViews.mergeRequestInfo, + ], icon: 'text-description', }, { show: true, title: __('Pipelines'), - isActive: this.pipelinesActive, - view: rightSidebarViews.pipelines, + views: [ + rightSidebarViews.pipelines, + rightSidebarViews.jobsDetail, + ], icon: 'rocket', }, { show: this.showLivePreview, title: __('Live preview'), - isActive: this.rightPane === rightSidebarViews.clientSidePreview, - view: rightSidebarViews.clientSidePreview, + views: [ + rightSidebarViews.clientSidePreview, + ], icon: 'live-preview', }, ]; @@ -71,13 +72,26 @@ export default { .concat(this.extensionTabs) .filter(tab => tab.show); }, + tabViews() { + return _.flatten(this.tabs.map(tab => tab.views)); + }, + aliveTabViews() { + return this.tabViews.filter(view => this.isAliveView(view.name)); + }, }, methods: { - ...mapActions(['setRightPane']), - clickTab(e, view) { + ...mapActions('rightPane', ['toggleOpen', 'open']), + clickTab(e, tab) { e.target.blur(); - this.setRightPane(view); + if (this.isActiveTab(tab)) { + this.toggleOpen(); + } else { + this.open(tab.views[0]); + } + }, + isActiveTab(tab) { + return tab.views.some(view => this.isActiveView(view.name)); }, }, }; @@ -88,15 +102,22 @@ export default { class="multi-file-commit-panel ide-right-sidebar" > <resizable-panel - v-if="rightPane" + v-show="isOpen" :collapsible="false" :initial-width="350" :min-size="350" - :class="`ide-right-sidebar-${rightPane}`" + :class="`ide-right-sidebar-${currentView}`" side="right" class="multi-file-commit-panel-inner" > - <component :is="rightPane" /> + <div + v-for="tabView in aliveTabViews" + v-show="isActiveView(tabView.name)" + :key="tabView.name" + class="h-100" + > + <component :is="tabView.name" /> + </div> </resizable-panel> <nav class="ide-activity-bar"> <ul class="list-unstyled"> @@ -109,13 +130,13 @@ export default { :title="tab.title" :aria-label="tab.title" :class="{ - active: tab.isActive + active: isActiveTab(tab) && isOpen }" data-container="body" data-placement="left" class="ide-sidebar-link is-right" type="button" - @click="clickTab($event, tab.view)" + @click="clickTab($event, tab)" > <icon :size="16" diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index d3a73e84cc7..b2599128213 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -22,12 +22,14 @@ export default { }, }, computed: { + ...mapState('rightPane', { + rightPaneIsOpen: 'isOpen', + }), ...mapState([ 'rightPanelCollapsed', 'viewer', 'panelResizing', 'currentActivityView', - 'rightPane', ]), ...mapGetters([ 'currentMergeRequest', @@ -99,7 +101,7 @@ export default { this.editor.updateDimensions(); } }, - rightPane() { + rightPaneIsOpen() { this.editor.updateDimensions(); }, }, diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js index 8caa5b86a9b..3b201f006aa 100644 --- a/app/assets/javascripts/ide/constants.js +++ b/app/assets/javascripts/ide/constants.js @@ -29,10 +29,10 @@ export const diffModes = { }; export const rightSidebarViews = { - pipelines: 'pipelines-list', - jobsDetail: 'jobs-detail', - mergeRequestInfo: 'merge-request-info', - clientSidePreview: 'clientside', + pipelines: { name: 'pipelines-list', keepAlive: true }, + jobsDetail: { name: 'jobs-detail', keepAlive: false }, + mergeRequestInfo: { name: 'merge-request-info', keepAlive: true }, + clientSidePreview: { name: 'clientside', keepAlive: false }, }; export const stageKeys = { diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index b8b64aead30..e10a132ab4b 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -184,10 +184,6 @@ export const burstUnusedSeal = ({ state, commit }) => { } }; -export const setRightPane = ({ commit }, view) => { - commit(types.SET_RIGHT_PANE, view); -}; - export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links); export const setErrorMessage = ({ commit }, errorMessage) => diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js index 877d88bb060..f1f544b52b2 100644 --- a/app/assets/javascripts/ide/stores/index.js +++ b/app/assets/javascripts/ide/stores/index.js @@ -9,6 +9,7 @@ import pipelines from './modules/pipelines'; import mergeRequests from './modules/merge_requests'; import branches from './modules/branches'; import fileTemplates from './modules/file_templates'; +import paneModule from './modules/pane'; Vue.use(Vuex); @@ -24,6 +25,7 @@ export const createStore = () => mergeRequests, branches, fileTemplates: fileTemplates(), + rightPane: paneModule(), }, }); diff --git a/app/assets/javascripts/ide/stores/modules/pane/actions.js b/app/assets/javascripts/ide/stores/modules/pane/actions.js new file mode 100644 index 00000000000..7f5d167a14f --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/actions.js @@ -0,0 +1,30 @@ +import * as types from './mutation_types'; + +export const toggleOpen = ({ dispatch, state }, view) => { + if (state.isOpen) { + dispatch('close'); + } else { + dispatch('open', view); + } +}; + +export const open = ({ commit }, view) => { + commit(types.SET_OPEN, true); + + if (view) { + const { name, keepAlive } = view; + + commit(types.SET_CURRENT_VIEW, name); + + if (keepAlive) { + commit(types.KEEP_ALIVE_VIEW, name); + } + } +}; + +export const close = ({ commit }) => { + commit(types.SET_OPEN, false); +}; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/app/assets/javascripts/ide/stores/modules/pane/getters.js b/app/assets/javascripts/ide/stores/modules/pane/getters.js new file mode 100644 index 00000000000..c346cf13689 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/getters.js @@ -0,0 +1,4 @@ +export const isActiveView = state => view => state.currentView === view; + +export const isAliveView = (state, getters) => view => + state.keepAliveViews[view] || (state.isOpen && getters.isActiveView(view)); diff --git a/app/assets/javascripts/ide/stores/modules/pane/index.js b/app/assets/javascripts/ide/stores/modules/pane/index.js new file mode 100644 index 00000000000..5f61cb732c8 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/index.js @@ -0,0 +1,12 @@ +import * as actions from './actions'; +import * as getters from './getters'; +import mutations from './mutations'; +import state from './state'; + +export default () => ({ + namespaced: true, + state: state(), + actions, + getters, + mutations, +}); diff --git a/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js b/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js new file mode 100644 index 00000000000..abdebc4d913 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js @@ -0,0 +1,3 @@ +export const SET_OPEN = 'SET_OPEN'; +export const SET_CURRENT_VIEW = 'SET_CURRENT_VIEW'; +export const KEEP_ALIVE_VIEW = 'KEEP_ALIVE_VIEW'; diff --git a/app/assets/javascripts/ide/stores/modules/pane/mutations.js b/app/assets/javascripts/ide/stores/modules/pane/mutations.js new file mode 100644 index 00000000000..c16484b4402 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/mutations.js @@ -0,0 +1,19 @@ +import * as types from './mutation_types'; + +export default { + [types.SET_OPEN](state, isOpen) { + Object.assign(state, { + isOpen, + }); + }, + [types.SET_CURRENT_VIEW](state, currentView) { + Object.assign(state, { + currentView, + }); + }, + [types.KEEP_ALIVE_VIEW](state, viewName) { + Object.assign(state.keepAliveViews, { + [viewName]: true, + }); + }, +}; diff --git a/app/assets/javascripts/ide/stores/modules/pane/state.js b/app/assets/javascripts/ide/stores/modules/pane/state.js new file mode 100644 index 00000000000..353065b5735 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/pane/state.js @@ -0,0 +1,5 @@ +export default () => ({ + isOpen: false, + currentView: null, + keepAliveViews: {}, +}); diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js index 3e67b222e66..8fa86995ef0 100644 --- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js +++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js @@ -113,7 +113,7 @@ export const toggleStageCollapsed = ({ commit }, stageId) => export const setDetailJob = ({ commit, dispatch }, job) => { commit(types.SET_DETAIL_JOB, job); - dispatch('setRightPane', job ? rightSidebarViews.jobsDetail : rightSidebarViews.pipelines, { + dispatch('rightPane/open', job ? rightSidebarViews.jobsDetail : rightSidebarViews.pipelines, { root: true, }); }; diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 5a7991d2fa7..a5f8098dc17 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -68,8 +68,6 @@ export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG'; export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER'; export const BURST_UNUSED_SEAL = 'BURST_UNUSED_SEAL'; -export const SET_RIGHT_PANE = 'SET_RIGHT_PANE'; - export const CLEAR_PROJECTS = 'CLEAR_PROJECTS'; export const RESET_OPEN_FILES = 'RESET_OPEN_FILES'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 2c8535bda59..78cdfda74f0 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -166,11 +166,6 @@ export default { unusedSeal: false, }); }, - [types.SET_RIGHT_PANE](state, view) { - Object.assign(state, { - rightPane: state.rightPane === view ? null : view, - }); - }, [types.SET_LINKS](state, links) { Object.assign(state, { links }); }, diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 46b52fa00fc..d400b9831a9 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -23,7 +23,6 @@ export default () => ({ currentActivityView: activityBarViews.edit, unusedSeal: true, fileFindVisible: false, - rightPane: null, links: {}, errorMessage: null, entryModal: { |