diff --git a/custom/imageGenerator.vue b/custom/imageGenerator.vue
index 5a68fdc..572a042 100644
--- a/custom/imageGenerator.vue
+++ b/custom/imageGenerator.vue
@@ -11,7 +11,7 @@
{{ $t('Generate image with AI') }}
@@ -190,6 +190,7 @@ const props = defineProps(['meta', 'record']);
const images = ref([]);
const loading = ref(false);
const attachmentFiles = ref([])
+const stopGeneration = ref(false);
function minifyField(field: string): string {
if (field.length > 100) {
@@ -248,7 +249,6 @@ onMounted(async () => {
if (resp?.files?.length) {
attachmentFiles.value = resp.files;
- console.log('attachmentFiles', attachmentFiles.value);
}
} catch (err) {
console.error('Failed to fetch attachment files', err);
@@ -337,7 +337,7 @@ async function generateImages() {
let error = null;
try {
resp = await callAdminForthApi({
- path: `/plugin/${props.meta.pluginInstanceId}/generate_images`,
+ path: `/plugin/${props.meta.pluginInstanceId}/create-image-generation-job`,
method: 'POST',
body: {
prompt: prompt.value,
@@ -346,16 +346,13 @@ async function generateImages() {
});
} catch (e) {
console.error(e);
- } finally {
- clearInterval(ticker);
- loadingTimer.value = null;
- loading.value = false;
}
+
if (resp?.error) {
error = resp.error;
}
if (!resp) {
- error = $t('Error generating images, something went wrong');
+ error = $t('Error creating image generation job');
}
if (error) {
@@ -371,11 +368,55 @@ async function generateImages() {
return;
}
+ const jobId = resp.jobId;
+ let jobStatus = null;
+ let jobResponse = null;
+ do {
+ jobResponse = await callAdminForthApi({
+ path: `/plugin/${props.meta.pluginInstanceId}/get-image-generation-job-status`,
+ method: 'POST',
+ body: { jobId },
+ });
+ if (jobResponse !== null) {
+ if (jobResponse?.error) {
+ error = jobResponse.error;
+ break;
+ };
+ jobStatus = jobResponse?.job?.status;
+ if (jobStatus === 'failed') {
+ error = jobResponse?.job?.error || $t('Image generation job failed');
+ }
+ if (jobStatus === 'timeout') {
+ error = jobResponse?.job?.error || $t('Image generation job timeout');
+ }
+ }
+ await new Promise((resolve) => setTimeout(resolve, 2000));
+ } while ((jobStatus === 'in_progress' || jobStatus === null) && !stopGeneration.value);
+
+ if (error) {
+ adminforth.alert({
+ message: error,
+ variant: 'danger',
+ timeout: 'unlimited',
+ });
+ clearInterval(ticker);
+ loadingTimer.value = null;
+ loading.value = false;
+ return;
+ }
+
+ const respImages = jobResponse?.job?.images || [];
+
images.value = [
...images.value,
- ...resp.images,
+ ...respImages,
];
+ clearInterval(ticker);
+ loadingTimer.value = null;
+ loading.value = false;
+
+
// images.value = [
// 'https://via.placeholder.com/600x400?text=Image+1',
// 'https://via.placeholder.com/600x400?text=Image+2',
@@ -386,7 +427,6 @@ async function generateImages() {
caurosel.value = new Carousel(
document.getElementById('gallery'),
images.value.map((img, index) => {
- console.log('mapping image', img, index);
return {
image: img,
el: document.getElementById('gallery').querySelector(`[data-carousel-item]:nth-child(${index + 1})`),
diff --git a/custom/preview.vue b/custom/preview.vue
index 25af34f..65073f2 100644
--- a/custom/preview.vue
+++ b/custom/preview.vue
@@ -1,31 +1,36 @@
-
-
-
-
-
-
-
- {{ $t('Download file') }}
-
+
+
@@ -74,8 +79,10 @@ const props = defineProps({
const trueContentType = ref(null);
onMounted(async () => {
- // try to get HEAD request
- try {
+ // try to get HEAD request (single url only). For arrays we just guess by extension.
+ if (!url.value) return;
+ if (Array.isArray(url.value)) return;
+ try {
const response = await fetch(url.value, {
method: 'HEAD',
mode: 'cors',
@@ -101,6 +108,11 @@ const url = computed(() => {
return props.record[`previewUrl_${props.meta.pluginInstanceId}`];
});
+const urls = computed(() => {
+ if (!url.value) return [];
+ return Array.isArray(url.value) ? url.value : [url.value];
+});
+
const maxWidth = computed(() => {
const isShowPage = route.path.includes('/show/');
const width = isShowPage
@@ -124,6 +136,7 @@ const guessedContentType = computed(() => {
if (!url.value) {
return null;
}
+ if (Array.isArray(url.value)) return null;
const u = new URL(url.value, url.value.startsWith('http') ? undefined : location.origin);
return guessContentType(u.pathname);
});
@@ -141,6 +154,15 @@ function guessContentType(url) {
}
}
+function guessContentTypeFromUrl(u) {
+ if (!u) return null;
+ try {
+ const parsed = new URL(u, u.startsWith('http') ? undefined : location.origin);
+ return guessContentType(parsed.pathname);
+ } catch (e) {
+ return guessContentType(u);
+ }
+}
watch([contentType], async ([contentType]) => {
// since content type might change after true guessing (HEAD request might be slow) we need to try initializing zoom again
@@ -148,12 +170,19 @@ watch([contentType], async ([contentType]) => {
zoom.value.detach();
}
await nextTick();
- if (contentType?.startsWith('image')) {
- zoom.value = mediumZoom(img.value, {
- margin: 24,
- });
+ // For arrays we use click-to-open per image, for single we keep existing behavior.
+ if (contentType?.startsWith('image') && !Array.isArray(url.value)) {
+ zoom.value = mediumZoom(img.value, { margin: 24 });
}
}, { immediate: true });
+function openZoom(index) {
+ if (!urls.value?.length) return;
+ const el = Array.isArray(img.value) ? img.value[index] : img.value;
+ if (!el) return;
+ const z = mediumZoom(el, { margin: 24 });
+ z.open();
+}
+
\ No newline at end of file
diff --git a/custom/tsconfig.json b/custom/tsconfig.json
index d313f46..32a1325 100644
--- a/custom/tsconfig.json
+++ b/custom/tsconfig.json
@@ -1,19 +1,27 @@
{
"compilerOptions": {
- "baseUrl": ".", // This should point to your project root
+ "baseUrl": ".",
"paths": {
"@/*": [
- // "node_modules/adminforth/dist/spa/src/*"
- "../../../spa/src/*"
+ "../../../adminforth/spa/src/*"
],
"*": [
- // "node_modules/adminforth/dist/spa/node_modules/*"
- "../../../spa/node_modules/*"
+ "../../../adminforth/spa/node_modules/*"
],
"@@/*": [
- // "node_modules/adminforth/dist/spa/src/*"
"."
]
}
- }
+ },
+ "include": [
+ "./**/*.ts",
+ "./**/*.tsx",
+ "./**/*.vue",
+ "../**/*.ts",
+ "../**/*.tsx",
+ "../**/*.vue",
+ "../*.vue",
+ "../*.ts",
+ "../*.tsx"
+ ]
}
\ No newline at end of file
diff --git a/custom/uploader.vue b/custom/uploader.vue
index e787d0e..0f49273 100644
--- a/custom/uploader.vue
+++ b/custom/uploader.vue
@@ -24,7 +24,7 @@
}"
>
-
![]()
+