|
6 | 6 | <div class="modal-close-icon" v-on:click="closeModal"> |
7 | 7 | <Icon name="x" aria-label="Close modal" role="button"/> |
8 | 8 | </div> |
9 | | - <MessageBox class="alert error mb-2" title="Error" :message="error" v-if="error"/> |
| 9 | + <MessageBox class="alert error mb-4" title="Error" :message="error" v-if="error"/> |
| 10 | + <div class="flex items-center mb-4 bg-white rounded p-2"> |
| 11 | + <div class="mx-2"> |
| 12 | + <label class="input-label mb-0" for="file-name-input">File name:</label> |
| 13 | + </div> |
| 14 | + <div class="flex-1"> |
| 15 | + <input |
| 16 | + type="text" |
| 17 | + name="file_name" |
| 18 | + class="input" |
| 19 | + id="file-name-input" |
| 20 | + :disabled="typeof file !== 'undefined'" |
| 21 | + v-model="fileName" |
| 22 | + v-validate="'required'" |
| 23 | + /> |
| 24 | + <p class="input-help error" v-show="errors.has('file_name')">{{ errors.first('file_name') }}</p> |
| 25 | + </div> |
| 26 | + </div> |
10 | 27 | <div id="editor"></div> |
11 | 28 | <div class="flex mt-4 bg-white rounded p-2"> |
12 | 29 | <div class="flex-1"> |
|
35 | 52 | import {ApplicationState, FileManagerState} from '@/store/types'; |
36 | 53 | import {mapState} from "vuex"; |
37 | 54 | import * as Ace from 'brace'; |
38 | | - import { join } from 'path'; |
| 55 | + import {join} from 'path'; |
39 | 56 | import {DirectoryContentObject} from "@/api/server/types"; |
40 | 57 | import getFileContents from '@/api/server/files/getFileContents'; |
41 | 58 | import SpinnerModal from "@/components/core/SpinnerModal.vue"; |
|
46 | 63 | file?: DirectoryContentObject, |
47 | 64 | serverUuid?: string, |
48 | 65 | fm?: FileManagerState, |
| 66 | + fileName?: string, |
49 | 67 | error: string | null, |
50 | 68 | editor: Ace.Editor | null, |
51 | 69 | isVisible: boolean, |
52 | 70 | isLoading: boolean, |
53 | | - supportedTypes: {type: string, name: string, default?: boolean}[], |
| 71 | + supportedTypes: { type: string, name: string, default?: boolean }[], |
54 | 72 | } |
55 | 73 |
|
56 | 74 | const defaults = { |
57 | 75 | error: null, |
58 | 76 | editor: null, |
59 | 77 | isVisible: false, |
60 | 78 | isLoading: true, |
| 79 | + file: undefined, |
| 80 | + fileName: undefined, |
61 | 81 | }; |
62 | 82 |
|
63 | 83 | export default Vue.extend({ |
|
101 | 121 | this.file = file; |
102 | 122 | this.isVisible = true; |
103 | 123 | this.isLoading = true; |
| 124 | + this.fileName = file ? file.name : undefined; |
| 125 | + this.errors.clear(); |
104 | 126 |
|
105 | 127 | this.$nextTick(() => { |
106 | 128 | this.editor = Ace.edit('editor'); |
|
120 | 142 | }); |
121 | 143 | }, |
122 | 144 |
|
| 145 | + watch: { |
| 146 | + fileName: function (newValue?: string, oldValue?: string) { |
| 147 | + if (newValue === oldValue || !newValue) { |
| 148 | + return; |
| 149 | + } |
| 150 | +
|
| 151 | + this.updateFileLanguageFromName(newValue); |
| 152 | + }, |
| 153 | + }, |
| 154 | +
|
123 | 155 | methods: { |
124 | 156 | submit: function () { |
| 157 | + if (!this.file && (!this.fileName || this.fileName.length === 0)) { |
| 158 | + this.error = 'You must provide a file name before saving.'; |
| 159 | + return; |
| 160 | + } |
| 161 | +
|
125 | 162 | this.isLoading = true; |
126 | 163 | const content = this.editor!.getValue(); |
127 | 164 |
|
128 | | - writeFileContents(this.serverUuid!, join(this.fm!.currentDirectory, this.file!.name), content) |
129 | | - .then(() => this.error = null) |
| 165 | + writeFileContents(this.serverUuid!, join(this.fm!.currentDirectory, this.fileName!), content) |
| 166 | + .then(() => { |
| 167 | + this.error = null; |
| 168 | +
|
| 169 | + // @todo come up with a more graceful solution here |
| 170 | + if (!this.file) { |
| 171 | + this.$emit('refresh'); |
| 172 | + this.closeModal(); |
| 173 | + } |
| 174 | + }) |
130 | 175 | .catch(error => { |
131 | 176 | console.log(error); |
132 | 177 | this.error = httpErrorToHuman(error); |
|
136 | 181 |
|
137 | 182 | loadFileContent: function (): Promise<void> { |
138 | 183 | return new Promise((resolve, reject) => { |
139 | | - const { editor, file } = this; |
| 184 | + const {editor, file} = this; |
140 | 185 |
|
141 | 186 | if (!file || !editor || file.directory) { |
142 | 187 | return resolve(); |
|
147 | 192 | editor.$blockScrolling = Infinity; |
148 | 193 | editor.setValue(contents, 1); |
149 | 194 | }) |
150 | | - .then(() => { |
151 | | - // Set the correct MIME type on the editor for the user. |
152 | | - const modelist = Ace.acequire('ace/ext/modelist'); |
153 | | - if (modelist) { |
154 | | - const mode = modelist.getModeForPath(file.name).mode || 'ace/mode/text'; |
155 | | - editor.getSession().setMode(mode); |
156 | | -
|
157 | | - const parts = mode.split('/'); |
158 | | - const element = (this.$refs.fileLanguageSelector as HTMLSelectElement | null); |
159 | | -
|
160 | | - if (element) { |
161 | | - const index = this.supportedTypes.findIndex(value => value.type === parts[parts.length - 1]); |
162 | | - if (index >= 0) { |
163 | | - element.selectedIndex = index; |
164 | | - } |
165 | | - } |
166 | | - } |
167 | | - }) |
| 195 | + .then(() => this.updateFileLanguageFromName(file.name)) |
168 | 196 | .then(() => resolve()) |
169 | 197 | .catch(reject); |
170 | 198 | }); |
171 | 199 | }, |
172 | 200 |
|
| 201 | + updateFileLanguageFromName: function (name: string) { |
| 202 | + const modelist = Ace.acequire('ace/ext/modelist'); |
| 203 | + if (!modelist || !this.editor) { |
| 204 | + return; |
| 205 | + } |
| 206 | +
|
| 207 | + const mode = modelist.getModeForPath(name).mode || 'ace/mode/text'; |
| 208 | +
|
| 209 | + const parts = mode.split('/'); |
| 210 | + const element = (this.$refs.fileLanguageSelector as HTMLSelectElement | null); |
| 211 | +
|
| 212 | + if (element) { |
| 213 | + const index = this.supportedTypes.findIndex(value => value.type === parts[parts.length - 1]); |
| 214 | + if (index >= 0) { |
| 215 | + element.selectedIndex = index; |
| 216 | + this.editor.getSession().setMode(mode); |
| 217 | + } |
| 218 | + } |
| 219 | + }, |
| 220 | +
|
173 | 221 | updateFileLanguage: function (e: MouseEvent) { |
174 | 222 | if (!this.editor) { |
175 | 223 | return; |
|
185 | 233 | /* webpackMode: "lazy-once" */ |
186 | 234 | /* webpackInclude: /(dockerfile|golang|html|java|javascript|json|kotlin|lua|markdown|text|php|properties|python|ruby|sh|sql|xml|yaml).js$/ */ |
187 | 235 | `brace/mode/${o.type}` |
188 | | - )) |
| 236 | + )) |
189 | 237 | ); |
190 | 238 | }, |
191 | 239 |
|
|
0 commit comments