@adminforth/upload 2.8.7 → 2.10.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/build.log +2 -2
- package/custom/imageGenerator.vue +4 -22
- package/custom/package-lock.json +65 -0
- package/custom/package.json +1 -0
- package/dist/custom/imageGenerator.vue +4 -22
- package/dist/custom/package-lock.json +65 -0
- package/dist/custom/package.json +1 -0
- package/dist/index.js +129 -21
- package/index.ts +146 -12
- package/package.json +1 -1
- package/types.ts +0 -6
package/build.log
CHANGED
|
@@ -11,5 +11,5 @@ custom/preview.vue
|
|
|
11
11
|
custom/tsconfig.json
|
|
12
12
|
custom/uploader.vue
|
|
13
13
|
|
|
14
|
-
sent
|
|
15
|
-
total size is
|
|
14
|
+
sent 53,885 bytes received 134 bytes 108,038.00 bytes/sec
|
|
15
|
+
total size is 53,396 speedup is 0.99
|
|
@@ -181,6 +181,7 @@ import { callAdminForthApi } from '@/utils';
|
|
|
181
181
|
import { useI18n } from 'vue-i18n';
|
|
182
182
|
import adminforth from '@/adminforth';
|
|
183
183
|
import { ProgressBar } from '@/afcl';
|
|
184
|
+
import * as Handlebars from 'handlebars';
|
|
184
185
|
|
|
185
186
|
const { t: $t } = useI18n();
|
|
186
187
|
|
|
@@ -214,28 +215,9 @@ onMounted(async () => {
|
|
|
214
215
|
}
|
|
215
216
|
// iterate over all variables in template and replace them with their values from props.record[field].
|
|
216
217
|
// if field is not present in props.record[field] then replace it with empty string and drop warning
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
matches.forEach((match) => {
|
|
221
|
-
const field = match.replace(/{{|}}/g, '').trim();
|
|
222
|
-
if (field in context) {
|
|
223
|
-
return;
|
|
224
|
-
} else if (field in props.record) {
|
|
225
|
-
context[field] = minifyField(props.record[field]);
|
|
226
|
-
} else {
|
|
227
|
-
adminforth.alert({
|
|
228
|
-
message: $t('Field {{field}} defined in template but not found in record', { field }),
|
|
229
|
-
variant: 'warning',
|
|
230
|
-
timeout: 15,
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
prompt.value = template.replace(regex, (_, field) => {
|
|
237
|
-
return context[field.trim()] || '';
|
|
238
|
-
});
|
|
218
|
+
const tpl = Handlebars.compile(template);
|
|
219
|
+
const compiledTemplate = tpl(props.record);
|
|
220
|
+
prompt.value = compiledTemplate;
|
|
239
221
|
|
|
240
222
|
const recordId = props.record[props.meta.recorPkFieldName];
|
|
241
223
|
if (!recordId) return;
|
package/custom/package-lock.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@iconify-prerendered/vue-mdi": "^0.25.1718880438",
|
|
13
|
+
"handlebars": "^4.7.8",
|
|
13
14
|
"medium-zoom": "^1.1.0"
|
|
14
15
|
}
|
|
15
16
|
},
|
|
@@ -201,6 +202,27 @@
|
|
|
201
202
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
|
202
203
|
"peer": true
|
|
203
204
|
},
|
|
205
|
+
"node_modules/handlebars": {
|
|
206
|
+
"version": "4.7.8",
|
|
207
|
+
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
|
208
|
+
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
|
209
|
+
"license": "MIT",
|
|
210
|
+
"dependencies": {
|
|
211
|
+
"minimist": "^1.2.5",
|
|
212
|
+
"neo-async": "^2.6.2",
|
|
213
|
+
"source-map": "^0.6.1",
|
|
214
|
+
"wordwrap": "^1.0.0"
|
|
215
|
+
},
|
|
216
|
+
"bin": {
|
|
217
|
+
"handlebars": "bin/handlebars"
|
|
218
|
+
},
|
|
219
|
+
"engines": {
|
|
220
|
+
"node": ">=0.4.7"
|
|
221
|
+
},
|
|
222
|
+
"optionalDependencies": {
|
|
223
|
+
"uglify-js": "^3.1.4"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
204
226
|
"node_modules/magic-string": {
|
|
205
227
|
"version": "0.30.11",
|
|
206
228
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
|
@@ -215,6 +237,15 @@
|
|
|
215
237
|
"resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz",
|
|
216
238
|
"integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ=="
|
|
217
239
|
},
|
|
240
|
+
"node_modules/minimist": {
|
|
241
|
+
"version": "1.2.8",
|
|
242
|
+
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
|
243
|
+
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
|
244
|
+
"license": "MIT",
|
|
245
|
+
"funding": {
|
|
246
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
218
249
|
"node_modules/nanoid": {
|
|
219
250
|
"version": "3.3.7",
|
|
220
251
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
|
@@ -233,6 +264,12 @@
|
|
|
233
264
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
|
234
265
|
}
|
|
235
266
|
},
|
|
267
|
+
"node_modules/neo-async": {
|
|
268
|
+
"version": "2.6.2",
|
|
269
|
+
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
|
270
|
+
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
|
271
|
+
"license": "MIT"
|
|
272
|
+
},
|
|
236
273
|
"node_modules/picocolors": {
|
|
237
274
|
"version": "1.1.0",
|
|
238
275
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
|
@@ -267,6 +304,15 @@
|
|
|
267
304
|
"node": "^10 || ^12 || >=14"
|
|
268
305
|
}
|
|
269
306
|
},
|
|
307
|
+
"node_modules/source-map": {
|
|
308
|
+
"version": "0.6.1",
|
|
309
|
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
310
|
+
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
|
311
|
+
"license": "BSD-3-Clause",
|
|
312
|
+
"engines": {
|
|
313
|
+
"node": ">=0.10.0"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
270
316
|
"node_modules/source-map-js": {
|
|
271
317
|
"version": "1.2.1",
|
|
272
318
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
|
@@ -285,6 +331,19 @@
|
|
|
285
331
|
"node": ">=4"
|
|
286
332
|
}
|
|
287
333
|
},
|
|
334
|
+
"node_modules/uglify-js": {
|
|
335
|
+
"version": "3.19.3",
|
|
336
|
+
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
|
|
337
|
+
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
|
|
338
|
+
"license": "BSD-2-Clause",
|
|
339
|
+
"optional": true,
|
|
340
|
+
"bin": {
|
|
341
|
+
"uglifyjs": "bin/uglifyjs"
|
|
342
|
+
},
|
|
343
|
+
"engines": {
|
|
344
|
+
"node": ">=0.8.0"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
288
347
|
"node_modules/vue": {
|
|
289
348
|
"version": "3.5.10",
|
|
290
349
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.10.tgz",
|
|
@@ -305,6 +364,12 @@
|
|
|
305
364
|
"optional": true
|
|
306
365
|
}
|
|
307
366
|
}
|
|
367
|
+
},
|
|
368
|
+
"node_modules/wordwrap": {
|
|
369
|
+
"version": "1.0.0",
|
|
370
|
+
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
|
371
|
+
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
|
|
372
|
+
"license": "MIT"
|
|
308
373
|
}
|
|
309
374
|
}
|
|
310
375
|
}
|
package/custom/package.json
CHANGED
|
@@ -181,6 +181,7 @@ import { callAdminForthApi } from '@/utils';
|
|
|
181
181
|
import { useI18n } from 'vue-i18n';
|
|
182
182
|
import adminforth from '@/adminforth';
|
|
183
183
|
import { ProgressBar } from '@/afcl';
|
|
184
|
+
import * as Handlebars from 'handlebars';
|
|
184
185
|
|
|
185
186
|
const { t: $t } = useI18n();
|
|
186
187
|
|
|
@@ -214,28 +215,9 @@ onMounted(async () => {
|
|
|
214
215
|
}
|
|
215
216
|
// iterate over all variables in template and replace them with their values from props.record[field].
|
|
216
217
|
// if field is not present in props.record[field] then replace it with empty string and drop warning
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
matches.forEach((match) => {
|
|
221
|
-
const field = match.replace(/{{|}}/g, '').trim();
|
|
222
|
-
if (field in context) {
|
|
223
|
-
return;
|
|
224
|
-
} else if (field in props.record) {
|
|
225
|
-
context[field] = minifyField(props.record[field]);
|
|
226
|
-
} else {
|
|
227
|
-
adminforth.alert({
|
|
228
|
-
message: $t('Field {{field}} defined in template but not found in record', { field }),
|
|
229
|
-
variant: 'warning',
|
|
230
|
-
timeout: 15,
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
prompt.value = template.replace(regex, (_, field) => {
|
|
237
|
-
return context[field.trim()] || '';
|
|
238
|
-
});
|
|
218
|
+
const tpl = Handlebars.compile(template);
|
|
219
|
+
const compiledTemplate = tpl(props.record);
|
|
220
|
+
prompt.value = compiledTemplate;
|
|
239
221
|
|
|
240
222
|
const recordId = props.record[props.meta.recorPkFieldName];
|
|
241
223
|
if (!recordId) return;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@iconify-prerendered/vue-mdi": "^0.25.1718880438",
|
|
13
|
+
"handlebars": "^4.7.8",
|
|
13
14
|
"medium-zoom": "^1.1.0"
|
|
14
15
|
}
|
|
15
16
|
},
|
|
@@ -201,6 +202,27 @@
|
|
|
201
202
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
|
202
203
|
"peer": true
|
|
203
204
|
},
|
|
205
|
+
"node_modules/handlebars": {
|
|
206
|
+
"version": "4.7.8",
|
|
207
|
+
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
|
208
|
+
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
|
209
|
+
"license": "MIT",
|
|
210
|
+
"dependencies": {
|
|
211
|
+
"minimist": "^1.2.5",
|
|
212
|
+
"neo-async": "^2.6.2",
|
|
213
|
+
"source-map": "^0.6.1",
|
|
214
|
+
"wordwrap": "^1.0.0"
|
|
215
|
+
},
|
|
216
|
+
"bin": {
|
|
217
|
+
"handlebars": "bin/handlebars"
|
|
218
|
+
},
|
|
219
|
+
"engines": {
|
|
220
|
+
"node": ">=0.4.7"
|
|
221
|
+
},
|
|
222
|
+
"optionalDependencies": {
|
|
223
|
+
"uglify-js": "^3.1.4"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
204
226
|
"node_modules/magic-string": {
|
|
205
227
|
"version": "0.30.11",
|
|
206
228
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
|
@@ -215,6 +237,15 @@
|
|
|
215
237
|
"resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz",
|
|
216
238
|
"integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ=="
|
|
217
239
|
},
|
|
240
|
+
"node_modules/minimist": {
|
|
241
|
+
"version": "1.2.8",
|
|
242
|
+
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
|
243
|
+
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
|
244
|
+
"license": "MIT",
|
|
245
|
+
"funding": {
|
|
246
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
218
249
|
"node_modules/nanoid": {
|
|
219
250
|
"version": "3.3.7",
|
|
220
251
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
|
@@ -233,6 +264,12 @@
|
|
|
233
264
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
|
234
265
|
}
|
|
235
266
|
},
|
|
267
|
+
"node_modules/neo-async": {
|
|
268
|
+
"version": "2.6.2",
|
|
269
|
+
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
|
270
|
+
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
|
271
|
+
"license": "MIT"
|
|
272
|
+
},
|
|
236
273
|
"node_modules/picocolors": {
|
|
237
274
|
"version": "1.1.0",
|
|
238
275
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
|
@@ -267,6 +304,15 @@
|
|
|
267
304
|
"node": "^10 || ^12 || >=14"
|
|
268
305
|
}
|
|
269
306
|
},
|
|
307
|
+
"node_modules/source-map": {
|
|
308
|
+
"version": "0.6.1",
|
|
309
|
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
|
310
|
+
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
|
311
|
+
"license": "BSD-3-Clause",
|
|
312
|
+
"engines": {
|
|
313
|
+
"node": ">=0.10.0"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
270
316
|
"node_modules/source-map-js": {
|
|
271
317
|
"version": "1.2.1",
|
|
272
318
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
|
@@ -285,6 +331,19 @@
|
|
|
285
331
|
"node": ">=4"
|
|
286
332
|
}
|
|
287
333
|
},
|
|
334
|
+
"node_modules/uglify-js": {
|
|
335
|
+
"version": "3.19.3",
|
|
336
|
+
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
|
|
337
|
+
"integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
|
|
338
|
+
"license": "BSD-2-Clause",
|
|
339
|
+
"optional": true,
|
|
340
|
+
"bin": {
|
|
341
|
+
"uglifyjs": "bin/uglifyjs"
|
|
342
|
+
},
|
|
343
|
+
"engines": {
|
|
344
|
+
"node": ">=0.8.0"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
288
347
|
"node_modules/vue": {
|
|
289
348
|
"version": "3.5.10",
|
|
290
349
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.10.tgz",
|
|
@@ -305,6 +364,12 @@
|
|
|
305
364
|
"optional": true
|
|
306
365
|
}
|
|
307
366
|
}
|
|
367
|
+
},
|
|
368
|
+
"node_modules/wordwrap": {
|
|
369
|
+
"version": "1.0.0",
|
|
370
|
+
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
|
371
|
+
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
|
|
372
|
+
"license": "MIT"
|
|
308
373
|
}
|
|
309
374
|
}
|
|
310
375
|
}
|
package/dist/custom/package.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -7,9 +7,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { AdminForthPlugin, Filters, suggestIfTypo } from "adminforth";
|
|
10
|
+
import { AdminForthPlugin, Filters, suggestIfTypo, RateLimiter } from "adminforth";
|
|
11
11
|
import { Readable } from "stream";
|
|
12
|
-
import { RateLimiter } from "adminforth";
|
|
13
12
|
import { randomUUID } from "crypto";
|
|
14
13
|
import { interpretResource } from 'adminforth';
|
|
15
14
|
import { ActionCheckSource } from 'adminforth';
|
|
@@ -186,7 +185,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
186
185
|
modifyResourceConfig: { get: () => super.modifyResourceConfig }
|
|
187
186
|
});
|
|
188
187
|
return __awaiter(this, void 0, void 0, function* () {
|
|
189
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j
|
|
188
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
190
189
|
_super.modifyResourceConfig.call(this, adminforth, resourceConfig);
|
|
191
190
|
this.resourceConfig = resourceConfig;
|
|
192
191
|
// after column to store the path of the uploaded file, add new VirtualColumn,
|
|
@@ -197,15 +196,6 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
197
196
|
if (pathColumnIndex === -1) {
|
|
198
197
|
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.label}"`);
|
|
199
198
|
}
|
|
200
|
-
if ((_a = this.options.generation) === null || _a === void 0 ? void 0 : _a.fieldsForContext) {
|
|
201
|
-
(_b = this.options.generation) === null || _b === void 0 ? void 0 : _b.fieldsForContext.forEach((field) => {
|
|
202
|
-
if (!resourceConfig.columns.find((column) => column.name === field)) {
|
|
203
|
-
const similar = suggestIfTypo(resourceConfig.columns.map((column) => column.name), field);
|
|
204
|
-
throw new Error(`Field "${field}" specified in fieldsForContext not found in
|
|
205
|
-
resource "${resourceConfig.label}". ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
199
|
const pluginFrontendOptions = {
|
|
210
200
|
allowedExtensions: this.options.allowedFileExtensions,
|
|
211
201
|
maxFileSize: this.options.maxFileSize,
|
|
@@ -213,14 +203,14 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
213
203
|
resourceLabel: resourceConfig.label,
|
|
214
204
|
generateImages: this.options.generation ? true : false,
|
|
215
205
|
pathColumnLabel: resourceConfig.columns[pathColumnIndex].label,
|
|
216
|
-
maxWidth: (
|
|
217
|
-
maxListWidth: (
|
|
218
|
-
maxShowWidth: (
|
|
219
|
-
minWidth: (
|
|
220
|
-
minListWidth: (
|
|
221
|
-
minShowWidth: (
|
|
222
|
-
generationPrompt: (
|
|
223
|
-
recorPkFieldName: (
|
|
206
|
+
maxWidth: (_a = this.options.preview) === null || _a === void 0 ? void 0 : _a.maxWidth,
|
|
207
|
+
maxListWidth: (_b = this.options.preview) === null || _b === void 0 ? void 0 : _b.maxListWidth,
|
|
208
|
+
maxShowWidth: (_c = this.options.preview) === null || _c === void 0 ? void 0 : _c.maxShowWidth,
|
|
209
|
+
minWidth: (_d = this.options.preview) === null || _d === void 0 ? void 0 : _d.minWidth,
|
|
210
|
+
minListWidth: (_e = this.options.preview) === null || _e === void 0 ? void 0 : _e.minListWidth,
|
|
211
|
+
minShowWidth: (_f = this.options.preview) === null || _f === void 0 ? void 0 : _f.minShowWidth,
|
|
212
|
+
generationPrompt: (_g = this.options.generation) === null || _g === void 0 ? void 0 : _g.generationPrompt,
|
|
213
|
+
recorPkFieldName: (_h = this.resourceConfig.columns.find((column) => column.primaryKey)) === null || _h === void 0 ? void 0 : _h.name,
|
|
224
214
|
pathColumnName: this.options.pathColumnName,
|
|
225
215
|
};
|
|
226
216
|
// define components which will be imported from other components
|
|
@@ -230,7 +220,7 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
230
220
|
}
|
|
231
221
|
const pathColumn = resourceConfig.columns[pathColumnIndex];
|
|
232
222
|
// add preview column to list
|
|
233
|
-
if (((
|
|
223
|
+
if (((_j = this.options.preview) === null || _j === void 0 ? void 0 : _j.usePreviewComponents) !== false) {
|
|
234
224
|
resourceConfig.columns[pathColumnIndex].components.list = {
|
|
235
225
|
file: this.componentPath('preview.vue'),
|
|
236
226
|
meta: pluginFrontendOptions,
|
|
@@ -333,7 +323,28 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
333
323
|
});
|
|
334
324
|
}
|
|
335
325
|
validateConfigAfterDiscover(adminforth, resourceConfig) {
|
|
326
|
+
var _a;
|
|
336
327
|
this.adminforth = adminforth;
|
|
328
|
+
if (this.options.generation) {
|
|
329
|
+
const template = (_a = this.options.generation) === null || _a === void 0 ? void 0 : _a.generationPrompt;
|
|
330
|
+
const regex = /{{(.*?)}}/g;
|
|
331
|
+
const matches = template.match(regex);
|
|
332
|
+
if (matches) {
|
|
333
|
+
matches.forEach((match) => {
|
|
334
|
+
const field = match.replace(/{{|}}/g, '').trim();
|
|
335
|
+
if (!resourceConfig.columns.find((column) => column.name === field)) {
|
|
336
|
+
const similar = suggestIfTypo(resourceConfig.columns.map((column) => column.name), field);
|
|
337
|
+
throw new Error(`Field "${field}" specified in generationPrompt not found in resource "${resourceConfig.label}". ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
let column = resourceConfig.columns.find((column) => column.name === field);
|
|
341
|
+
if (column.backendOnly === true) {
|
|
342
|
+
throw new Error(`Field "${field}" specified in generationPrompt is marked as backendOnly in resource "${resourceConfig.label}". Please remove backendOnly or choose another field.`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
337
348
|
// called here because modifyResourceConfig can be called in build time where there is no environment and AWS secrets
|
|
338
349
|
this.setupLifecycleRule();
|
|
339
350
|
}
|
|
@@ -471,4 +482,101 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
471
482
|
}),
|
|
472
483
|
});
|
|
473
484
|
}
|
|
485
|
+
uploadFromBuffer(_a) {
|
|
486
|
+
return __awaiter(this, arguments, void 0, function* ({ filename, contentType, buffer, adminUser, extra, }) {
|
|
487
|
+
var _b;
|
|
488
|
+
if (!filename || !contentType || !buffer) {
|
|
489
|
+
throw new Error('filename, contentType and buffer are required');
|
|
490
|
+
}
|
|
491
|
+
const lastDotIndex = filename.lastIndexOf('.');
|
|
492
|
+
if (lastDotIndex === -1) {
|
|
493
|
+
throw new Error('filename must contain an extension');
|
|
494
|
+
}
|
|
495
|
+
const originalExtension = filename.substring(lastDotIndex + 1).toLowerCase();
|
|
496
|
+
const originalFilename = filename.substring(0, lastDotIndex);
|
|
497
|
+
if (this.options.allowedFileExtensions && !this.options.allowedFileExtensions.includes(originalExtension)) {
|
|
498
|
+
throw new Error(`File extension "${originalExtension}" is not allowed, allowed extensions are: ${this.options.allowedFileExtensions.join(', ')}`);
|
|
499
|
+
}
|
|
500
|
+
let nodeBuffer;
|
|
501
|
+
if (Buffer.isBuffer(buffer)) {
|
|
502
|
+
nodeBuffer = buffer;
|
|
503
|
+
}
|
|
504
|
+
else if (buffer instanceof ArrayBuffer) {
|
|
505
|
+
nodeBuffer = Buffer.from(buffer);
|
|
506
|
+
}
|
|
507
|
+
else if (ArrayBuffer.isView(buffer)) {
|
|
508
|
+
nodeBuffer = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
throw new Error('Unsupported buffer type');
|
|
512
|
+
}
|
|
513
|
+
const size = nodeBuffer.byteLength;
|
|
514
|
+
if (this.options.maxFileSize && size > this.options.maxFileSize) {
|
|
515
|
+
throw new Error(`File size ${size} is too large. Maximum allowed size is ${this.options.maxFileSize}`);
|
|
516
|
+
}
|
|
517
|
+
const filePath = this.options.filePath({
|
|
518
|
+
originalFilename,
|
|
519
|
+
originalExtension,
|
|
520
|
+
contentType,
|
|
521
|
+
record: undefined,
|
|
522
|
+
});
|
|
523
|
+
if (filePath.startsWith('/')) {
|
|
524
|
+
throw new Error('s3Path should not start with /, please adjust s3path function to not return / at the start of the path');
|
|
525
|
+
}
|
|
526
|
+
const { uploadUrl, uploadExtraParams } = yield this.options.storageAdapter.getUploadSignedUrl(filePath, contentType, 1800);
|
|
527
|
+
const headers = {
|
|
528
|
+
'Content-Type': contentType,
|
|
529
|
+
};
|
|
530
|
+
if (uploadExtraParams) {
|
|
531
|
+
Object.entries(uploadExtraParams).forEach(([key, value]) => {
|
|
532
|
+
headers[key] = value;
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
const resp = yield fetch(uploadUrl, {
|
|
536
|
+
method: 'PUT',
|
|
537
|
+
headers,
|
|
538
|
+
body: nodeBuffer,
|
|
539
|
+
});
|
|
540
|
+
if (!resp.ok) {
|
|
541
|
+
let bodyText = '';
|
|
542
|
+
try {
|
|
543
|
+
bodyText = yield resp.text();
|
|
544
|
+
}
|
|
545
|
+
catch (e) {
|
|
546
|
+
// ignore
|
|
547
|
+
}
|
|
548
|
+
throw new Error(`Upload failed with status ${resp.status}: ${bodyText}`);
|
|
549
|
+
}
|
|
550
|
+
yield this.options.storageAdapter.markKeyForNotDeletation(filePath);
|
|
551
|
+
if (!this.resourceConfig) {
|
|
552
|
+
throw new Error('resourceConfig is not initialized yet');
|
|
553
|
+
}
|
|
554
|
+
const { error: createError } = yield this.adminforth.createResourceRecord({
|
|
555
|
+
resource: this.resourceConfig,
|
|
556
|
+
record: { [this.options.pathColumnName]: filePath },
|
|
557
|
+
adminUser,
|
|
558
|
+
extra,
|
|
559
|
+
});
|
|
560
|
+
if (createError) {
|
|
561
|
+
try {
|
|
562
|
+
yield this.options.storageAdapter.markKeyForDeletation(filePath);
|
|
563
|
+
}
|
|
564
|
+
catch (e) {
|
|
565
|
+
// best-effort cleanup, ignore error
|
|
566
|
+
}
|
|
567
|
+
throw new Error(`Error creating record after upload: ${createError}`);
|
|
568
|
+
}
|
|
569
|
+
let previewUrl;
|
|
570
|
+
if ((_b = this.options.preview) === null || _b === void 0 ? void 0 : _b.previewUrl) {
|
|
571
|
+
previewUrl = this.options.preview.previewUrl({ filePath });
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
previewUrl = yield this.options.storageAdapter.getDownloadUrl(filePath, 1800);
|
|
575
|
+
}
|
|
576
|
+
return {
|
|
577
|
+
path: filePath,
|
|
578
|
+
previewUrl,
|
|
579
|
+
};
|
|
580
|
+
});
|
|
581
|
+
}
|
|
474
582
|
}
|
package/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { PluginOptions } from './types.js';
|
|
3
|
-
import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResource, Filters, IAdminForth, IHttpServer, suggestIfTypo } from "adminforth";
|
|
3
|
+
import { AdminForthPlugin, AdminForthResourceColumn, AdminForthResource, Filters, IAdminForth, IHttpServer, suggestIfTypo, RateLimiter, AdminUser, HttpExtra } from "adminforth";
|
|
4
4
|
import { Readable } from "stream";
|
|
5
|
-
import { RateLimiter } from "adminforth";
|
|
6
5
|
import { randomUUID } from "crypto";
|
|
7
6
|
import { interpretResource } from 'adminforth';
|
|
8
7
|
import { ActionCheckSource } from 'adminforth';
|
|
@@ -219,16 +218,6 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
219
218
|
throw new Error(`Column with name "${pathColumnName}" not found in resource "${resourceConfig.label}"`);
|
|
220
219
|
}
|
|
221
220
|
|
|
222
|
-
if (this.options.generation?.fieldsForContext) {
|
|
223
|
-
this.options.generation?.fieldsForContext.forEach((field: string) => {
|
|
224
|
-
if (!resourceConfig.columns.find((column: any) => column.name === field)) {
|
|
225
|
-
const similar = suggestIfTypo(resourceConfig.columns.map((column: any) => column.name), field);
|
|
226
|
-
throw new Error(`Field "${field}" specified in fieldsForContext not found in
|
|
227
|
-
resource "${resourceConfig.label}". ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
221
|
const pluginFrontendOptions = {
|
|
233
222
|
allowedExtensions: this.options.allowedFileExtensions,
|
|
234
223
|
maxFileSize: this.options.maxFileSize,
|
|
@@ -386,6 +375,26 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
386
375
|
|
|
387
376
|
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: any) {
|
|
388
377
|
this.adminforth = adminforth;
|
|
378
|
+
|
|
379
|
+
if (this.options.generation) {
|
|
380
|
+
const template = this.options.generation?.generationPrompt;
|
|
381
|
+
const regex = /{{(.*?)}}/g;
|
|
382
|
+
const matches = template.match(regex);
|
|
383
|
+
if (matches) {
|
|
384
|
+
matches.forEach((match) => {
|
|
385
|
+
const field = match.replace(/{{|}}/g, '').trim();
|
|
386
|
+
if (!resourceConfig.columns.find((column: any) => column.name === field)) {
|
|
387
|
+
const similar = suggestIfTypo(resourceConfig.columns.map((column: any) => column.name), field);
|
|
388
|
+
throw new Error(`Field "${field}" specified in generationPrompt not found in resource "${resourceConfig.label}". ${similar ? `Did you mean "${similar}"?` : ''}`);
|
|
389
|
+
} else {
|
|
390
|
+
let column = resourceConfig.columns.find((column: any) => column.name === field);
|
|
391
|
+
if (column.backendOnly === true) {
|
|
392
|
+
throw new Error(`Field "${field}" specified in generationPrompt is marked as backendOnly in resource "${resourceConfig.label}". Please remove backendOnly or choose another field.`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
389
398
|
// called here because modifyResourceConfig can be called in build time where there is no environment and AWS secrets
|
|
390
399
|
this.setupLifecycleRule();
|
|
391
400
|
}
|
|
@@ -545,4 +554,129 @@ export default class UploadPlugin extends AdminForthPlugin {
|
|
|
545
554
|
}
|
|
546
555
|
|
|
547
556
|
|
|
557
|
+
async uploadFromBuffer({
|
|
558
|
+
filename,
|
|
559
|
+
contentType,
|
|
560
|
+
buffer,
|
|
561
|
+
adminUser,
|
|
562
|
+
extra,
|
|
563
|
+
}: {
|
|
564
|
+
filename: string;
|
|
565
|
+
contentType: string;
|
|
566
|
+
buffer: Buffer | Uint8Array | ArrayBuffer;
|
|
567
|
+
adminUser: AdminUser;
|
|
568
|
+
extra?: HttpExtra;
|
|
569
|
+
}): Promise<{ path: string; previewUrl: string }> {
|
|
570
|
+
if (!filename || !contentType || !buffer) {
|
|
571
|
+
throw new Error('filename, contentType and buffer are required');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const lastDotIndex = filename.lastIndexOf('.');
|
|
575
|
+
if (lastDotIndex === -1) {
|
|
576
|
+
throw new Error('filename must contain an extension');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const originalExtension = filename.substring(lastDotIndex + 1).toLowerCase();
|
|
580
|
+
const originalFilename = filename.substring(0, lastDotIndex);
|
|
581
|
+
|
|
582
|
+
if (this.options.allowedFileExtensions && !this.options.allowedFileExtensions.includes(originalExtension)) {
|
|
583
|
+
throw new Error(
|
|
584
|
+
`File extension "${originalExtension}" is not allowed, allowed extensions are: ${this.options.allowedFileExtensions.join(', ')}`
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
let nodeBuffer: Buffer;
|
|
589
|
+
if (Buffer.isBuffer(buffer)) {
|
|
590
|
+
nodeBuffer = buffer;
|
|
591
|
+
} else if (buffer instanceof ArrayBuffer) {
|
|
592
|
+
nodeBuffer = Buffer.from(buffer);
|
|
593
|
+
} else if (ArrayBuffer.isView(buffer)) {
|
|
594
|
+
nodeBuffer = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
595
|
+
} else {
|
|
596
|
+
throw new Error('Unsupported buffer type');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const size = nodeBuffer.byteLength;
|
|
600
|
+
if (this.options.maxFileSize && size > this.options.maxFileSize) {
|
|
601
|
+
throw new Error(
|
|
602
|
+
`File size ${size} is too large. Maximum allowed size is ${this.options.maxFileSize}`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
const filePath: string = this.options.filePath({
|
|
606
|
+
originalFilename,
|
|
607
|
+
originalExtension,
|
|
608
|
+
contentType,
|
|
609
|
+
record: undefined,
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
if (filePath.startsWith('/')) {
|
|
613
|
+
throw new Error('s3Path should not start with /, please adjust s3path function to not return / at the start of the path');
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const { uploadUrl, uploadExtraParams } = await this.options.storageAdapter.getUploadSignedUrl(
|
|
617
|
+
filePath,
|
|
618
|
+
contentType,
|
|
619
|
+
1800,
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
const headers: Record<string, string> = {
|
|
623
|
+
'Content-Type': contentType,
|
|
624
|
+
};
|
|
625
|
+
if (uploadExtraParams) {
|
|
626
|
+
Object.entries(uploadExtraParams).forEach(([key, value]) => {
|
|
627
|
+
headers[key] = value as string;
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const resp = await fetch(uploadUrl as any, {
|
|
632
|
+
method: 'PUT',
|
|
633
|
+
headers,
|
|
634
|
+
body: nodeBuffer as any,
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
if (!resp.ok) {
|
|
638
|
+
let bodyText = '';
|
|
639
|
+
try {
|
|
640
|
+
bodyText = await resp.text();
|
|
641
|
+
} catch (e) {
|
|
642
|
+
// ignore
|
|
643
|
+
}
|
|
644
|
+
throw new Error(`Upload failed with status ${resp.status}: ${bodyText}`);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
await this.options.storageAdapter.markKeyForNotDeletation(filePath);
|
|
648
|
+
|
|
649
|
+
if (!this.resourceConfig) {
|
|
650
|
+
throw new Error('resourceConfig is not initialized yet');
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const { error: createError } = await this.adminforth.createResourceRecord({
|
|
654
|
+
resource: this.resourceConfig,
|
|
655
|
+
record: { [this.options.pathColumnName]: filePath },
|
|
656
|
+
adminUser,
|
|
657
|
+
extra,
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
if (createError) {
|
|
661
|
+
try {
|
|
662
|
+
await this.options.storageAdapter.markKeyForDeletation(filePath);
|
|
663
|
+
} catch (e) {
|
|
664
|
+
// best-effort cleanup, ignore error
|
|
665
|
+
}
|
|
666
|
+
throw new Error(`Error creating record after upload: ${createError}`);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
let previewUrl: string;
|
|
670
|
+
if (this.options.preview?.previewUrl) {
|
|
671
|
+
previewUrl = this.options.preview.previewUrl({ filePath });
|
|
672
|
+
} else {
|
|
673
|
+
previewUrl = await this.options.storageAdapter.getDownloadUrl(filePath, 1800);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return {
|
|
677
|
+
path: filePath,
|
|
678
|
+
previewUrl,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
548
682
|
}
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -102,12 +102,6 @@ export type PluginOptions = {
|
|
|
102
102
|
*/
|
|
103
103
|
outputSize?: string,
|
|
104
104
|
|
|
105
|
-
/**
|
|
106
|
-
* Fields for conetext which will be used to generate the image.
|
|
107
|
-
* If specified, the plugin will use fields from the record to provide additional context to the AI model.
|
|
108
|
-
*/
|
|
109
|
-
fieldsForContext?: string[],
|
|
110
|
-
|
|
111
105
|
/**
|
|
112
106
|
* The number of images to generate
|
|
113
107
|
* in one request
|