@axium/storage 0.19.0 → 0.19.2
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/db.json +10 -0
- package/dist/common.d.ts +2 -0
- package/dist/server/item.js +8 -1
- package/lib/Add.svelte +1 -1
- package/lib/List.svelte +51 -8
- package/package.json +2 -2
- package/routes/files/[id]/+page.svelte +7 -3
package/db.json
CHANGED
|
@@ -79,6 +79,16 @@
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"delta": true,
|
|
85
|
+
"alter_tables": {
|
|
86
|
+
"storage": {
|
|
87
|
+
"add_constraints": {
|
|
88
|
+
"unique_name_parentId": { "type": "unique", "on": ["name", "parentId"] }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
],
|
|
84
94
|
"wipe": ["storage", "acl.storage"],
|
package/dist/common.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ export declare const StorageItemSorting: z.ZodObject<{
|
|
|
61
61
|
descending: z.ZodOptional<z.ZodBoolean>;
|
|
62
62
|
by: z.ZodLiteral<"name" | "createdAt" | "modifiedAt" | "size">;
|
|
63
63
|
}, z.core.$strip>;
|
|
64
|
+
export interface StorageItemSorting extends z.infer<typeof StorageItemSorting> {
|
|
65
|
+
}
|
|
64
66
|
export declare const syncProtocolVersion = 0;
|
|
65
67
|
export declare const StorageLimits: z.ZodObject<{
|
|
66
68
|
item_size: z.ZodInt;
|
package/dist/server/item.js
CHANGED
|
@@ -77,7 +77,14 @@ export async function createNewItem(init, userId, writeContent) {
|
|
|
77
77
|
hash,
|
|
78
78
|
})
|
|
79
79
|
.returningAll()
|
|
80
|
-
.executeTakeFirstOrThrow()
|
|
80
|
+
.executeTakeFirstOrThrow()
|
|
81
|
+
.catch(e => {
|
|
82
|
+
if (!(e instanceof Error))
|
|
83
|
+
throw e;
|
|
84
|
+
if (e.message.includes('unique_name_parentId') && e.message.includes('duplicate'))
|
|
85
|
+
error(409, 'A file with that name already exists in this folder.');
|
|
86
|
+
throw e;
|
|
87
|
+
}));
|
|
81
88
|
const path = join(dataDir, item.id);
|
|
82
89
|
if (existing)
|
|
83
90
|
linkSync(join(dataDir, existing.id), path);
|
package/lib/Add.svelte
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
<Popover>
|
|
34
34
|
{#snippet toggle()}
|
|
35
|
-
<button class="icon-text"><Icon i="plus" />{text('storage.Add.text')}</button>
|
|
35
|
+
<button class="icon-text StorageAdd"><Icon i="plus" />{text('storage.Add.text')}</button>
|
|
36
36
|
{/snippet}
|
|
37
37
|
|
|
38
38
|
<span class="menu-item" onclick={() => uploadDialog.showModal()}><Icon i="upload" />{text('storage.Add.upload')}</span>
|
package/lib/List.svelte
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { text } from '@axium/client';
|
|
3
|
-
import { contextMenu } from '@axium/client/attachments';
|
|
3
|
+
import { closeOnBackGesture, contextMenu } from '@axium/client/attachments';
|
|
4
4
|
import { AccessControlDialog, FormDialog, Icon } from '@axium/client/components';
|
|
5
|
+
import { copy } from '@axium/client/gui';
|
|
5
6
|
import '@axium/client/styles/list';
|
|
6
7
|
import type { AccessControllable, UserPublic } from '@axium/core';
|
|
7
8
|
import { formatBytes } from '@axium/core/format';
|
|
8
9
|
import { forMime as iconForMime } from '@axium/core/icons';
|
|
10
|
+
import { errorText } from '@axium/core/io';
|
|
9
11
|
import { getDirectoryMetadata, updateItemMetadata } from '@axium/storage/client';
|
|
10
12
|
import { copyShortURL, formatItemName } from '@axium/storage/client/frontend';
|
|
11
|
-
import type
|
|
13
|
+
import { StorageItemSorting, type StorageItemMetadata } from '@axium/storage/common';
|
|
12
14
|
import Preview from './Preview.svelte';
|
|
13
|
-
import { copy } from '@axium/client/gui';
|
|
14
15
|
|
|
15
16
|
let {
|
|
16
17
|
items = $bindable(),
|
|
@@ -23,6 +24,31 @@
|
|
|
23
24
|
const activeItem = $derived(items[activeIndex]);
|
|
24
25
|
const activeItemName = $derived(formatItemName(activeItem));
|
|
25
26
|
const dialogs = $state<Record<string, HTMLDialogElement>>({});
|
|
27
|
+
|
|
28
|
+
const search = new URLSearchParams(location.search);
|
|
29
|
+
let sort = $state<StorageItemSorting | null>();
|
|
30
|
+
try {
|
|
31
|
+
sort = StorageItemSorting.parse({
|
|
32
|
+
by: search.get('sortBy'),
|
|
33
|
+
descending: search.has('descending'),
|
|
34
|
+
});
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.log('Ignoring invalid sorting parameters', errorText(e));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const sortedItems = $derived(
|
|
40
|
+
items
|
|
41
|
+
.map((item, i) => [item, i] as const)
|
|
42
|
+
.toSorted(
|
|
43
|
+
sort
|
|
44
|
+
? ([_a], [_b]) => {
|
|
45
|
+
const [a, b] = sort?.descending ? [_b, _a] : [_a, _b];
|
|
46
|
+
// @ts-expect-error 2362 — `Date`s have a `valueOf` and can be treated like numbers
|
|
47
|
+
return sort.by == 'name' ? a.name.localeCompare(b.name) : a[sort.by] - b[sort.by];
|
|
48
|
+
}
|
|
49
|
+
: undefined
|
|
50
|
+
)
|
|
51
|
+
);
|
|
26
52
|
</script>
|
|
27
53
|
|
|
28
54
|
{#snippet action(name: string, icon: string, i: number, preview: boolean = false)}
|
|
@@ -40,11 +66,19 @@
|
|
|
40
66
|
<div class="list">
|
|
41
67
|
<div class="list-item list-header">
|
|
42
68
|
<span></span>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
69
|
+
{#each [['name', 'storage.generic.name'], ['modifiedAt', 'storage.List.last_modified'], ['size', 'storage.List.size']] as const as [key, translation]}
|
|
70
|
+
<span
|
|
71
|
+
class="header-column"
|
|
72
|
+
onclick={() => (sort = sort?.descending === false ? null : { by: key, descending: !sort?.descending })}
|
|
73
|
+
>
|
|
74
|
+
{#if sort?.by == key}
|
|
75
|
+
<Icon i="sort-{sort.descending ? 'down' : 'up'}" />
|
|
76
|
+
{/if}
|
|
77
|
+
<span>{text(translation)}</span>
|
|
78
|
+
</span>
|
|
79
|
+
{/each}
|
|
46
80
|
</div>
|
|
47
|
-
{#each
|
|
81
|
+
{#each sortedItems as [item, i] (item.id)}
|
|
48
82
|
<div
|
|
49
83
|
class="list-item"
|
|
50
84
|
onclick={async () => {
|
|
@@ -107,7 +141,7 @@
|
|
|
107
141
|
{/each}
|
|
108
142
|
</div>
|
|
109
143
|
|
|
110
|
-
<dialog bind:this={dialogs.preview} class="preview" onclick={e => e.stopPropagation()}>
|
|
144
|
+
<dialog bind:this={dialogs.preview} class="preview" onclick={e => e.stopPropagation()} {@attach closeOnBackGesture}>
|
|
111
145
|
{#if activeItem}
|
|
112
146
|
<Preview
|
|
113
147
|
item={activeItem}
|
|
@@ -167,6 +201,15 @@
|
|
|
167
201
|
grid-template-columns: 1em 4fr 15em 5em repeat(4, 1em);
|
|
168
202
|
}
|
|
169
203
|
|
|
204
|
+
.header-column {
|
|
205
|
+
display: inline-flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
|
|
208
|
+
&:hover {
|
|
209
|
+
cursor: pointer;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
170
213
|
@media (width < 700px) {
|
|
171
214
|
.item-actions {
|
|
172
215
|
display: none;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/storage",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
4
4
|
"author": "James Prevett <axium@jamespre.dev>",
|
|
5
5
|
"description": "User file storage for Axium",
|
|
6
6
|
"funding": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"build": "tsc"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@axium/client": ">=0.
|
|
43
|
+
"@axium/client": ">=0.19.0",
|
|
44
44
|
"@axium/core": ">=0.19.0",
|
|
45
45
|
"@axium/server": ">=0.39.0",
|
|
46
46
|
"@sveltejs/kit": "^2.27.3",
|