@cardinali-studio/adminkit 1.0.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/api.d.ts +195 -0
- package/dist/api.js +118 -0
- package/dist/app/App.d.ts +3 -0
- package/dist/app/App.js +320 -0
- package/dist/app/app.css +2068 -0
- package/dist/app/index.d.ts +18 -0
- package/dist/app/index.js +33 -0
- package/dist/app/lib/bookings.d.ts +132 -0
- package/dist/app/lib/bookings.js +79 -0
- package/dist/app/lib/deliveries.d.ts +95 -0
- package/dist/app/lib/deliveries.js +104 -0
- package/dist/app/lib/delivery-drop.d.ts +1 -0
- package/dist/app/lib/delivery-drop.js +72 -0
- package/dist/app/lib/delivery-upload.d.ts +78 -0
- package/dist/app/lib/delivery-upload.js +585 -0
- package/dist/app/lib/groups.d.ts +9 -0
- package/dist/app/lib/groups.js +32 -0
- package/dist/app/lib/home.d.ts +11 -0
- package/dist/app/lib/home.js +67 -0
- package/dist/app/lib/overview.d.ts +82 -0
- package/dist/app/lib/overview.js +68 -0
- package/dist/app/lib/pages.d.ts +24 -0
- package/dist/app/lib/pages.js +156 -0
- package/dist/app/lib/publish.d.ts +18 -0
- package/dist/app/lib/publish.js +63 -0
- package/dist/app/lib/reorder.d.ts +3 -0
- package/dist/app/lib/reorder.js +31 -0
- package/dist/app/lib/requests.d.ts +10 -0
- package/dist/app/lib/requests.js +67 -0
- package/dist/app/lib/router.d.ts +1 -0
- package/dist/app/lib/router.js +14 -0
- package/dist/app/lib/settings.d.ts +29 -0
- package/dist/app/lib/settings.js +82 -0
- package/dist/app/lib/slug.d.ts +3 -0
- package/dist/app/lib/slug.js +23 -0
- package/dist/app/lib/text.d.ts +1 -0
- package/dist/app/lib/text.js +13 -0
- package/dist/app/lib/theme.d.ts +7 -0
- package/dist/app/lib/theme.js +43 -0
- package/dist/app/lib/upload-queue.d.ts +35 -0
- package/dist/app/lib/upload-queue.js +167 -0
- package/dist/app/routes/AboutEditor.d.ts +15 -0
- package/dist/app/routes/AboutEditor.js +122 -0
- package/dist/app/routes/Bookings.d.ts +21 -0
- package/dist/app/routes/Bookings.js +134 -0
- package/dist/app/routes/Deliveries.d.ts +37 -0
- package/dist/app/routes/Deliveries.js +563 -0
- package/dist/app/routes/GallerySectionsEditor.d.ts +12 -0
- package/dist/app/routes/GallerySectionsEditor.js +107 -0
- package/dist/app/routes/HomeEditor.d.ts +10 -0
- package/dist/app/routes/HomeEditor.js +188 -0
- package/dist/app/routes/Overview.d.ts +17 -0
- package/dist/app/routes/Overview.js +318 -0
- package/dist/app/routes/PageActions.d.ts +12 -0
- package/dist/app/routes/PageActions.js +93 -0
- package/dist/app/routes/PageEditor.d.ts +23 -0
- package/dist/app/routes/PageEditor.js +233 -0
- package/dist/app/routes/PageSeoEditor.d.ts +13 -0
- package/dist/app/routes/PageSeoEditor.js +102 -0
- package/dist/app/routes/PagesList.d.ts +10 -0
- package/dist/app/routes/PagesList.js +76 -0
- package/dist/app/routes/PortfolioWorksEditor.d.ts +12 -0
- package/dist/app/routes/PortfolioWorksEditor.js +139 -0
- package/dist/app/routes/Requests.d.ts +13 -0
- package/dist/app/routes/Requests.js +30 -0
- package/dist/app/routes/SiteSettingsEditor.d.ts +21 -0
- package/dist/app/routes/SiteSettingsEditor.js +66 -0
- package/dist/app/routes/UploadDock.d.ts +1 -0
- package/dist/app/routes/UploadDock.js +66 -0
- package/dist/app/routes/WorkshopEditionsEditor.d.ts +12 -0
- package/dist/app/routes/WorkshopEditionsEditor.js +101 -0
- package/dist/app/site.d.ts +37 -0
- package/dist/app/site.js +18 -0
- package/dist/app/ui/MediaSlot.d.ts +10 -0
- package/dist/app/ui/MediaSlot.js +20 -0
- package/dist/app/ui/OpenCard.d.ts +18 -0
- package/dist/app/ui/OpenCard.js +20 -0
- package/dist/app/ui/ParagraphEditor.d.ts +8 -0
- package/dist/app/ui/ParagraphEditor.js +37 -0
- package/dist/app/ui/dnd.d.ts +1 -0
- package/dist/app/ui/dnd.js +11 -0
- package/dist/app/ui/icons.d.ts +26 -0
- package/dist/app/ui/icons.js +45 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +26 -0
- package/dist/form/MediaBrowser.d.ts +13 -0
- package/dist/form/MediaBrowser.js +24 -0
- package/dist/form/MediaPicker.d.ts +10 -0
- package/dist/form/MediaPicker.js +20 -0
- package/dist/form/SchemaForm.d.ts +21 -0
- package/dist/form/SchemaForm.js +67 -0
- package/dist/form/Trash.d.ts +1 -0
- package/dist/form/Trash.js +42 -0
- package/dist/form/fields/index.d.ts +1 -0
- package/dist/form/fields/index.js +110 -0
- package/dist/form/fields/objectList.d.ts +1 -0
- package/dist/form/fields/objectList.js +99 -0
- package/dist/form/index.d.ts +8 -0
- package/dist/form/index.js +8 -0
- package/dist/form/media/Lightbox.d.ts +4 -0
- package/dist/form/media/Lightbox.js +70 -0
- package/dist/form/media/MediaFolders.d.ts +20 -0
- package/dist/form/media/MediaFolders.js +116 -0
- package/dist/form/media/MediaGrid.d.ts +8 -0
- package/dist/form/media/MediaGrid.js +139 -0
- package/dist/form/media/UploadDialog.d.ts +4 -0
- package/dist/form/media/UploadDialog.js +37 -0
- package/dist/form/media/useMediaLibrary.d.ts +55 -0
- package/dist/form/media/useMediaLibrary.js +495 -0
- package/dist/form/prose/ProseBar.d.ts +21 -0
- package/dist/form/prose/ProseBar.js +111 -0
- package/dist/form/prose/ProseField.d.ts +11 -0
- package/dist/form/prose/ProseField.js +152 -0
- package/dist/form/prose/pages.d.ts +6 -0
- package/dist/form/prose/pages.js +13 -0
- package/dist/form/registry.d.ts +20 -0
- package/dist/form/registry.js +15 -0
- package/dist/frontmatter.d.ts +20 -0
- package/dist/frontmatter.js +202 -0
- package/dist/functions/_middleware.js +101 -0
- package/dist/functions/_shared/analytics-ga4.js +248 -0
- package/dist/functions/_shared/analytics-umami.js +119 -0
- package/dist/functions/_shared/assets.js +90 -0
- package/dist/functions/_shared/b2.js +300 -0
- package/dist/functions/_shared/delivery-crypto.js +99 -0
- package/dist/functions/_shared/delivery-purge.js +222 -0
- package/dist/functions/_shared/edge-cache.js +37 -0
- package/dist/functions/_shared/exif.js +53 -0
- package/dist/functions/_shared/github.js +138 -0
- package/dist/functions/_shared/imagesize.js +101 -0
- package/dist/functions/_shared/media-content.js +200 -0
- package/dist/functions/_shared/pending-media.js +98 -0
- package/dist/functions/_shared/refs.js +155 -0
- package/dist/functions/api/analytics.js +106 -0
- package/dist/functions/api/assets/delete.js +241 -0
- package/dist/functions/api/assets/folder.js +43 -0
- package/dist/functions/api/assets/folders.js +32 -0
- package/dist/functions/api/assets/move.js +253 -0
- package/dist/functions/api/assets/preview.js +17 -0
- package/dist/functions/api/assets/trash/delete.js +13 -0
- package/dist/functions/api/assets/trash/empty.js +16 -0
- package/dist/functions/api/assets/trash/restore.js +43 -0
- package/dist/functions/api/assets/trash.js +28 -0
- package/dist/functions/api/assets/upload.js +54 -0
- package/dist/functions/api/assets/usage.js +41 -0
- package/dist/functions/api/assets.js +94 -0
- package/dist/functions/api/deliveries.js +629 -0
- package/dist/functions/api/delivery/hero.js +21 -0
- package/dist/functions/api/delivery/image.js +35 -0
- package/dist/functions/api/delivery/multipart.js +261 -0
- package/dist/functions/api/pages/get.js +26 -0
- package/dist/functions/api/pages.js +354 -0
- package/dist/functions/api/publish.js +134 -0
- package/dist/functions/api/requests.js +57 -0
- package/dist/functions/api/settings.js +236 -0
- package/dist/functions/api/singleton.js +105 -0
- package/dist/functions/api/storage.js +125 -0
- package/dist/functions/index.js +124 -0
- package/dist/functions/site.js +38 -0
- package/dist/gallery.d.ts +28 -0
- package/dist/gallery.js +18 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/model.d.ts +2 -0
- package/dist/model.js +47 -0
- package/dist/normalize.d.ts +50 -0
- package/dist/normalize.js +120 -0
- package/dist/preview.d.ts +3 -0
- package/dist/preview.js +82 -0
- package/dist/prose.d.ts +17 -0
- package/dist/prose.js +205 -0
- package/dist/registries.d.ts +43 -0
- package/dist/registries.js +29 -0
- package/dist/serialize.d.ts +26 -0
- package/dist/serialize.js +136 -0
- package/dist/testing.d.ts +26 -0
- package/dist/testing.js +66 -0
- package/dist/theme.css +636 -0
- package/dist/yaml.d.ts +8 -0
- package/dist/yaml.js +90 -0
- package/package.json +97 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
code: string;
|
|
3
|
+
status: number;
|
|
4
|
+
constructor(message: string, code: string, status: number);
|
|
5
|
+
}
|
|
6
|
+
export interface AssetFile {
|
|
7
|
+
key: string;
|
|
8
|
+
name: string;
|
|
9
|
+
size: number;
|
|
10
|
+
url: string;
|
|
11
|
+
uploaded?: string;
|
|
12
|
+
capturedAt?: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
w?: number | null;
|
|
15
|
+
h?: number | null;
|
|
16
|
+
}
|
|
17
|
+
export interface AssetFolder {
|
|
18
|
+
prefix: string;
|
|
19
|
+
name: string;
|
|
20
|
+
count?: number;
|
|
21
|
+
label?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TrashItem {
|
|
24
|
+
trashKey: string;
|
|
25
|
+
originalKey: string;
|
|
26
|
+
name: string;
|
|
27
|
+
deletedAt?: string;
|
|
28
|
+
size: number;
|
|
29
|
+
type?: string;
|
|
30
|
+
previewUrl: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ContactRequestRow {
|
|
33
|
+
id: number;
|
|
34
|
+
name: string;
|
|
35
|
+
email: string;
|
|
36
|
+
message: string;
|
|
37
|
+
created_at: string;
|
|
38
|
+
handled_at: string | null;
|
|
39
|
+
}
|
|
40
|
+
/** Una pagina come arriva dall'elenco: identità, versione del file, e il modello. */
|
|
41
|
+
export interface RepoPage {
|
|
42
|
+
slug: string;
|
|
43
|
+
url: string;
|
|
44
|
+
/** Lo `sha` del blob su GitHub: identifica la VERSIONE di questo file, non il suo contenuto. */
|
|
45
|
+
sha: string;
|
|
46
|
+
page: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
export declare const api: {
|
|
49
|
+
pages: () => Promise<{
|
|
50
|
+
ok: true;
|
|
51
|
+
commit: string;
|
|
52
|
+
pages: RepoPage[];
|
|
53
|
+
}>;
|
|
54
|
+
pageBody: (slug: string) => Promise<{
|
|
55
|
+
ok: true;
|
|
56
|
+
slug: string;
|
|
57
|
+
body: string;
|
|
58
|
+
page: Record<string, unknown>;
|
|
59
|
+
}>;
|
|
60
|
+
savePages: (pages: unknown[]) => Promise<{
|
|
61
|
+
ok: true;
|
|
62
|
+
commit: string;
|
|
63
|
+
files: number;
|
|
64
|
+
skipped: string[];
|
|
65
|
+
shas?: Record<string, string>;
|
|
66
|
+
}>;
|
|
67
|
+
publishState: () => Promise<{
|
|
68
|
+
ok: true;
|
|
69
|
+
configured: boolean;
|
|
70
|
+
ahead: number;
|
|
71
|
+
behind: number;
|
|
72
|
+
error?: string;
|
|
73
|
+
commits: {
|
|
74
|
+
message: string;
|
|
75
|
+
date: string | null;
|
|
76
|
+
}[];
|
|
77
|
+
}>;
|
|
78
|
+
publish: () => Promise<{
|
|
79
|
+
ok: true;
|
|
80
|
+
published: boolean;
|
|
81
|
+
commit?: string;
|
|
82
|
+
message?: string;
|
|
83
|
+
}>;
|
|
84
|
+
assets: (prefix?: string, opts?: {
|
|
85
|
+
recursive?: boolean;
|
|
86
|
+
}) => Promise<{
|
|
87
|
+
ok: true;
|
|
88
|
+
prefix: string;
|
|
89
|
+
label?: string;
|
|
90
|
+
folders: AssetFolder[];
|
|
91
|
+
files: AssetFile[];
|
|
92
|
+
}>;
|
|
93
|
+
folders: () => Promise<{
|
|
94
|
+
ok: true;
|
|
95
|
+
folders: AssetFolder[];
|
|
96
|
+
}>;
|
|
97
|
+
/** `label` è il nome per esteso; lo slug della chiave lo calcola il server e lo restituisce. */
|
|
98
|
+
createFolder: (parent: string, name: string, opts?: {
|
|
99
|
+
label?: string;
|
|
100
|
+
relabel?: boolean;
|
|
101
|
+
}) => Promise<{
|
|
102
|
+
ok: true;
|
|
103
|
+
prefix: string;
|
|
104
|
+
exists?: boolean;
|
|
105
|
+
label?: string;
|
|
106
|
+
}>;
|
|
107
|
+
/** Con `skipRefs` copia senza cancellare gli originali e restituisce la mappa degli URL. */
|
|
108
|
+
move: (keys: string[], dest: string, opts?: {
|
|
109
|
+
skipRefs?: boolean;
|
|
110
|
+
}) => Promise<{
|
|
111
|
+
ok: true;
|
|
112
|
+
moved: number;
|
|
113
|
+
finalized?: number;
|
|
114
|
+
urlMap?: Record<string, string>;
|
|
115
|
+
pagesUpdated: string[];
|
|
116
|
+
failed: {
|
|
117
|
+
key: string;
|
|
118
|
+
error: string;
|
|
119
|
+
}[];
|
|
120
|
+
warning?: string;
|
|
121
|
+
}>;
|
|
122
|
+
/** Riscrive i riferimenti, poi elimina gli originali le cui copie sono state verificate. */
|
|
123
|
+
moveApplyRefs: (applyRefs: Record<string, string>) => Promise<{
|
|
124
|
+
ok: true;
|
|
125
|
+
moved: number;
|
|
126
|
+
finalized?: number;
|
|
127
|
+
pagesUpdated: string[];
|
|
128
|
+
failed: {
|
|
129
|
+
key: string;
|
|
130
|
+
error: string;
|
|
131
|
+
}[];
|
|
132
|
+
warning?: string;
|
|
133
|
+
}>;
|
|
134
|
+
usage: (target: {
|
|
135
|
+
keys?: string[];
|
|
136
|
+
prefixes?: string[];
|
|
137
|
+
}) => Promise<{
|
|
138
|
+
ok: true;
|
|
139
|
+
usage: Record<string, string[]>;
|
|
140
|
+
pages: string[];
|
|
141
|
+
count: number;
|
|
142
|
+
selectedCount: number;
|
|
143
|
+
blockers: {
|
|
144
|
+
path: string;
|
|
145
|
+
label: string;
|
|
146
|
+
reason: string;
|
|
147
|
+
}[];
|
|
148
|
+
}>;
|
|
149
|
+
remove: (target: {
|
|
150
|
+
keys?: string[];
|
|
151
|
+
prefixes?: string[];
|
|
152
|
+
}, opts?: {
|
|
153
|
+
refsOnly?: boolean;
|
|
154
|
+
skipRefs?: boolean;
|
|
155
|
+
refsToken?: string;
|
|
156
|
+
}) => Promise<{
|
|
157
|
+
ok: true;
|
|
158
|
+
trashed: number;
|
|
159
|
+
pagesUpdated: string[];
|
|
160
|
+
refsToken?: string;
|
|
161
|
+
}>;
|
|
162
|
+
requests: () => Promise<{
|
|
163
|
+
ok: true;
|
|
164
|
+
requests: ContactRequestRow[];
|
|
165
|
+
}>;
|
|
166
|
+
markRequest: (id: number, handled: boolean) => Promise<{
|
|
167
|
+
ok: true;
|
|
168
|
+
}>;
|
|
169
|
+
deleteRequest: (id: number) => Promise<{
|
|
170
|
+
ok: true;
|
|
171
|
+
}>;
|
|
172
|
+
/** L'upload NON è JSON: corpo grezzo e metadati negli header (vedi assets/upload.js). */
|
|
173
|
+
upload: (prefix: string, file: File) => Promise<AssetFile>;
|
|
174
|
+
trash: () => Promise<{
|
|
175
|
+
ok: true;
|
|
176
|
+
items: TrashItem[];
|
|
177
|
+
}>;
|
|
178
|
+
trashRestore: (trashKeys: string[]) => Promise<{
|
|
179
|
+
ok: true;
|
|
180
|
+
restored: string[];
|
|
181
|
+
conflicts: {
|
|
182
|
+
originalKey: string;
|
|
183
|
+
restoredAs: string;
|
|
184
|
+
}[];
|
|
185
|
+
}>;
|
|
186
|
+
trashDelete: (trashKeys: string[]) => Promise<{
|
|
187
|
+
ok: true;
|
|
188
|
+
removed: number;
|
|
189
|
+
}>;
|
|
190
|
+
trashEmpty: () => Promise<{
|
|
191
|
+
ok: true;
|
|
192
|
+
removed: number;
|
|
193
|
+
}>;
|
|
194
|
+
};
|
|
195
|
+
export declare function uploadQueue(prefix: string, files: File[], onProgress: (done: number, total: number, last?: AssetFile, error?: string) => void, concurrency?: number): Promise<AssetFile[]>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* Client tipizzato degli endpoint dell'admin. Un posto solo per sapere che forma hanno le
|
|
2
|
+
* risposte — e, soprattutto, per riconoscere i codici che il server ora sa distinguere:
|
|
3
|
+
* `unauthenticated` (sessione scaduta), `conflict` (qualcuno ha salvato nel frattempo),
|
|
4
|
+
* `unreadable` (un file che non sappiamo riprodurre). Prima qualunque errore diventava
|
|
5
|
+
* "backend non collegato", che manda a cercare il guasto dalla parte sbagliata. */
|
|
6
|
+
export class ApiError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
status;
|
|
9
|
+
constructor(message, code, status) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "ApiError";
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.status = status;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function call(url, init) {
|
|
17
|
+
const res = await fetch(url, { cache: "no-store", ...init });
|
|
18
|
+
let body = null;
|
|
19
|
+
try {
|
|
20
|
+
body = await res.json();
|
|
21
|
+
}
|
|
22
|
+
catch { /* risposta non JSON */ }
|
|
23
|
+
if (!res.ok || (body && body.ok === false)) {
|
|
24
|
+
const code = body?.code ?? (res.status === 401 ? "unauthenticated" : "error");
|
|
25
|
+
throw new ApiError(body?.error ?? `HTTP ${res.status}`, code, res.status);
|
|
26
|
+
}
|
|
27
|
+
return body;
|
|
28
|
+
}
|
|
29
|
+
const post = (url, data) => call(url, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "Content-Type": "application/json" },
|
|
32
|
+
body: JSON.stringify(data),
|
|
33
|
+
});
|
|
34
|
+
export const api = {
|
|
35
|
+
// ---- pagine
|
|
36
|
+
/* L'elenco viene DAL REPO, non da `/index.json`, che è il sito pubblicato e quindi indietro
|
|
37
|
+
* di una build. `sha` è quello del file su GitHub e torna indietro nel salvataggio: è il modo
|
|
38
|
+
* di accorgersi che qualcun altro ha toccato la stessa pagina nel frattempo. */
|
|
39
|
+
pages: () => call("/admin/api/pages"),
|
|
40
|
+
/* Il corpo markdown, che nell'elenco non c'è: sono testi lunghi e servono solo alla pagina
|
|
41
|
+
* che si sta aprendo. `page` è il modello letto dallo stesso file. */
|
|
42
|
+
pageBody: (slug) => call(`/admin/api/pages/get?slug=${encodeURIComponent(slug)}`),
|
|
43
|
+
/* `shas` è la versione di ogni file DOPO il commit: senza, il salvataggio successivo
|
|
44
|
+
* partirebbe da una versione che non esiste più e verrebbe rifiutato. */
|
|
45
|
+
savePages: (pages) => post("/admin/api/pages", { pages }),
|
|
46
|
+
// ---- pubblicazione
|
|
47
|
+
/* Salvare scrive sulla bozza e non fa partire nessuna build; è questo che manda online. Due
|
|
48
|
+
* gesti separati, quindi due chiamate: una chiede quanto c'è di non pubblicato, l'altra lo
|
|
49
|
+
* pubblica. */
|
|
50
|
+
publishState: () => call("/admin/api/publish"),
|
|
51
|
+
publish: () => post("/admin/api/publish", {}),
|
|
52
|
+
// ---- media
|
|
53
|
+
/* `recursive` scende a qualunque profondità e restituisce solo chiave e nome dei file: serve
|
|
54
|
+
* a spostare o cancellare una cartella intera senza lasciare indietro ciò che sta annidato. */
|
|
55
|
+
assets: (prefix = "", opts = {}) => call(`/admin/api/assets?prefix=${encodeURIComponent(prefix)}${opts.recursive ? "&recursive=1" : ""}`),
|
|
56
|
+
folders: () => call("/admin/api/assets/folders"),
|
|
57
|
+
/** `label` è il nome per esteso; lo slug della chiave lo calcola il server e lo restituisce. */
|
|
58
|
+
createFolder: (parent, name, opts = {}) => post("/admin/api/assets/folder", { parent, name, ...opts }),
|
|
59
|
+
/** Con `skipRefs` copia senza cancellare gli originali e restituisce la mappa degli URL. */
|
|
60
|
+
move: (keys, dest, opts = {}) => post("/admin/api/assets/move", { keys, dest, ...opts }),
|
|
61
|
+
/** Riscrive i riferimenti, poi elimina gli originali le cui copie sono state verificate. */
|
|
62
|
+
moveApplyRefs: (applyRefs) => post("/admin/api/assets/move", { applyRefs }),
|
|
63
|
+
usage: (target) => post("/admin/api/assets/usage", target),
|
|
64
|
+
/* `refsOnly` pulisce solo i riferimenti nelle pagine (un commit, niente file spostati);
|
|
65
|
+
* `skipRefs` sposta i file e non tocca il repo. Servono a spezzare una cancellazione grande
|
|
66
|
+
* in più richieste senza fare un commit — cioè una build — per ogni gruppo. */
|
|
67
|
+
remove: (target, opts = {}) => post("/admin/api/assets/delete", { ...target, ...opts }),
|
|
68
|
+
// ---- richieste dal form di contatto
|
|
69
|
+
requests: () => call("/admin/api/requests"),
|
|
70
|
+
markRequest: (id, handled) => call("/admin/api/requests", {
|
|
71
|
+
method: "PATCH",
|
|
72
|
+
headers: { "Content-Type": "application/json" },
|
|
73
|
+
body: JSON.stringify({ id, handled }),
|
|
74
|
+
}),
|
|
75
|
+
deleteRequest: (id) => call("/admin/api/requests", {
|
|
76
|
+
method: "DELETE",
|
|
77
|
+
headers: { "Content-Type": "application/json" },
|
|
78
|
+
body: JSON.stringify({ id }),
|
|
79
|
+
}),
|
|
80
|
+
/** L'upload NON è JSON: corpo grezzo e metadati negli header (vedi assets/upload.js). */
|
|
81
|
+
upload: (prefix, file) => call("/admin/api/assets/upload", {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: {
|
|
84
|
+
"Content-Type": file.type || "application/octet-stream",
|
|
85
|
+
"X-Prefix": prefix,
|
|
86
|
+
"X-Filename": encodeURIComponent(file.name),
|
|
87
|
+
},
|
|
88
|
+
body: file,
|
|
89
|
+
}),
|
|
90
|
+
// ---- cestino
|
|
91
|
+
trash: () => call("/admin/api/assets/trash"),
|
|
92
|
+
trashRestore: (trashKeys) => post("/admin/api/assets/trash/restore", { trashKeys }),
|
|
93
|
+
trashDelete: (trashKeys) => post("/admin/api/assets/trash/delete", { trashKeys }),
|
|
94
|
+
trashEmpty: () => post("/admin/api/assets/trash/empty", {}),
|
|
95
|
+
};
|
|
96
|
+
/* Coda di upload a concorrenza limitata. Il vecchio admin caricava un file alla volta
|
|
97
|
+
* (app.js:922), il che su quaranta foto è tedioso senza motivo; tutte insieme invece saturano
|
|
98
|
+
* la connessione e rendono il progresso illeggibile. Tre è il compromesso.
|
|
99
|
+
* Un file che fallisce non ferma gli altri: si segnala e si prosegue. */
|
|
100
|
+
export async function uploadQueue(prefix, files, onProgress, concurrency = 3) {
|
|
101
|
+
const out = [];
|
|
102
|
+
let done = 0, next = 0;
|
|
103
|
+
const worker = async () => {
|
|
104
|
+
while (next < files.length) {
|
|
105
|
+
const file = files[next++];
|
|
106
|
+
try {
|
|
107
|
+
const r = await api.upload(prefix, file);
|
|
108
|
+
out.push(r);
|
|
109
|
+
onProgress(++done, files.length, r);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
onProgress(++done, files.length, undefined, `${file.name}: ${e.message}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, files.length) }, worker));
|
|
117
|
+
return out;
|
|
118
|
+
}
|