@hostlink/nuxt-light 1.61.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/l-dialog-upload-files.d.vue.ts +29 -0
- package/dist/runtime/components/l-dialog-upload-files.vue +178 -0
- package/dist/runtime/components/l-dialog-upload-files.vue.d.ts +29 -0
- package/dist/runtime/components/l-file-manager-breadcrumbs.d.vue.ts +10 -0
- package/dist/runtime/components/l-file-manager-breadcrumbs.vue +37 -0
- package/dist/runtime/components/l-file-manager-breadcrumbs.vue.d.ts +10 -0
- package/dist/runtime/components/l-file-manager-move.d.vue.ts +7 -3
- package/dist/runtime/components/l-file-manager-move.vue +68 -29
- package/dist/runtime/components/l-file-manager-move.vue.d.ts +7 -3
- package/dist/runtime/components/l-file-manager-preview.d.vue.ts +3 -13
- package/dist/runtime/components/l-file-manager-preview.vue +33 -23
- package/dist/runtime/components/l-file-manager-preview.vue.d.ts +3 -13
- package/dist/runtime/components/l-file-manager.vue +173 -256
- package/dist/runtime/composables/showUploadFilesDialog.d.ts +1 -0
- package/dist/runtime/composables/showUploadFilesDialog.js +11 -0
- package/dist/runtime/pages/System/fs.vue +26 -51
- package/package.json +2 -2
|
@@ -1,43 +1,42 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useI18n } from "vue-i18n";
|
|
3
3
|
import { ref, watch, computed } from "vue";
|
|
4
|
-
import { useQuasar, format } from "quasar";
|
|
5
|
-
import { q, m, useLight } from "#imports";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import { getDrive, listDrives } from "@hostlink/light";
|
|
4
|
+
import { useQuasar, format, date } from "quasar";
|
|
5
|
+
import { q, m, useLight, showUploadFilesDialog } from "#imports";
|
|
6
|
+
import { getGrantedRights } from "@hostlink/light";
|
|
7
|
+
import { fs } from "@hostlink/light";
|
|
9
8
|
const { humanStorageSize } = format;
|
|
10
9
|
const light = useLight();
|
|
11
10
|
const i18n = useI18n();
|
|
12
11
|
const $q = useQuasar();
|
|
13
12
|
const emit = defineEmits(["input", "close"]);
|
|
14
|
-
const
|
|
13
|
+
const fss = await q({
|
|
14
|
+
app: {
|
|
15
|
+
fs: {
|
|
16
|
+
list: true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}).then((res) => res.app.fs.list);
|
|
15
20
|
const folders = ref([]);
|
|
16
21
|
const files = ref([]);
|
|
17
|
-
const nodes =
|
|
22
|
+
const nodes = fss.map((drive) => {
|
|
18
23
|
return {
|
|
19
24
|
icon: "sym_o_storage",
|
|
20
|
-
name:
|
|
21
|
-
|
|
25
|
+
name: drive.name,
|
|
26
|
+
location: drive.name + "://",
|
|
22
27
|
path: "/",
|
|
23
28
|
lazy: true,
|
|
24
|
-
driveIndex:
|
|
29
|
+
driveIndex: drive.index,
|
|
25
30
|
type: "drive"
|
|
26
31
|
};
|
|
27
32
|
});
|
|
28
33
|
const onLazyLoad = async ({ node, key, done, fail }) => {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
path: true
|
|
32
|
-
});
|
|
33
|
-
const data = folders2.map((item) => {
|
|
34
|
-
item.driveIndex = node.driveIndex;
|
|
35
|
-
item.id = node.driveIndex + "/" + item.path;
|
|
34
|
+
const folder = await fs.list(node.location);
|
|
35
|
+
const folders2 = folder.children.filter((item) => item.__typename === "Folder").map((item) => {
|
|
36
36
|
item.lazy = true;
|
|
37
|
-
item.type = "folder";
|
|
38
37
|
return item;
|
|
39
38
|
});
|
|
40
|
-
done(
|
|
39
|
+
done(folders2);
|
|
41
40
|
};
|
|
42
41
|
const props = defineProps({
|
|
43
42
|
closeable: Boolean,
|
|
@@ -80,7 +79,14 @@ const columns = ref([
|
|
|
80
79
|
{
|
|
81
80
|
name: "last_modified",
|
|
82
81
|
label: i18n.t("Last Modified"),
|
|
83
|
-
field: "
|
|
82
|
+
field: "lastModified",
|
|
83
|
+
sortable: true,
|
|
84
|
+
format: (value) => {
|
|
85
|
+
if (value) {
|
|
86
|
+
return date.formatDate(value * 1e3, "YYYY-MM-DD HH:mm:ss");
|
|
87
|
+
}
|
|
88
|
+
return "";
|
|
89
|
+
},
|
|
84
90
|
align: "left"
|
|
85
91
|
},
|
|
86
92
|
{
|
|
@@ -88,6 +94,7 @@ const columns = ref([
|
|
|
88
94
|
label: i18n.t("Size"),
|
|
89
95
|
field: "size",
|
|
90
96
|
align: "right",
|
|
97
|
+
sortable: true,
|
|
91
98
|
format: (val) => {
|
|
92
99
|
if (val == null) {
|
|
93
100
|
return "";
|
|
@@ -100,104 +107,43 @@ const columns = ref([
|
|
|
100
107
|
const localSearch = ref(null);
|
|
101
108
|
const rightDrawerOpen = ref(false);
|
|
102
109
|
const leftDrawerOpen = ref(false);
|
|
103
|
-
const showDateOptions = ref(false);
|
|
104
|
-
const exactPhrase = ref("");
|
|
105
|
-
const hasWords = ref("");
|
|
106
|
-
const excludeWords = ref("");
|
|
107
|
-
const byWebsite = ref("");
|
|
108
|
-
const byDate = ref("Any time");
|
|
109
|
-
function onClear() {
|
|
110
|
-
exactPhrase.value = "";
|
|
111
|
-
hasWords.value = "";
|
|
112
|
-
excludeWords.value = "";
|
|
113
|
-
byWebsite.value = "";
|
|
114
|
-
byDate.value = "Any time";
|
|
115
|
-
}
|
|
116
|
-
function changeDate(option) {
|
|
117
|
-
byDate.value = option;
|
|
118
|
-
showDateOptions.value = false;
|
|
119
|
-
}
|
|
120
110
|
function toggleLeftDrawer() {
|
|
121
111
|
leftDrawerOpen.value = !leftDrawerOpen.value;
|
|
122
112
|
}
|
|
123
113
|
const loadItems = async () => {
|
|
124
|
-
let
|
|
114
|
+
let path = selectedLocation.value;
|
|
125
115
|
files.value = [];
|
|
126
116
|
folders.value = [];
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (label.value) {
|
|
130
|
-
filesParams.type = label.value;
|
|
117
|
+
if (!path) {
|
|
118
|
+
return;
|
|
131
119
|
}
|
|
132
|
-
if (localSearch.value) {
|
|
133
|
-
|
|
120
|
+
if (label.value || localSearch.value) {
|
|
121
|
+
loading.value = true;
|
|
122
|
+
const items2 = await fs.find(localSearch.value, label.value);
|
|
123
|
+
loading.value = false;
|
|
124
|
+
files.value = items2.filter((item) => item.__typename === "File");
|
|
125
|
+
folders.value = items2.filter((item) => item.__typename === "Folder");
|
|
126
|
+
return;
|
|
134
127
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
index: selectedDrive.value
|
|
140
|
-
},
|
|
141
|
-
files: {
|
|
142
|
-
__args: filesParams,
|
|
143
|
-
name: true,
|
|
144
|
-
path: true,
|
|
145
|
-
size: true,
|
|
146
|
-
mime: true,
|
|
147
|
-
url: true,
|
|
148
|
-
lastModified: true,
|
|
149
|
-
lastModifiedHuman: true
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
files.value = resp.app.drive.files.map((item) => {
|
|
155
|
-
item.driveIndex = selectedDrive.value;
|
|
156
|
-
item.type = "file";
|
|
157
|
-
return item;
|
|
158
|
-
});
|
|
128
|
+
loading.value = true;
|
|
129
|
+
const folder = await fs.list(path);
|
|
130
|
+
loading.value = false;
|
|
131
|
+
files.value = folder.children.filter((item) => item.__typename === "File");
|
|
159
132
|
if (!label.value && !localSearch.value) {
|
|
160
|
-
folders.value =
|
|
161
|
-
item.driveIndex = selectedDrive.value;
|
|
162
|
-
item.type = "folder";
|
|
133
|
+
folders.value = folder.children.filter((item) => item.__typename === "Folder").map((item) => {
|
|
163
134
|
item.lazy = true;
|
|
164
|
-
item.id = selectedDrive.value + "/" + item.path;
|
|
165
135
|
return item;
|
|
166
136
|
});
|
|
167
|
-
reloadTreeFolder(
|
|
137
|
+
reloadTreeFolder(selectedLocation.value, folders.value);
|
|
168
138
|
}
|
|
169
|
-
loading.value = false;
|
|
170
139
|
};
|
|
171
140
|
const label = ref(null);
|
|
172
141
|
watch(label, () => {
|
|
173
142
|
loadItems();
|
|
174
143
|
});
|
|
175
144
|
const selected = ref([]);
|
|
176
|
-
const breadcrumbs = computed(() => {
|
|
177
|
-
if (selectedPath.value.toString() == "") {
|
|
178
|
-
return [];
|
|
179
|
-
}
|
|
180
|
-
let paths = selectedNodePath.value.split("/");
|
|
181
|
-
let driveIndex = paths.shift();
|
|
182
|
-
let driveName = drives.find((d) => d.index == driveIndex).name;
|
|
183
|
-
let breadcrumbs2 = [{
|
|
184
|
-
label: driveName,
|
|
185
|
-
path: driveIndex
|
|
186
|
-
}];
|
|
187
|
-
let ps = [];
|
|
188
|
-
for (let p of paths) {
|
|
189
|
-
if (p) {
|
|
190
|
-
ps.push(p);
|
|
191
|
-
breadcrumbs2.push({
|
|
192
|
-
label: p,
|
|
193
|
-
path: driveIndex + "/" + ps.join("/")
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return breadcrumbs2;
|
|
198
|
-
});
|
|
199
145
|
const onClickRow = (evt, row, index) => {
|
|
200
|
-
if (row.
|
|
146
|
+
if (row.__typename == "Folder") {
|
|
201
147
|
preview.value = null;
|
|
202
148
|
return;
|
|
203
149
|
}
|
|
@@ -205,31 +151,31 @@ const onClickRow = (evt, row, index) => {
|
|
|
205
151
|
};
|
|
206
152
|
const grid = ref(false);
|
|
207
153
|
const onDblclickRow = (evt, row, index) => {
|
|
208
|
-
if (row.
|
|
209
|
-
|
|
154
|
+
if (row.__typename == "Folder") {
|
|
155
|
+
selectedLocation.value = row.location;
|
|
210
156
|
return;
|
|
211
157
|
}
|
|
212
|
-
if (row.
|
|
158
|
+
if (row.__typename == "File") {
|
|
213
159
|
emit("input", row.path);
|
|
214
160
|
}
|
|
215
161
|
};
|
|
216
|
-
const findFolder = (
|
|
162
|
+
const findFolder = (path, folders2) => {
|
|
217
163
|
folders2.value.forEach((item) => {
|
|
218
|
-
if (item.path ==
|
|
164
|
+
if (item.path == path) {
|
|
219
165
|
return item;
|
|
220
166
|
}
|
|
221
|
-
let found = findFolder(
|
|
167
|
+
let found = findFolder(path, item.children);
|
|
222
168
|
if (found) {
|
|
223
169
|
return found;
|
|
224
170
|
}
|
|
225
171
|
});
|
|
226
172
|
};
|
|
227
|
-
const reloadTreeFolder = (
|
|
228
|
-
let node = folderTree.value.getNodeByKey(
|
|
173
|
+
const reloadTreeFolder = (path, newFolders) => {
|
|
174
|
+
let node = folderTree.value.getNodeByKey(path);
|
|
229
175
|
if (node) {
|
|
230
176
|
node.lazy = false;
|
|
231
177
|
node.children = newFolders;
|
|
232
|
-
folderTree.value.setExpanded(
|
|
178
|
+
folderTree.value.setExpanded(path, true);
|
|
233
179
|
}
|
|
234
180
|
};
|
|
235
181
|
const onDeleteSelected = () => {
|
|
@@ -238,14 +184,17 @@ const onDeleteSelected = () => {
|
|
|
238
184
|
message: "Are you sure you want to delete this files or folders?",
|
|
239
185
|
cancel: true
|
|
240
186
|
}).onOk(async () => {
|
|
187
|
+
loading.value = true;
|
|
241
188
|
for (let row of selected.value) {
|
|
242
|
-
if (row.
|
|
243
|
-
await
|
|
189
|
+
if (row.__typename == "Folder") {
|
|
190
|
+
await fs.deleteFolder(row.location);
|
|
244
191
|
} else {
|
|
245
|
-
await
|
|
192
|
+
await fs.deleteFile(row.location);
|
|
246
193
|
}
|
|
247
194
|
}
|
|
195
|
+
loading.value = false;
|
|
248
196
|
selected.value = [];
|
|
197
|
+
preview.value = null;
|
|
249
198
|
await loadItems();
|
|
250
199
|
});
|
|
251
200
|
};
|
|
@@ -257,98 +206,83 @@ const onNewFolder = () => {
|
|
|
257
206
|
label: "Name",
|
|
258
207
|
isValid: (val) => {
|
|
259
208
|
return val.length > 0;
|
|
260
|
-
}
|
|
209
|
+
},
|
|
210
|
+
hint: "Create a new folder in " + selectedLocation.value
|
|
261
211
|
},
|
|
262
212
|
cancel: true
|
|
263
213
|
}).onOk(async (name) => {
|
|
264
|
-
|
|
214
|
+
loading.value = true;
|
|
215
|
+
await fs.createFolder(selectedLocation.value + "/" + name);
|
|
265
216
|
await loadItems();
|
|
217
|
+
loading.value = false;
|
|
266
218
|
});
|
|
267
219
|
};
|
|
268
|
-
const onDeleteRow = (
|
|
269
|
-
if (
|
|
220
|
+
const onDeleteRow = (node) => {
|
|
221
|
+
if (node.__typename == "File") {
|
|
270
222
|
$q.dialog({
|
|
271
223
|
title: "Delete",
|
|
272
224
|
message: "Are you sure you want to delete this file?",
|
|
273
225
|
cancel: true
|
|
274
226
|
}).onOk(async () => {
|
|
275
|
-
|
|
227
|
+
loading.value = true;
|
|
228
|
+
await fs.deleteFile(node.location);
|
|
276
229
|
await loadItems();
|
|
230
|
+
loading.value = false;
|
|
277
231
|
});
|
|
278
|
-
} else if (
|
|
232
|
+
} else if (node.__typename == "Folder") {
|
|
279
233
|
$q.dialog({
|
|
280
234
|
title: "Delete",
|
|
281
235
|
message: "Are you sure you want to delete this folder?",
|
|
282
236
|
cancel: true
|
|
283
237
|
}).onOk(async () => {
|
|
284
|
-
|
|
238
|
+
loading.value = true;
|
|
239
|
+
await fs.deleteFolder(node.location);
|
|
285
240
|
await loadItems();
|
|
241
|
+
loading.value = false;
|
|
286
242
|
});
|
|
287
243
|
}
|
|
288
244
|
};
|
|
289
|
-
const
|
|
245
|
+
const onRenameNode = (node) => {
|
|
290
246
|
$q.dialog({
|
|
291
|
-
title: "Rename " +
|
|
247
|
+
title: "Rename " + node.__typename,
|
|
292
248
|
prompt: {
|
|
293
249
|
label: "Name",
|
|
294
|
-
model:
|
|
250
|
+
model: node.name
|
|
295
251
|
},
|
|
296
252
|
cancel: true
|
|
297
253
|
}).onOk(async (name) => {
|
|
298
254
|
try {
|
|
299
|
-
if (
|
|
300
|
-
await
|
|
255
|
+
if (node.__typename == "File") {
|
|
256
|
+
await fs.renameFile(node.location, name);
|
|
301
257
|
} else {
|
|
302
|
-
await
|
|
258
|
+
await fs.renameFolder(node.location, name);
|
|
303
259
|
}
|
|
260
|
+
await loadItems();
|
|
304
261
|
} catch (e) {
|
|
305
|
-
$q.
|
|
262
|
+
$q.notify({
|
|
306
263
|
title: "Error",
|
|
307
|
-
message: e.message
|
|
264
|
+
message: e.message,
|
|
265
|
+
type: "negative"
|
|
308
266
|
});
|
|
309
|
-
return;
|
|
310
267
|
}
|
|
311
|
-
await loadItems();
|
|
312
268
|
});
|
|
313
269
|
};
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
$q.loading.show({
|
|
318
|
-
message: "Uploading files..."
|
|
270
|
+
const openUploadDialog = () => {
|
|
271
|
+
showUploadFilesDialog(selectedLocation.value).onOk((files2) => {
|
|
272
|
+
loadItems();
|
|
319
273
|
});
|
|
274
|
+
};
|
|
275
|
+
const preview = ref(null);
|
|
276
|
+
const moveToFolder = async (folder) => {
|
|
320
277
|
try {
|
|
321
|
-
for (let
|
|
322
|
-
await
|
|
323
|
-
index: selectedDrive.value,
|
|
324
|
-
path: selectedPath.value,
|
|
325
|
-
file
|
|
326
|
-
});
|
|
278
|
+
for (let node of selected.value) {
|
|
279
|
+
await fs.move(node.location, folder);
|
|
327
280
|
}
|
|
328
281
|
} catch (e) {
|
|
329
282
|
$q.dialog({
|
|
330
283
|
title: "Error",
|
|
331
284
|
message: e.message
|
|
332
285
|
});
|
|
333
|
-
$q.loading.hide();
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
uploadFiles.value = [];
|
|
337
|
-
$q.loading.hide();
|
|
338
|
-
showUploadFiles.value = false;
|
|
339
|
-
await loadItems();
|
|
340
|
-
};
|
|
341
|
-
const preview = ref(null);
|
|
342
|
-
const drive = computed(() => {
|
|
343
|
-
return api.drive(selectedDrive.value);
|
|
344
|
-
});
|
|
345
|
-
const moveToFolder = async (folder) => {
|
|
346
|
-
for (let row of selected.value) {
|
|
347
|
-
if (row.type == "folder") {
|
|
348
|
-
await drive.value.folders.move(row.path, folder);
|
|
349
|
-
} else {
|
|
350
|
-
await drive.value.files.move(row.path, folder);
|
|
351
|
-
}
|
|
352
286
|
}
|
|
353
287
|
await loadItems();
|
|
354
288
|
};
|
|
@@ -356,21 +290,14 @@ const submitSearch = (e) => {
|
|
|
356
290
|
localSearch.value = search.value;
|
|
357
291
|
loadItems();
|
|
358
292
|
};
|
|
359
|
-
const
|
|
360
|
-
const base64Content = await
|
|
293
|
+
const onDownloadNode = async (node) => {
|
|
294
|
+
const base64Content = await fs.readFile(node.location, "base64");
|
|
361
295
|
const downloadLink = document.createElement("a");
|
|
362
|
-
downloadLink.href = `data
|
|
363
|
-
downloadLink.download =
|
|
296
|
+
downloadLink.href = `data:${node.mimeType};base64,${base64Content}`;
|
|
297
|
+
downloadLink.download = node.name;
|
|
364
298
|
downloadLink.click();
|
|
365
299
|
};
|
|
366
300
|
const search = ref(null);
|
|
367
|
-
const reloadStorage = async () => {
|
|
368
|
-
path.value = props.base;
|
|
369
|
-
search.value = "";
|
|
370
|
-
localSearch.value = "";
|
|
371
|
-
label.value = null;
|
|
372
|
-
await loadItems();
|
|
373
|
-
};
|
|
374
301
|
const permission = await getGrantedRights([
|
|
375
302
|
"fs.folder.create",
|
|
376
303
|
"fs.folder.delete",
|
|
@@ -380,19 +307,19 @@ const permission = await getGrantedRights([
|
|
|
380
307
|
"fs.file.upload"
|
|
381
308
|
]);
|
|
382
309
|
const canDeleteRow = (row) => {
|
|
383
|
-
if (row.
|
|
310
|
+
if (row.__typename == "Folder" && permission.includes("fs.folder.delete")) {
|
|
384
311
|
return true;
|
|
385
312
|
}
|
|
386
|
-
if (row.
|
|
313
|
+
if (row.__typename == "File" && permission.includes("fs.file.delete")) {
|
|
387
314
|
return true;
|
|
388
315
|
}
|
|
389
316
|
return false;
|
|
390
317
|
};
|
|
391
318
|
const canRenameRow = (row) => {
|
|
392
|
-
if (row.
|
|
319
|
+
if (row.__typename == "Folder" && permission.includes("fs.folder.rename")) {
|
|
393
320
|
return true;
|
|
394
321
|
}
|
|
395
|
-
if (row.
|
|
322
|
+
if (row.__typename == "File" && permission.includes("fs.file.rename")) {
|
|
396
323
|
return true;
|
|
397
324
|
}
|
|
398
325
|
return false;
|
|
@@ -400,18 +327,37 @@ const canRenameRow = (row) => {
|
|
|
400
327
|
const showPreviewImgDialog = ref(false);
|
|
401
328
|
const previewImg = ref(null);
|
|
402
329
|
const isDark = computed(() => light.isDarkMode());
|
|
403
|
-
const
|
|
330
|
+
const getFilePublicUrl = async (location) => {
|
|
331
|
+
const file = await q({
|
|
332
|
+
app: {
|
|
333
|
+
fs: {
|
|
334
|
+
node: {
|
|
335
|
+
__args: {
|
|
336
|
+
location
|
|
337
|
+
},
|
|
338
|
+
__typename: true,
|
|
339
|
+
__on: {
|
|
340
|
+
__typeName: "File",
|
|
341
|
+
publicUrl: true
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}).then((res) => res.app.fs.node);
|
|
347
|
+
return file.publicUrl;
|
|
348
|
+
};
|
|
349
|
+
const onPreview = async (node) => {
|
|
404
350
|
showPreviewImgDialog.value = true;
|
|
405
|
-
previewImg.value =
|
|
351
|
+
previewImg.value = await getFilePublicUrl(node.location);
|
|
406
352
|
};
|
|
407
|
-
const onPreviewPDF = async (
|
|
353
|
+
const onPreviewPDF = async (node) => {
|
|
408
354
|
const height = window.innerHeight - 200;
|
|
409
355
|
$q.dialog({
|
|
410
356
|
autoClose: true,
|
|
411
357
|
fullWidth: true,
|
|
412
358
|
fullHeight: true,
|
|
413
359
|
title: "Preview PDF",
|
|
414
|
-
message: "<iframe src='" +
|
|
360
|
+
message: "<iframe src='" + await getFilePublicUrl(node.location) + "' width='100%' height='" + height + "px'></iframe>",
|
|
415
361
|
html: true
|
|
416
362
|
});
|
|
417
363
|
};
|
|
@@ -421,54 +367,41 @@ const onClickInfo = async (row) => {
|
|
|
421
367
|
const items = computed(() => {
|
|
422
368
|
return [...folders.value, ...files.value];
|
|
423
369
|
});
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
if (selectedNodePath.value) {
|
|
427
|
-
const [driveIndex, ...path2] = selectedNodePath.value.split("/");
|
|
428
|
-
return parseInt(driveIndex);
|
|
429
|
-
}
|
|
430
|
-
return null;
|
|
431
|
-
});
|
|
432
|
-
const selectedPath = computed(() => {
|
|
433
|
-
if (selectedNodePath.value) {
|
|
434
|
-
const [driveIndex, ...path2] = selectedNodePath.value.split("/");
|
|
435
|
-
return "/" + path2.join("/");
|
|
436
|
-
}
|
|
437
|
-
return "";
|
|
438
|
-
});
|
|
439
|
-
watch(selectedNodePath, async () => {
|
|
370
|
+
const selectedLocation = ref(null);
|
|
371
|
+
watch(selectedLocation, async () => {
|
|
440
372
|
selected.value = [];
|
|
441
373
|
await loadItems();
|
|
442
374
|
});
|
|
443
375
|
const canPreview = (file) => {
|
|
444
|
-
if (!file.
|
|
376
|
+
if (!file.mimeType) {
|
|
445
377
|
return false;
|
|
446
378
|
}
|
|
447
|
-
return file.
|
|
379
|
+
return file.mimeType.startsWith("image/");
|
|
448
380
|
};
|
|
449
381
|
const onCheckTotalSize = async (folder) => {
|
|
450
382
|
const d = $q.dialog({
|
|
451
383
|
title: "Total Size",
|
|
452
384
|
progress: true
|
|
453
385
|
});
|
|
454
|
-
const
|
|
386
|
+
const node = await q({
|
|
455
387
|
app: {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
index: folder.driveIndex
|
|
459
|
-
},
|
|
460
|
-
folder: {
|
|
388
|
+
fs: {
|
|
389
|
+
node: {
|
|
461
390
|
__args: {
|
|
462
|
-
|
|
391
|
+
location: folder.location
|
|
463
392
|
},
|
|
464
|
-
|
|
393
|
+
__typename: true,
|
|
394
|
+
name: true,
|
|
395
|
+
__on: {
|
|
396
|
+
__typeName: "Folder",
|
|
397
|
+
totalSize: true
|
|
398
|
+
}
|
|
465
399
|
}
|
|
466
400
|
}
|
|
467
401
|
}
|
|
468
|
-
});
|
|
469
|
-
const size = humanStorageSize(resp.app.drive.folder.totalSize);
|
|
402
|
+
}).then((res) => res.app.fs.node);
|
|
470
403
|
d.update({
|
|
471
|
-
message: "Total size of folder '" +
|
|
404
|
+
message: "Total size of folder '" + node.name + "' is " + humanStorageSize(node.totalSize),
|
|
472
405
|
progress: false
|
|
473
406
|
});
|
|
474
407
|
};
|
|
@@ -494,7 +427,7 @@ const onDuplicateFile = async (file) => {
|
|
|
494
427
|
const onDrop = (event) => {
|
|
495
428
|
event.preventDefault();
|
|
496
429
|
event.stopPropagation();
|
|
497
|
-
if (
|
|
430
|
+
if (selectedLocation.value == null) {
|
|
498
431
|
$q.notify({
|
|
499
432
|
type: "warning",
|
|
500
433
|
message: "Please select a folder to upload files."
|
|
@@ -503,18 +436,19 @@ const onDrop = (event) => {
|
|
|
503
436
|
}
|
|
504
437
|
const files2 = event.dataTransfer.files;
|
|
505
438
|
console.log("Dropped files:", files2);
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
439
|
+
if (files2.length > 0) {
|
|
440
|
+
const fileList = Array.from(files2);
|
|
441
|
+
showUploadFilesDialog(selectedLocation.value, fileList).onOk((uploadedFiles) => {
|
|
442
|
+
loadItems();
|
|
443
|
+
});
|
|
509
444
|
}
|
|
510
|
-
showUploadFiles.value = true;
|
|
511
445
|
dragzone.value.style.border = "none";
|
|
512
446
|
};
|
|
513
447
|
const dragzone = ref(null);
|
|
514
448
|
const onDragover = (event) => {
|
|
515
449
|
event.preventDefault();
|
|
516
450
|
event.stopPropagation();
|
|
517
|
-
if (
|
|
451
|
+
if (selectedLocation.value == null) {
|
|
518
452
|
return;
|
|
519
453
|
}
|
|
520
454
|
dragzone.value.style.border = "2px dashed #1976d2";
|
|
@@ -522,21 +456,24 @@ const onDragover = (event) => {
|
|
|
522
456
|
const onDragLeave = (event) => {
|
|
523
457
|
event.preventDefault();
|
|
524
458
|
event.stopPropagation();
|
|
525
|
-
if (
|
|
459
|
+
if (selectedLocation.value == null) {
|
|
526
460
|
return;
|
|
527
461
|
}
|
|
528
462
|
dragzone.value.style.border = "none";
|
|
529
463
|
};
|
|
530
464
|
const getFileIcon = (file) => {
|
|
531
|
-
if (file.
|
|
465
|
+
if (!file.mimeType) {
|
|
466
|
+
return "sym_o_description";
|
|
467
|
+
}
|
|
468
|
+
if (file.mimeType.startsWith("image/")) {
|
|
532
469
|
return "sym_o_image";
|
|
533
|
-
} else if (file.
|
|
470
|
+
} else if (file.mimeType === "application/pdf") {
|
|
534
471
|
return "sym_o_picture_as_pdf";
|
|
535
|
-
} else if (file.
|
|
472
|
+
} else if (file.mimeType.startsWith("video/")) {
|
|
536
473
|
return "sym_o_videocam";
|
|
537
|
-
} else if (file.
|
|
474
|
+
} else if (file.mimeType.startsWith("audio/")) {
|
|
538
475
|
return "sym_o_audiotrack";
|
|
539
|
-
} else if (file.
|
|
476
|
+
} else if (file.mimeType === "application/zip" || file.mimeType === "application/x-rar-compressed") {
|
|
540
477
|
return "sym_o_archive";
|
|
541
478
|
} else {
|
|
542
479
|
return "sym_o_description";
|
|
@@ -573,7 +510,7 @@ const getFileIcon = (file) => {
|
|
|
573
510
|
<q-list padding class="text-grey-8">
|
|
574
511
|
<q-item>
|
|
575
512
|
<q-item-section>
|
|
576
|
-
<l-btn icon="add" label="New" :disable="!
|
|
513
|
+
<l-btn icon="add" label="New" :disable="!selectedLocation">
|
|
577
514
|
<q-menu>
|
|
578
515
|
<q-list>
|
|
579
516
|
<q-item clickable v-close-popup @click="onNewFolder" v-if="permission.includes('fs.folder.create')">
|
|
@@ -583,7 +520,7 @@ const getFileIcon = (file) => {
|
|
|
583
520
|
<q-item-section>{{ $t('Folder') }}</q-item-section>
|
|
584
521
|
</q-item>
|
|
585
522
|
<q-separator />
|
|
586
|
-
<q-item clickable v-close-popup @click="
|
|
523
|
+
<q-item clickable v-close-popup @click="openUploadDialog"
|
|
587
524
|
v-if="permission.includes('fs.file.upload')">
|
|
588
525
|
<q-item-section avatar>
|
|
589
526
|
<q-icon name="sym_o_upload_file"></q-icon>
|
|
@@ -596,8 +533,8 @@ const getFileIcon = (file) => {
|
|
|
596
533
|
</q-item-section>
|
|
597
534
|
</q-item>
|
|
598
535
|
|
|
599
|
-
<q-tree ref="folderTree" :nodes="nodes" node-key="
|
|
600
|
-
v-model:selected="
|
|
536
|
+
<q-tree ref="folderTree" :nodes="nodes" node-key="location" label-key="name" @lazy-load="onLazyLoad"
|
|
537
|
+
v-model:selected="selectedLocation" no-selection-unset>
|
|
601
538
|
</q-tree>
|
|
602
539
|
|
|
603
540
|
<q-separator inset class="q-my-sm" />
|
|
@@ -608,7 +545,7 @@ const getFileIcon = (file) => {
|
|
|
608
545
|
</q-drawer>
|
|
609
546
|
|
|
610
547
|
<q-drawer v-model="rightDrawerOpen" side="right" show-if-above bordered>
|
|
611
|
-
<l-file-manager-preview :
|
|
548
|
+
<l-file-manager-preview :location="preview.location" v-if="preview" :key="preview.location" />
|
|
612
549
|
</q-drawer>
|
|
613
550
|
|
|
614
551
|
<q-page-container :style="{ height }">
|
|
@@ -622,33 +559,12 @@ const getFileIcon = (file) => {
|
|
|
622
559
|
</q-card>
|
|
623
560
|
</q-dialog>
|
|
624
561
|
|
|
625
|
-
<q-dialog v-model="showUploadFiles" persistent transition-show="scale" transition-hide="scale">
|
|
626
|
-
<q-card style="min-width: 400px;">
|
|
627
|
-
<q-toolbar>
|
|
628
|
-
<q-toolbar-title>{{ $t('Upload Files') }}</q-toolbar-title>
|
|
629
|
-
<q-space></q-space>
|
|
630
|
-
<q-btn flat round dense icon="sym_o_close" v-close-popup></q-btn>
|
|
631
|
-
</q-toolbar>
|
|
632
|
-
<q-card-section>
|
|
633
|
-
<q-file ref="file" v-model="uploadFiles" multiple name="file" label="Files" color="primary"></q-file>
|
|
634
|
-
</q-card-section>
|
|
635
|
-
|
|
636
|
-
<q-card-actions align="right">
|
|
637
|
-
<q-btn flat :label="$t('Cancel')" color="primary" v-close-popup></q-btn>
|
|
638
|
-
<q-btn flat :label="$t('Upload')" color="primary" @click="onUploadFiles"></q-btn>
|
|
639
|
-
</q-card-actions>
|
|
640
|
-
</q-card>
|
|
641
|
-
</q-dialog>
|
|
642
|
-
|
|
643
562
|
<q-toolbar>
|
|
644
|
-
<
|
|
645
|
-
<q-breadcrumbs-el v-for="(b, index) in breadcrumbs" :label="b.label" :key="index"
|
|
646
|
-
@click="selectedNodePath = b.path" href="javascript:void(0)"></q-breadcrumbs-el>
|
|
647
|
-
</q-breadcrumbs>
|
|
563
|
+
<l-file-manager-breadcrumbs v-model="selectedLocation" />
|
|
648
564
|
<q-space></q-space>
|
|
649
|
-
|
|
650
565
|
<q-btn flat round icon="sym_o_drive_file_move" v-if="selected.length > 0">
|
|
651
|
-
<l-file-manager-move @selected="moveToFolder($event)" :
|
|
566
|
+
<l-file-manager-move @selected="moveToFolder($event)" :current_location="selectedLocation"
|
|
567
|
+
:allow_cross_fs="selected.every(item => item.__typename == 'File')" />
|
|
652
568
|
<q-tooltip>
|
|
653
569
|
{{ $t('Move to') }}
|
|
654
570
|
</q-tooltip>
|
|
@@ -668,7 +584,7 @@ const getFileIcon = (file) => {
|
|
|
668
584
|
|
|
669
585
|
<template v-if="grid">
|
|
670
586
|
<q-table :title="$t('Folders')" flat grid :columns="columns" :rows="folders" hide-pagination
|
|
671
|
-
:pagination="{ rowsPerPage: 0 }">
|
|
587
|
+
:pagination="{ rowsPerPage: 0 }" row-key="location">
|
|
672
588
|
<template v-slot:item="props">
|
|
673
589
|
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4" @click="onDblclickRow(null, props.row, null)">
|
|
674
590
|
<q-card flat bordered>
|
|
@@ -689,14 +605,14 @@ const getFileIcon = (file) => {
|
|
|
689
605
|
</q-table>
|
|
690
606
|
|
|
691
607
|
<q-table :title="$t('Files')" flat grid :columns="columns" :rows="files" hide-pagination
|
|
692
|
-
:pagination="{ rowsPerPage: 0 }">
|
|
608
|
+
:pagination="{ rowsPerPage: 0 }" row-key="location">
|
|
693
609
|
|
|
694
610
|
<template v-slot:item="props">
|
|
695
611
|
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4" @click="onClickRow(null, props.row, null)">
|
|
696
612
|
<q-card flat bordered>
|
|
697
613
|
<q-item>
|
|
698
614
|
<q-item-section avatar>
|
|
699
|
-
<q-icon :name="getFileIcon(props.row)"
|
|
615
|
+
<q-icon :name="getFileIcon(props.row)" size="sm"></q-icon>
|
|
700
616
|
</q-item-section>
|
|
701
617
|
<q-item-section>
|
|
702
618
|
<q-item-label lines="1">
|
|
@@ -718,12 +634,12 @@ const getFileIcon = (file) => {
|
|
|
718
634
|
<template v-else>
|
|
719
635
|
|
|
720
636
|
<q-table flat :columns="columns" :rows="items" @row-dblclick="onDblclickRow" @row-click="onClickRow"
|
|
721
|
-
:pagination="pagination" row-key="
|
|
637
|
+
:pagination="pagination" row-key="location" selection="multiple" v-model:selected="selected" dense
|
|
722
638
|
:loading="loading" :loading-label="$t('Loading...')" :no-data-label="$t('No data available')"
|
|
723
639
|
separator="horizontal" :rows-per-page-options="[0]" color="primary">
|
|
724
640
|
<template #body-cell-icon="props">
|
|
725
641
|
<q-td auto-width>
|
|
726
|
-
<q-icon name="sym_o_folder" v-if="props.
|
|
642
|
+
<q-icon name="sym_o_folder" v-if="props.row.__typename == 'Folder'" size="sm" />
|
|
727
643
|
<q-icon :name="getFileIcon(props.row)" v-else size="sm" />
|
|
728
644
|
</q-td>
|
|
729
645
|
</template>
|
|
@@ -735,7 +651,7 @@ const getFileIcon = (file) => {
|
|
|
735
651
|
<q-list>
|
|
736
652
|
|
|
737
653
|
<q-item clickable v-close-popup="true" @click="onCheckTotalSize(props.row)"
|
|
738
|
-
v-if="props.row.
|
|
654
|
+
v-if="props.row.__typename == 'Folder'">
|
|
739
655
|
<q-item-section avatar>
|
|
740
656
|
<q-icon name="sym_o_info"></q-icon>
|
|
741
657
|
</q-item-section>
|
|
@@ -749,14 +665,15 @@ const getFileIcon = (file) => {
|
|
|
749
665
|
<q-item-section>{{ $t('Delete') }}</q-item-section>
|
|
750
666
|
</q-item>
|
|
751
667
|
|
|
752
|
-
<q-item v-if="props.row.
|
|
668
|
+
<q-item v-if="props.row.__typename == 'File'" clickable v-close-popup
|
|
669
|
+
@click="onDownloadNode(props.row)">
|
|
753
670
|
<q-item-section avatar>
|
|
754
671
|
<q-icon name="sym_o_download"></q-icon>
|
|
755
672
|
</q-item-section>
|
|
756
673
|
<q-item-section>{{ $t('Download') }}</q-item-section>
|
|
757
674
|
</q-item>
|
|
758
675
|
|
|
759
|
-
<q-item clickable v-close-popup @click="
|
|
676
|
+
<q-item clickable v-close-popup @click="onRenameNode(props.row)" v-if="canRenameRow(props.row)">
|
|
760
677
|
<q-item-section avatar>
|
|
761
678
|
<q-icon name="sym_o_edit"></q-icon>
|
|
762
679
|
</q-item-section>
|
|
@@ -764,7 +681,7 @@ const getFileIcon = (file) => {
|
|
|
764
681
|
</q-item>
|
|
765
682
|
|
|
766
683
|
<q-item clickable v-close-popup @click="onDuplicateFile(props.row)"
|
|
767
|
-
v-if="props.row.
|
|
684
|
+
v-if="props.row.__typename == 'File'">
|
|
768
685
|
<q-item-section avatar>
|
|
769
686
|
<q-icon name="sym_o_content_copy"></q-icon>
|
|
770
687
|
</q-item-section>
|
|
@@ -778,7 +695,7 @@ const getFileIcon = (file) => {
|
|
|
778
695
|
<q-item-section>{{ $t('Preview') }}</q-item-section>
|
|
779
696
|
</q-item>
|
|
780
697
|
|
|
781
|
-
<q-item clickable v-close-popup v-if="props.row.
|
|
698
|
+
<q-item clickable v-close-popup v-if="props.row.mimeType == 'application/pdf'"
|
|
782
699
|
@click="onPreviewPDF(props.row)">
|
|
783
700
|
<q-item-section avatar>
|
|
784
701
|
<q-icon name="sym_o_preview"></q-icon>
|