1
- <script setup>
1
+ <script setup lang="ts" >
2
2
definePageMeta ({
3
3
middleware: ' auth'
4
4
})
5
5
const loading = ref (false )
6
- const newFileKey = ref (' ' )
7
- const newFileValue = ref ()
8
- const newFileKeyInput = ref ()
6
+ const newFilesValue = ref <File []>([])
9
7
const uploadRef = ref ()
10
8
11
9
const toast = useToast ()
12
10
const { user, clear } = useUserSession ()
13
11
const { data : storage } = await useFetch (' /api/storage' )
14
12
15
13
async function addFile () {
16
- const key = newFileKey .value .trim ().replace (/ \s / g , ' -' )
17
- if (! key || ! newFileValue .value ) {
18
- toast .add ({ title: ` Missing ${ ! key ? ' key' : ' file' } .` , color: ' red' })
14
+ if (! newFilesValue .value .length ) {
15
+ toast .add ({ title: ' Missing files.' , color: ' red' })
19
16
return
20
17
}
21
18
22
19
loading .value = true
23
20
24
21
try {
25
22
const formData = new FormData ()
26
- formData .append (' data' , new Blob ([JSON .stringify ({ key })], { type: ' application/json' }))
27
- formData .append (' file' , newFileValue .value )
28
- const file = await $fetch (' /api/storage' , {
23
+ newFilesValue .value .forEach ((file ) => formData .append (' files' , file ))
24
+ const files = await $fetch (' /api/storage' , {
29
25
method: ' PUT' ,
30
26
body: formData
31
27
})
32
- const fileIndex = storage .value .findIndex (e => e .key === file .key )
33
- if (fileIndex !== - 1 ) {
34
- storage .value .splice (fileIndex, 1 , file)
35
- } else {
36
- storage .value .push (file)
37
- }
38
- toast .add ({ title: ` File "${ key} " created.` })
39
- newFileKey .value = ' '
40
- newFileValue .value = null
41
- nextTick (() => {
42
- newFileKeyInput .value ? .input ? .focus ()
43
- })
44
- } catch (err) {
45
- if (err .data ? .data ? .issues ) {
46
- const title = err .data .data .issues .map (issue => issue .message ).join (' \n ' )
47
- toast .add ({ title, color: ' red' })
48
- }
28
+ storage .value ! .push (... files )
29
+ toast .add ({ title: ' Files created.' })
30
+ newFilesValue .value = []
31
+ } catch (err : any ) {
32
+ const title = err .data ?.data ?.issues ?.map ((issue : any ) => issue .message ).join (' \n ' ) || err .message ()
33
+ toast .add ({ title , color: ' red' })
49
34
}
50
35
loading .value = false
51
36
}
52
37
53
- function onFileSelect (e ) {
38
+ function onFileSelect (e : any ) {
54
39
const target = e .target
55
40
56
41
// clone FileList so the reference does not clear due to following target clear
57
- const files = [... (target .files || [])]
58
- if (files .length ) {
59
- newFileValue .value = files[0 ]
60
- newFileKey .value = files[0 ].name
61
- }
42
+ newFilesValue .value = [... (target .files || [])]
62
43
63
44
// Clear the input value so that the same file can be uploaded again
64
45
target .value = ' '
65
46
}
66
47
67
- async function deleteFile (key ) {
48
+ async function deleteFile (key : string ) {
68
49
try {
69
50
await useFetch (` /api/storage/${key } ` , { method: ' DELETE' })
70
- storage .value = storage .value .filter (t => t .key !== key)
51
+ storage .value = storage .value ! .filter (t => t .key !== key )
71
52
toast .add ({ title: ` File "${key }" deleted. ` })
72
- } catch (err) {
73
- if (err .data ? .data ? .issues ) {
74
- const title = err .data .data .issues .map (issue => issue .message ).join (' \n ' )
75
- toast .add ({ title, color: ' red' })
76
- }
53
+ } catch (err : any ) {
54
+ const title = err .data ?.data ?.issues ?.map ((issue : any ) => issue .message ).join (' \n ' ) || err .message ()
55
+ toast .add ({ title , color: ' red' })
77
56
}
78
57
}
79
58
80
- onMounted (async () => {
81
- // FIXME
82
- // storage.value = await Promise.all(storage.value.map(async (file) => {
83
- // const { data: { body } } = await useFetch(`/api/storage/${file.key}`, { params: { populate: true } })
84
- // return {
85
- // ...file,
86
- // body
87
- // }
88
- // }))
89
- })
90
-
91
59
const items = [[{
92
60
label: ' Logout' ,
93
61
icon: ' i-heroicons-arrow-left-on-rectangle' ,
@@ -114,18 +82,7 @@ const items = [[{
114
82
115
83
<div class =" flex items-center gap-2" >
116
84
<UInput
117
- ref= " newFileKeyInput"
118
- v- model= " newFileKey"
119
- name= " fileKey"
120
- : disabled= " loading"
121
- class = " flex-1"
122
- placeholder= " key"
123
- autocomplete= " off"
124
- autofocus
125
- : ui= " { wrapper: 'flex-1' }"
126
- / >
127
- < UInput
128
- : model- value= " newFileValue?.name"
85
+ :model-value =" newFilesValue?.map((file) => file.name).join(', ')"
129
86
name =" fileValue"
130
87
disabled
131
88
class =" flex-1"
@@ -137,7 +94,8 @@ const items = [[{
137
94
tabindex =" -1"
138
95
accept =" jpeg, png"
139
96
type =" file"
140
- name= " file"
97
+ name =" files"
98
+ multiple
141
99
class =" hidden"
142
100
@change =" onFileSelect"
143
101
>
@@ -147,7 +105,7 @@ const items = [[{
147
105
@click =" uploadRef.click()"
148
106
/>
149
107
150
- < UButton type= " submit" icon= " i-heroicons-plus-20-solid" : loading= " loading" : disabled= " false " / >
108
+ <UButton type =" submit" icon =" i-heroicons-plus-20-solid" :loading =" loading" :disabled =" !newFilesValue.length " />
151
109
</div >
152
110
153
111
<div class =" grid grid-cols-1 md:grid-cols-3 gap-2" >
@@ -163,13 +121,13 @@ const items = [[{
163
121
class =" overflow-hidden relative"
164
122
>
165
123
<img v-if =" file.httpMetadata?.contentType?.startsWith('image/') && file.body" :src =" `data:${file.httpMetadata.contentType};base64,${(file.body)}`" class =" h-36 w-full object-cover" >
166
- < div v - else class = " h-36 w-full flex items-center justify-center" >
124
+ <div class =" h-36 w-full flex items-center justify-center p-2 text -center" >
167
125
{{ file.key }}
168
126
</div >
169
127
<div class =" flex flex-col gap-1 p-2 border-t border-gray-200 dark:border-gray-800" >
170
128
<span class =" text-sm font-medium" >{{ file.key }}</span >
171
- < div class = " flex items-center justify-between" >
172
- < span class = " text-xs" > {{ file .httpMetadata ? .contentType || ' -' }}< / span>
129
+ <div class =" flex items-center justify-between gap-1 " >
130
+ <span class =" text-xs truncate " >{{ file.httpMetadata?.contentType || '-' }}</span >
173
131
<span class =" text-xs" >{{ file.size ? `${Math.round(file.size / Math.pow(1024, 2) * 100) / 100}MB` : '-' }}</span >
174
132
</div >
175
133
</div >
0 commit comments