Show a cleaner interface while loading file contents
This commit is contained in:
parent
a8462bf109
commit
89194b4c55
|
@ -2,7 +2,7 @@
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div class="modal-mask" v-show="visible">
|
<div class="modal-mask" v-show="visible">
|
||||||
<div class="modal-container w-auto">
|
<div class="modal-container w-auto">
|
||||||
<div class="p-8 pb-0">
|
<div class="modal-content p-8 pb-0">
|
||||||
<div class="spinner spinner-thick spinner-relative blue spinner-xl"></div>
|
<div class="spinner spinner-thick spinner-relative blue spinner-xl"></div>
|
||||||
<p class="text-neutral-700 mt-8 text-sm">
|
<p class="text-neutral-700 mt-8 text-sm">
|
||||||
<slot/>
|
<slot/>
|
||||||
|
|
|
@ -2,18 +2,21 @@
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div class="modal-mask" v-show="isVisible">
|
<div class="modal-mask" v-show="isVisible">
|
||||||
<div class="modal-container full-screen" @click.stop>
|
<div class="modal-container full-screen" @click.stop>
|
||||||
<div class="modal-close-icon" v-on:click="isVisible = false">
|
<SpinnerModal :visible="isVisible && isLoading"/>
|
||||||
|
<div class="modal-close-icon" v-on:click="closeModal">
|
||||||
<Icon name="x" aria-label="Close modal" role="button"/>
|
<Icon name="x" aria-label="Close modal" role="button"/>
|
||||||
</div>
|
</div>
|
||||||
<MessageBox class="alert error mb-8" title="Error" :message="error" v-if="error"/>
|
<MessageBox class="alert error mb-2" title="Error" :message="error" v-if="error"/>
|
||||||
<div id="editor"></div>
|
<div id="editor"></div>
|
||||||
<div class="flex mt-4 bg-white rounded p-2">
|
<div class="flex mt-4 bg-white rounded p-2">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<select v-on:change="updateFileLanguage">
|
<select v-on:change="updateFileLanguage" ref="fileLanguageSelector">
|
||||||
<option v-for="item in supportedTypes" :value="item.type">{{ item.name }}</option>
|
<option v-for="item in supportedTypes" :value="item.type">
|
||||||
|
{{ item.name }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-secondary btn-sm" v-on:click="isVisible = false">
|
<button class="btn btn-secondary btn-sm" v-on:click="closeModal">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button class="ml-2 btn btn-primary btn-sm">
|
<button class="ml-2 btn btn-primary btn-sm">
|
||||||
|
@ -35,6 +38,7 @@
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import {DirectoryContentObject} from "@/api/server/types";
|
import {DirectoryContentObject} from "@/api/server/types";
|
||||||
import getFileContents from '@/api/server/files/getFileContents';
|
import getFileContents from '@/api/server/files/getFileContents';
|
||||||
|
import SpinnerModal from "@/components/core/SpinnerModal.vue";
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
file?: DirectoryContentObject,
|
file?: DirectoryContentObject,
|
||||||
|
@ -44,21 +48,26 @@
|
||||||
editor: Ace.Editor | null,
|
editor: Ace.Editor | null,
|
||||||
isVisible: boolean,
|
isVisible: boolean,
|
||||||
isLoading: boolean,
|
isLoading: boolean,
|
||||||
supportedTypes: {type: string, name: string}[],
|
supportedTypes: {type: string, name: string, default?: boolean}[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaults = {
|
||||||
|
error: null,
|
||||||
|
editor: null,
|
||||||
|
isVisible: false,
|
||||||
|
isLoading: true,
|
||||||
|
};
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'NewFileModal',
|
name: 'NewFileModal',
|
||||||
|
|
||||||
components: {Icon, MessageBox},
|
components: {Icon, SpinnerModal, MessageBox},
|
||||||
|
|
||||||
data: function (): Data {
|
data: function (): Data {
|
||||||
return {
|
return {
|
||||||
error: null,
|
...defaults,
|
||||||
editor: null,
|
|
||||||
isVisible: false,
|
|
||||||
isLoading: false,
|
|
||||||
supportedTypes: [
|
supportedTypes: [
|
||||||
|
{type: 'text', name: 'Text'},
|
||||||
{type: 'dockerfile', name: 'Docker'},
|
{type: 'dockerfile', name: 'Docker'},
|
||||||
{type: 'golang', name: 'Go'},
|
{type: 'golang', name: 'Go'},
|
||||||
{type: 'html', name: 'HTML'},
|
{type: 'html', name: 'HTML'},
|
||||||
|
@ -68,7 +77,6 @@
|
||||||
{type: 'kotlin', name: 'Kotlin'},
|
{type: 'kotlin', name: 'Kotlin'},
|
||||||
{type: 'lua', name: 'Lua'},
|
{type: 'lua', name: 'Lua'},
|
||||||
{type: 'markdown', name: 'Markdown'},
|
{type: 'markdown', name: 'Markdown'},
|
||||||
{type: 'plain_text', name: 'Text'},
|
|
||||||
{type: 'php', name: 'PHP'},
|
{type: 'php', name: 'PHP'},
|
||||||
{type: 'properties', name: 'Properties'},
|
{type: 'properties', name: 'Properties'},
|
||||||
{type: 'python', name: 'Python'},
|
{type: 'python', name: 'Python'},
|
||||||
|
@ -90,6 +98,7 @@
|
||||||
window.events.$on('server:files:open-edit-file-modal', (file?: DirectoryContentObject) => {
|
window.events.$on('server:files:open-edit-file-modal', (file?: DirectoryContentObject) => {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.isVisible = true;
|
this.isVisible = true;
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.editor = Ace.edit('editor');
|
this.editor = Ace.edit('editor');
|
||||||
|
@ -97,6 +106,14 @@
|
||||||
.then(() => this.loadLanguages())
|
.then(() => this.loadLanguages())
|
||||||
.then(() => this.configureEditor())
|
.then(() => this.configureEditor())
|
||||||
.then(() => this.loadFileContent())
|
.then(() => this.loadFileContent())
|
||||||
|
.then(() => {
|
||||||
|
this.isLoading = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
this.isLoading = false;
|
||||||
|
this.error = error.message;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -106,15 +123,39 @@
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loadFileContent: function () {
|
loadFileContent: function (): Promise<void> {
|
||||||
if (!this.file || !this.editor || this.file.directory) {
|
return new Promise((resolve, reject) => {
|
||||||
return;
|
const { editor, file } = this;
|
||||||
|
|
||||||
|
if (!file || !editor || file.directory) {
|
||||||
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
getFileContents(this.serverUuid!, join(this.fm!.currentDirectory, this.file.name))
|
getFileContents(this.serverUuid!, join(this.fm!.currentDirectory, file.name))
|
||||||
.then(contents => {
|
.then(contents => {
|
||||||
this.editor!.$blockScrolling = Infinity;
|
editor.$blockScrolling = Infinity;
|
||||||
this.editor!.setValue(contents, 1);
|
editor.setValue(contents, 1);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Set the correct MIME type on the editor for the user.
|
||||||
|
const modelist = Ace.acequire('ace/ext/modelist');
|
||||||
|
if (modelist) {
|
||||||
|
const mode = modelist.getModeForPath(file.name).mode || 'ace/mode/text';
|
||||||
|
editor.getSession().setMode(mode);
|
||||||
|
|
||||||
|
const parts = mode.split('/');
|
||||||
|
const element = (this.$refs.fileLanguageSelector as HTMLSelectElement | null);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
const index = this.supportedTypes.findIndex(value => value.type === parts[parts.length - 1]);
|
||||||
|
if (index >= 0) {
|
||||||
|
element.selectedIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => resolve())
|
||||||
|
.catch(reject);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -131,7 +172,7 @@
|
||||||
this.supportedTypes.map(o => import(
|
this.supportedTypes.map(o => import(
|
||||||
/* webpackChunkName: "ace_editor" */
|
/* webpackChunkName: "ace_editor" */
|
||||||
/* webpackMode: "lazy-once" */
|
/* webpackMode: "lazy-once" */
|
||||||
/* webpackInclude: /(dockerfile|golang|html|java|javascript|json|kotlin|lua|markdown|plain_text|php|properties|python|ruby|sh|sql|xml|yaml).js$/ */
|
/* webpackInclude: /(dockerfile|golang|html|java|javascript|json|kotlin|lua|markdown|text|php|properties|python|ruby|sh|sql|xml|yaml).js$/ */
|
||||||
`brace/mode/${o.type}`
|
`brace/mode/${o.type}`
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -153,7 +194,6 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const modelist = Ace.acequire('brace/ext/whitespace');
|
|
||||||
const whitespace = Ace.acequire('ace/ext/whitespace');
|
const whitespace = Ace.acequire('ace/ext/whitespace');
|
||||||
|
|
||||||
this.editor.setTheme('ace/theme/chrome');
|
this.editor.setTheme('ace/theme/chrome');
|
||||||
|
@ -167,7 +207,15 @@
|
||||||
this.editor!.commands.addCommand(c);
|
this.editor!.commands.addCommand(c);
|
||||||
});
|
});
|
||||||
whitespace.detectIndentation(this.editor.session);
|
whitespace.detectIndentation(this.editor.session);
|
||||||
|
},
|
||||||
|
|
||||||
|
closeModal: function () {
|
||||||
|
if (this.editor) {
|
||||||
|
this.editor.setValue('', -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.assign(this.$data, defaults);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue