@adminforth/bulk-ai-flow 1.21.9 → 1.22.1

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.
@@ -1,8 +1,9 @@
1
1
  <template>
2
2
  <Table
3
+ ref="tableRef"
3
4
  :columns="tableHeaders"
4
- :data="tableColumns"
5
- :pageSize="6"
5
+ :data="tableDataProvider"
6
+ :pageSize="pageSize"
6
7
  makeHeaderSticky
7
8
  makePaginationSticky
8
9
  >
@@ -14,7 +15,7 @@
14
15
  <template #cell:checkboxes="{ item }">
15
16
  <div class="max-w-[100px] flex items-center justify-center">
16
17
  <Checkbox
17
- v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])].isChecked"
18
+ v-model="item.isChecked"
18
19
  />
19
20
  </div>
20
21
  </template>
@@ -55,8 +56,8 @@
55
56
  </div>
56
57
  </template>
57
58
  <!-- CUSTOM FIELD TEMPLATES -->
58
- <template v-for="n in customFieldNames" :key="n" #[`cell:${n}`]="{ item, column }">
59
- <div v-if="(isAnalyzing(item, n) && !(props.regeneratingFieldsStatus[item[props.primaryKey]] && props.regeneratingFieldsStatus[item[props.primaryKey]][n])) && !isInColumnImage(n)" @mouseenter="(() => { hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = true})" @mouseleave="(() => { hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = false})">
59
+ <template v-for="n in customFieldNames" :key="n" #[`cell:${n}`]="{ item }">
60
+ <div v-if="(isAnalyzing(item, n) && !item.regeneratingFieldsStatus?.[n]) && !isInColumnImage(n)" @mouseenter="(() => { setHover(item.id, n, true) })" @mouseleave="(() => { setHover(item.id, n, false) })">
60
61
  <div class="flex gap-1 justify-end">
61
62
  <Tooltip v-if="checkForError(item, n)">
62
63
  <IconExclamationCircleSolid class="my-2 w-5 h-5 text-red-500" />
@@ -75,143 +76,143 @@
75
76
  <Select
76
77
  class="min-w-[150px]"
77
78
  :options="convertColumnEnumToSelectOptions(props.meta.columnEnums, n)"
78
- v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
79
+ v-model="item.data[n]"
79
80
  :teleportToTop="true"
80
81
  :teleportToBody="false"
81
82
  >
82
83
  </Select>
83
84
  <Tooltip>
84
- <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] }">
85
+ <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !isHovered(item.id, n) }">
85
86
  <p class="text-sm ">{{ $t('old value') }}</p>
86
87
  </div>
87
88
  <template #tooltip>
88
- {{ oldData[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] ?? "No old value" }}
89
+ {{ item.oldData?.[n] ?? "No old value" }}
89
90
  </template>
90
91
  </Tooltip>
91
92
  </div>
92
- <div v-else-if="typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'string' || typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'object'" class="flex flex-col items-start justify-end min-h-[90px]">
93
+ <div v-else-if="typeof item.data?.[n] === 'string' || typeof item.data?.[n] === 'object'" class="flex flex-col items-start justify-end min-h-[90px]">
93
94
  <Textarea
94
95
  class="min-w-[150px] h-full"
95
96
  type="text"
96
- v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
97
+ v-model="item.data[n]"
97
98
  >
98
99
  </Textarea>
99
100
  <Tooltip>
100
- <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] }">
101
+ <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !isHovered(item.id, n) }">
101
102
  <p class="text-sm ">{{ $t('old value') }}</p>
102
103
  </div>
103
104
  <template #tooltip>
104
- <p class="max-w-[200px]">{{ oldData[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] ?? "No old value" }}</p>
105
+ <p class="max-w-[200px]">{{ item.oldData?.[n] ?? "No old value" }}</p>
105
106
  </template>
106
107
  </Tooltip>
107
108
  </div>
108
- <div v-else-if="typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'boolean'" class="flex flex-col items-center justify-end min-h-[90px]">
109
+ <div v-else-if="typeof item.data?.[n] === 'boolean'" class="flex flex-col items-center justify-end min-h-[90px]">
109
110
  <Toggle
110
111
  class="p-2"
111
- v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
112
+ v-model="item.data[n]"
112
113
  >
113
114
  </Toggle>
114
115
  <Tooltip>
115
- <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] }">
116
+ <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !isHovered(item.id, n) }">
116
117
  <p class="text-sm ">{{ $t('old value') }}</p>
117
118
  </div>
118
119
  <template #tooltip>
119
- {{ oldData[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] ?? "No old value" }}
120
+ {{ item.oldData?.[n] ?? "No old value" }}
120
121
  </template>
121
122
  </Tooltip>
122
123
  </div>
123
124
  <div v-else class="flex flex-col items-start justify-end min-h-[90px]">
124
125
  <Input
125
126
  type="number"
126
- v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
127
+ v-model="item.data[n]"
127
128
  class="w-full min-w-[80px]"
128
129
  :fullWidth="true"
129
130
  />
130
131
  <Tooltip>
131
- <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] }">
132
+ <div class="mt-2 flex items-center justify-start gap-1 hover:text-blue-500" :class="{ 'opacity-0': !isHovered(item.id, n) }">
132
133
  <p class="text-sm ">{{ $t('old value') }}</p>
133
134
  </div>
134
135
  <template #tooltip>
135
- {{ oldData[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] ?? "No old value" }}
136
+ {{ item.oldData?.[n] ?? "No old value" }}
136
137
  </template>
137
138
  </Tooltip>
138
139
  </div>
139
140
  </div>
140
141
 
141
- <div v-if="isAiResponseReceivedImage[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])]" @mouseenter="(() => { hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = true})" @mouseleave="(() => { hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = false})">
142
+ <div v-if="item.aiStatus.generatedImages" @mouseenter="(() => { setHover(item.id, n, true) })" @mouseleave="(() => { setHover(item.id, n, false) })">
142
143
  <div v-if="isInColumnImage(n)">
143
144
  <div class="mt-2 mb-2 flex items-center justify-start gap-2">
144
- <div v-if="isValidUrl(selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n])" class="flex flex-col items-center relative">
145
+ <div v-if="isValidUrl(item.data?.[n])" class="flex flex-col items-center relative">
145
146
  <img
146
- :src="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
147
+ :src="item.data?.[n]"
147
148
  class="w-20 h-20 object-cover rounded cursor-pointer border hover:border-blue-500 transition"
148
- @click="() => {openGenerationCarousel[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = true}"
149
+ @click="() => {item.openGenerationCarousel[n] = true}"
149
150
  />
150
151
  <p
151
152
  v-if="isImageHasPreviewUrl[n]"
152
153
  class="absolute mt-20 text-sm hover:text-blue-500 hover:underline hover:cursor-pointer flex items-center gap-1"
153
- :class="{ 'opacity-0': !hovers[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] }"
154
- @click="() => {openImageCompare[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = true}"
154
+ :class="{ 'opacity-0': !isHovered(item.id, n) }"
155
+ @click="() => {item.openImageCompare[n] = true}"
155
156
  >
156
157
  {{ $t('old image') }}
157
158
  </p>
158
159
  </div>
159
160
  <div v-else class="flex items-center justify-center text-center w-20 h-20">
160
- <Tooltip v-if="imageGenerationErrorMessage[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] === 'No source images found'">
161
+ <Tooltip v-if="item.imageGenerationErrorMessage === 'No source images found'">
161
162
  <p
162
163
  >
163
164
  {{ $t("Can't generate image.") }}
164
165
  </p>
165
166
  <template #tooltip>
166
- {{ imageGenerationErrorMessage[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] }}
167
+ {{ item.imageGenerationErrorMessage }}
167
168
  </template>
168
169
  </Tooltip>
169
170
  <Tooltip v-else>
170
171
  <div>
171
172
  <IconRefreshOutline
172
- @click="() => {regenerateImages(item[primaryKey])}"
173
+ @click="() => {regenerateImages(item.id)}"
173
174
  class="w-20 h-20 hover:text-blue-500 cursor-pointer transition hover:scale-105"
174
175
  />
175
176
  </div>
176
177
  <template #tooltip>
177
- {{ imageGenerationErrorMessage[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] + '. Click to retry.' }}
178
+ {{ item.imageGenerationErrorMessage + '. Click to retry.' }}
178
179
  </template>
179
180
  </Tooltip>
180
181
  </div>
181
182
  </div>
182
183
  <div>
183
184
  <GenerationCarousel
184
- v-if="openGenerationCarousel[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
185
- :images="carouselSaveImages[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
186
- :recordId="item[primaryKey]"
185
+ v-if="item.openGenerationCarousel[n]"
186
+ :images="item.carouselSaveImages[n]"
187
+ :recordId="item.id"
187
188
  :meta="props.meta"
188
189
  :fieldName="n"
189
- :carouselImageIndex="carouselImageIndex[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
190
+ :carouselImageIndex="item.carouselImageIndex[n]"
190
191
  :regenerateImagesRefreshRate="regenerateImagesRefreshRate"
191
192
  :sourceImage="item.images && item.images.length ? item.images : null"
192
193
  :imageGenerationPrompts="imageGenerationPrompts[n]"
193
194
  @error="handleError"
194
- @close="openGenerationCarousel[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = false"
195
+ @close="item.openGenerationCarousel[n] = false"
195
196
  @selectImage="updateSelectedImage"
196
197
  @updateCarouselIndex="updateActiveIndex"
197
198
  />
198
199
  <ImageCompare
199
- v-if="openImageCompare[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
200
+ v-if="item.openImageCompare[n]"
200
201
  :meta="props.meta"
201
202
  :columnName="n"
202
- :oldImage="oldData[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
203
- :newImage="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
204
- @close="openImageCompare[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] = false"
203
+ :oldImage="item.oldData?.[n]"
204
+ :newImage="item.data?.[n]"
205
+ @close="item.openImageCompare[n] = false"
205
206
  />
206
207
  </div>
207
208
  </div>
208
209
  </div>
209
210
 
210
- <div v-if="!isAiResponseReceivedImage[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] && isInColumnImage(n)">
211
+ <div v-if="!item.aiStatus.generatedImages && isInColumnImage(n)">
211
212
  <Skeleton type="image" class="w-20 h-20" />
212
213
  </div>
213
214
 
214
- <div v-if="(!isAnalyzing(item, n) || (props.regeneratingFieldsStatus[item[props.primaryKey]] && props.regeneratingFieldsStatus[item[props.primaryKey]][n])) && !isInColumnImage(n)">
215
+ <div v-if="(!isAnalyzing(item, n) || item.regeneratingFieldsStatus?.[n]) && !isInColumnImage(n)">
215
216
  <Skeleton class="w-full h-6" />
216
217
  </div>
217
218
  </template>
@@ -219,7 +220,7 @@
219
220
  </template>
220
221
 
221
222
  <script lang="ts" setup>
222
- import { ref, watch, onMounted } from 'vue'
223
+ import { ref, watch, computed, reactive } from 'vue'
223
224
  import { Select, Input, Textarea, Table, Checkbox, Skeleton, Toggle, Tooltip } from '@/afcl'
224
225
  import GenerationCarousel from './ImageGenerationCarousel.vue'
225
226
  import ImageCompare from './ImageCompare.vue';
@@ -228,48 +229,47 @@ import { IconRefreshOutline, IconExclamationCircleSolid } from '@iconify-prerend
228
229
  const props = defineProps<{
229
230
  meta: any,
230
231
  tableHeaders: any,
231
- tableColumns: any,
232
+ records: any[],
232
233
  customFieldNames: any,
233
- tableColumnsIndexes: any,
234
- selected: any,
235
- isAiResponseReceivedAnalizeImage: boolean[],
236
- isAiResponseReceivedAnalizeNoImage: boolean[],
237
- isAiResponseReceivedImage: boolean[],
238
- primaryKey: any,
239
- openGenerationCarousel: any,
240
- openImageCompare: any,
241
234
  isError: boolean,
242
235
  errorMessage: string
243
- carouselSaveImages: any[]
244
- carouselImageIndex: any[]
245
236
  regenerateImagesRefreshRate: number
246
- isAiGenerationError: boolean[],
247
- aiGenerationErrorMessage: string[],
248
- isAiImageGenerationError: boolean[],
249
- imageGenerationErrorMessage: string[],
250
- oldData: any[],
251
237
  isImageHasPreviewUrl: Record<string, boolean>
252
238
  imageGenerationPrompts: Record<string, any>
253
- isImageToTextGenerationError: boolean[],
254
- imageToTextErrorMessages: Record<string, string>[],
255
- isTextToTextGenerationError: boolean[],
256
- textToTextErrorMessages: Record<string, string>[],
257
239
  outputImageFields: string[],
258
240
  outputFieldsForAnalizeFromImages: string[],
259
241
  outputPlainFields: string[],
260
- regeneratingFieldsStatus: Record<string, Record<string, boolean>>
261
242
  }>();
262
243
  const emit = defineEmits(['error', 'regenerateImages', 'regenerateCell']);
263
244
 
264
-
245
+ const pageSize = 6;
246
+ const pagination = reactive({ offset: 0, limit: pageSize });
265
247
  const zoomedImage = ref(null);
266
- const hovers = ref<{ [key: string]: boolean }[]>([]);
248
+ const hovers = ref<Record<string, Record<string, boolean>>>({});
249
+ const tableRef = ref(null);
267
250
 
268
- watch(() => props.tableColumnsIndexes, (newVal) => {
269
- if (newVal) {
270
- hovers.value = newVal.map(() => ({}));
251
+ defineExpose({
252
+ refresh() {
253
+ if (tableRef.value) {
254
+ tableRef.value.refreshTable();
255
+ }
271
256
  }
272
- }, { immediate: true });
257
+ });
258
+
259
+ const paginatedRecords = computed(() => props.records.slice(pagination.offset, pagination.offset + pagination.limit));
260
+
261
+ const tableDataProvider = async ({ offset, limit }) => {
262
+ pagination.offset = offset;
263
+ pagination.limit = limit;
264
+ return {
265
+ data: paginatedRecords.value,
266
+ total: props.records.length,
267
+ };
268
+ };
269
+
270
+ watch(() => props.records, (newVal) => {
271
+ hovers.value = Object.fromEntries((newVal || []).map(record => [String(record.id), {}]));
272
+ }, { immediate: true, deep: true });
273
273
 
274
274
  function zoomImage(img) {
275
275
  zoomedImage.value = img
@@ -301,7 +301,10 @@ function convertColumnEnumToSelectOptions(columnEnumArray: any[], key: string) {
301
301
  }
302
302
 
303
303
  function updateSelectedImage(image: string, id: any, fieldName: string) {
304
- props.selected[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === id)][fieldName] = image;
304
+ const record = props.records.find(rec => String(rec.id) === String(id));
305
+ if (record) {
306
+ record.data[fieldName] = image;
307
+ }
305
308
  }
306
309
 
307
310
  function handleError({ isError, errorMessage }) {
@@ -311,14 +314,15 @@ function handleError({ isError, errorMessage }) {
311
314
  });
312
315
  }
313
316
 
314
- function regenerateImages(recordInfo: any) {
315
- emit('regenerateImages', {
316
- recordInfo
317
- });
317
+ function regenerateImages(recordId: any) {
318
+ emit('regenerateImages', { recordId });
318
319
  }
319
320
 
320
321
  function updateActiveIndex(newIndex: number, id: any, fieldName: string) {
321
- props.carouselImageIndex[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === id)][fieldName] = newIndex;
322
+ const record = props.records.find(rec => String(rec.id) === String(id));
323
+ if (record) {
324
+ record.carouselImageIndex[fieldName] = newIndex;
325
+ }
322
326
  }
323
327
 
324
328
  function isValidUrl(str: string): boolean {
@@ -335,14 +339,14 @@ function regerenerateFieldIconClick(item, name) {
335
339
  return;
336
340
  }
337
341
  emit('regenerateCell', {
338
- recordId: item[props.primaryKey],
342
+ recordId: item.id,
339
343
  fieldName: name
340
344
  });
341
345
  };
342
346
 
343
347
  function shouldDisableRegenerateFieldIcon(item, name) {
344
348
  if (props.outputFieldsForAnalizeFromImages.findIndex( el => el === name) !== -1 &&
345
- props.imageToTextErrorMessages[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === item[props.primaryKey])]?.[name] === 'No source images found') {
349
+ item.imageToTextErrorMessages?.[name] === 'No source images found') {
346
350
  return true;
347
351
  }
348
352
  return false;
@@ -350,13 +354,13 @@ function shouldDisableRegenerateFieldIcon(item, name) {
350
354
 
351
355
  function checkForError(item, name) {
352
356
  if (props.outputFieldsForAnalizeFromImages.findIndex( el => el === name) !== -1) {
353
- const errorMessage = props.imageToTextErrorMessages?.[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === item[props.primaryKey])]?.[name];
357
+ const errorMessage = item.imageToTextErrorMessages?.[name];
354
358
  if (errorMessage) {
355
359
  return errorMessage;
356
360
  }
357
361
  }
358
362
  if (props.outputPlainFields.findIndex( el => el === name) !== -1) {
359
- const errorMessage = props.textToTextErrorMessages?.[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === item[props.primaryKey])]?.[name];
363
+ const errorMessage = item.textToTextErrorMessages?.[name];
360
364
  if (errorMessage) {
361
365
  return errorMessage;
362
366
  }
@@ -376,13 +380,23 @@ function isAnalyzing(item, name) {
376
380
  }
377
381
 
378
382
  function isImagesAnalyzing(item) {
379
- const isImagesAnalyzing = props.isAiResponseReceivedAnalizeImage[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === item[props.primaryKey])]
380
- return isImagesAnalyzing;
383
+ return item.aiStatus.analyzedImages;
381
384
  }
382
385
 
383
386
  function isNoImageAnalyzing(item) {
384
- const isNoImageAnalyzing = props.isAiResponseReceivedAnalizeNoImage[props.tableColumnsIndexes.findIndex(el => el[props.primaryKey] === item[props.primaryKey])]
385
- return isNoImageAnalyzing;
387
+ return item.aiStatus.analyzedNoImages;
388
+ }
389
+
390
+ function setHover(recordId: string | number, field: string, value: boolean) {
391
+ const key = String(recordId);
392
+ if (!hovers.value[key]) {
393
+ hovers.value[key] = {};
394
+ }
395
+ hovers.value[key][field] = value;
396
+ }
397
+
398
+ function isHovered(recordId: string | number, field: string) {
399
+ return Boolean(hovers.value?.[String(recordId)]?.[field]);
386
400
  }
387
401
 
388
402
 
@@ -11,6 +11,7 @@
11
11
  "dependencies": {
12
12
  "@iconify-prerendered/vue-mdi": "^0.25.1718880438",
13
13
  "medium-zoom": "^1.1.0",
14
+ "p-limit": "^4.0.0",
14
15
  "swiper": "^11.2.10"
15
16
  }
16
17
  },
@@ -254,6 +255,21 @@
254
255
  "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
255
256
  }
256
257
  },
258
+ "node_modules/p-limit": {
259
+ "version": "4.0.0",
260
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
261
+ "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
262
+ "license": "MIT",
263
+ "dependencies": {
264
+ "yocto-queue": "^1.0.0"
265
+ },
266
+ "engines": {
267
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
268
+ },
269
+ "funding": {
270
+ "url": "https://github.com/sponsors/sindresorhus"
271
+ }
272
+ },
257
273
  "node_modules/picocolors": {
258
274
  "version": "1.1.1",
259
275
  "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -340,6 +356,18 @@
340
356
  "optional": true
341
357
  }
342
358
  }
359
+ },
360
+ "node_modules/yocto-queue": {
361
+ "version": "1.2.2",
362
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz",
363
+ "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==",
364
+ "license": "MIT",
365
+ "engines": {
366
+ "node": ">=12.20"
367
+ },
368
+ "funding": {
369
+ "url": "https://github.com/sponsors/sindresorhus"
370
+ }
343
371
  }
344
372
  }
345
373
  }
@@ -12,6 +12,7 @@
12
12
  "dependencies": {
13
13
  "@iconify-prerendered/vue-mdi": "^0.25.1718880438",
14
14
  "medium-zoom": "^1.1.0",
15
- "swiper": "^11.2.10"
15
+ "swiper": "^11.2.10",
16
+ "p-limit": "^4.0.0"
16
17
  }
17
18
  }