Skip to content
Snippets Groups Projects
Unverified Commit 002cc923 authored by Phil Hughes's avatar Phil Hughes
Browse files

Added pending tabs to IDE

Pending tabs are normal tabs that are opened from the right sidebar.
They are opened in diff mode and when changed to edit mode they get
closed
& the actual file gets opened.
parent b3fb82a9
No related branches found
No related tags found
No related merge requests found
Showing with 209 additions and 203 deletions
<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>
Loading
Loading
<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>
Loading
Loading
@@ -60,7 +60,7 @@
v-if="activeFile"
>
<repo-tabs
:files="openFiles"
:files="tabs"
:viewer="viewer"
:has-changes="hasChanges"
/>
Loading
Loading
<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>
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
<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>
Loading
Loading
@@ -47,7 +46,7 @@
>
<repo-tab
v-for="tab in files"
:key="tab.key"
:key="`${tab.key}${tab.pending ? '-pending' : ''}`"
:tab="tab"
/>
</ul>
Loading
Loading
Loading
Loading
@@ -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 => {
Loading
Loading
@@ -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,
Loading
Loading
Loading
Loading
@@ -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}`);
Loading
Loading
@@ -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);
});
};
 
Loading
Loading
@@ -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 }) => {
Loading
Loading
@@ -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,
Loading
Loading
@@ -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);
};
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 => {
Loading
Loading
Loading
Loading
@@ -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';
Loading
Loading
@@ -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),
});
},
};
Loading
Loading
@@ -16,4 +16,5 @@ export default () => ({
entries: {},
viewer: 'editor',
delayViewerUpdated: false,
pendingTabs: [],
});
Loading
Loading
@@ -177,6 +177,10 @@
background-color: $white-light;
border-bottom-color: $white-light;
}
&.pending {
font-style: italic;
}
}
 
.multi-file-tab-close {
Loading
Loading
@@ -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});
}
}
}
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment