@acorex/modules 20.7.11 → 20.7.13
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/data-management/index.d.ts +250 -4
- package/document-management/index.d.ts +4 -2
- package/fesm2022/acorex-modules-data-management.mjs +1 -1
- package/fesm2022/acorex-modules-data-management.mjs.map +1 -1
- package/fesm2022/acorex-modules-document-management.mjs +344 -132
- package/fesm2022/acorex-modules-document-management.mjs.map +1 -1
- package/fesm2022/{acorex-modules-platform-management-acorex-modules-platform-management-BAIx0BJe.mjs → acorex-modules-platform-management-acorex-modules-platform-management-ndbiBVUt.mjs} +13 -9
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-ndbiBVUt.mjs.map +1 -0
- package/fesm2022/{acorex-modules-platform-management-menu-list.component-BxGLun0f.mjs → acorex-modules-platform-management-menu-list.component-w-Ix2VZA.mjs} +2 -2
- package/fesm2022/{acorex-modules-platform-management-menu-list.component-BxGLun0f.mjs.map → acorex-modules-platform-management-menu-list.component-w-Ix2VZA.mjs.map} +1 -1
- package/fesm2022/acorex-modules-platform-management.mjs +1 -1
- package/fesm2022/{acorex-modules-product-catalog-product.entity-BXDh4Wlu.mjs → acorex-modules-product-catalog-product.entity-CVW7-ye7.mjs} +2 -28
- package/fesm2022/acorex-modules-product-catalog-product.entity-CVW7-ye7.mjs.map +1 -0
- package/fesm2022/acorex-modules-product-catalog.mjs +1 -1
- package/package.json +2 -2
- package/fesm2022/acorex-modules-platform-management-acorex-modules-platform-management-BAIx0BJe.mjs.map +0 -1
- package/fesm2022/acorex-modules-product-catalog-product.entity-BXDh4Wlu.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AXPSessionService, AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex/platform/auth';
|
|
2
|
-
import { AXPEntityService, AXMEntityCrudServiceImpl, entityMasterCrudActions, entityMasterRecordActions, cloneLayoutArrays, ensureLayoutSection, ensureLayoutPropertyView, ensureListActions, actionExists, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
2
|
+
import { AXPEntityService, AXMEntityCrudServiceImpl, entityMasterCrudActions, entityMasterRecordActions, cloneLayoutArrays, ensureLayoutSection, ensureLayoutPropertyView, ensureListActions, actionExists, AXPEntityDefinitionRegistryService, AXP_ENTITY_CONFIG_TOKEN, AXP_ENTITY_ACTION_PLUGIN, AXP_ENTITY_STORAGE_MIDDLEWARE, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
3
3
|
import { AXPHookService, AXPPlatformScope, AXPDataGenerator, AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXPDeviceService, resolvePlatformScopeKey, resolvePlatformScopeName } from '@acorex/platform/core';
|
|
4
4
|
import { AXPSearchCommandProvider, createAllQueryView, createQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXPFileTypeProviderService, AXP_FILE_TYPE_INFO_PROVIDER, AXPFileStorageService, AXPFilterOperatorMiddlewareService, AXPSettingsService, AXPLockService, UploadFromComputerActionProvider, AXP_FILE_ACTION_PROVIDER, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER } from '@acorex/platform/common';
|
|
5
5
|
import * as i0 from '@angular/core';
|
|
@@ -1370,7 +1370,7 @@ async function documentTypeFactory(injector) {
|
|
|
1370
1370
|
actions: [...entityMasterRecordActions()],
|
|
1371
1371
|
},
|
|
1372
1372
|
list: {
|
|
1373
|
-
actions: [...entityMasterCrudActions()],
|
|
1373
|
+
actions: [...entityMasterCrudActions({ edit: true })],
|
|
1374
1374
|
views: [createAllQueryView()],
|
|
1375
1375
|
},
|
|
1376
1376
|
},
|
|
@@ -4120,7 +4120,7 @@ class AXMDocumentDialogService {
|
|
|
4120
4120
|
if (showMeta) {
|
|
4121
4121
|
flex.formField('@document-management:terms.common.meta-data', field => {
|
|
4122
4122
|
field.path(`file-${index}.metaDataForm`);
|
|
4123
|
-
field.customWidget('meta-data-form-editor', documentType?.metaDataList);
|
|
4123
|
+
field.customWidget('meta-data-form-editor', documentType?.metaDataList ?? { groups: [] });
|
|
4124
4124
|
});
|
|
4125
4125
|
}
|
|
4126
4126
|
flex.formField('@document-management:terms.common.file', field => {
|
|
@@ -4203,10 +4203,16 @@ class AXMDocumentDialogService {
|
|
|
4203
4203
|
.map((f) => `.${f.name.split('.')[1]}`)
|
|
4204
4204
|
.join(',');
|
|
4205
4205
|
const fileList = Array.isArray(files) ? files : [];
|
|
4206
|
-
|
|
4206
|
+
/** Get metaDataForm from a file item (widget may store under meta or metaDataForm). */
|
|
4207
|
+
const getFileMeta = (item) => item?.metaDataForm ?? (item?.meta && typeof item.meta === 'object' && !Array.isArray(item.meta) ? item.meta : undefined);
|
|
4208
|
+
// Build initial context for all files: each file-${index} gets that file's metaDataForm so form shows existing meta
|
|
4207
4209
|
const initialContext = {};
|
|
4208
4210
|
if (showMeta) {
|
|
4209
|
-
|
|
4211
|
+
fileList.forEach((item, index) => {
|
|
4212
|
+
initialContext[`file-${index}`] = { metaDataForm: getFileMeta(item) ?? metaData };
|
|
4213
|
+
});
|
|
4214
|
+
if (fileList.length === 0)
|
|
4215
|
+
initialContext['file-0'] = { metaDataForm: metaData };
|
|
4210
4216
|
}
|
|
4211
4217
|
// Initialize files array context with default values
|
|
4212
4218
|
initialContext['files'] = fileList.map(item => ({ file: [item] }));
|
|
@@ -4225,7 +4231,7 @@ class AXMDocumentDialogService {
|
|
|
4225
4231
|
if (showMeta) {
|
|
4226
4232
|
flex.formField('@document-management:terms.common.meta-data', field => {
|
|
4227
4233
|
field.path(`file-${index}.metaDataForm`);
|
|
4228
|
-
field.customWidget('meta-data-form-editor', documentType?.metaDataList);
|
|
4234
|
+
field.customWidget('meta-data-form-editor', documentType?.metaDataList ?? { groups: [] });
|
|
4229
4235
|
});
|
|
4230
4236
|
}
|
|
4231
4237
|
flex.formField('File', field => {
|
|
@@ -4252,15 +4258,17 @@ class AXMDocumentDialogService {
|
|
|
4252
4258
|
};
|
|
4253
4259
|
}
|
|
4254
4260
|
const ctx = dialogRef.context();
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4261
|
+
const outFiles = (ctx?.['files']).map((item, index) => ({
|
|
4262
|
+
...item,
|
|
4263
|
+
...(showMeta ? { metaDataForm: ctx?.[`file-${index}`]?.['metaDataForm'] } : {}),
|
|
4264
|
+
}));
|
|
4265
|
+
if (showMeta && outFiles.length) {
|
|
4266
|
+
console.debug('[document-dialog] openAttachmentDialogWithoutSave result', {
|
|
4267
|
+
filesCount: outFiles.length,
|
|
4268
|
+
firstFileMetaDataForm: outFiles[0]?.metaDataForm,
|
|
4269
|
+
});
|
|
4270
|
+
}
|
|
4271
|
+
return { data: { cancel: false, files: outFiles } };
|
|
4264
4272
|
});
|
|
4265
4273
|
})
|
|
4266
4274
|
.show();
|
|
@@ -5581,49 +5589,13 @@ class AXMDocumentManagerService {
|
|
|
5581
5589
|
const ext = item.name.split('.').pop()?.toLowerCase();
|
|
5582
5590
|
return ext && AXMDocumentManagerService.GALLERY_EXTENSIONS.includes(ext);
|
|
5583
5591
|
});
|
|
5584
|
-
// Fetch documents with null fileId.source.value
|
|
5585
|
-
const documentsWithNullFileId = filteredDocuments.filter((doc) => !doc.fileId.source.value);
|
|
5586
|
-
// Fetch missing documents and replace them in the array
|
|
5587
|
-
if (documentsWithNullFileId.length > 0) {
|
|
5588
|
-
const fetchedDocuments = await Promise.all(documentsWithNullFileId.map((doc) => this.documentService.getOne(doc.id)));
|
|
5589
|
-
// Replace documents in filteredDocuments with fetched ones
|
|
5590
|
-
fetchedDocuments.forEach((fetchedDoc) => {
|
|
5591
|
-
const index = filteredDocuments.findIndex((doc) => doc.id === fetchedDoc.id);
|
|
5592
|
-
if (index !== -1) {
|
|
5593
|
-
filteredDocuments[index] = fetchedDoc;
|
|
5594
|
-
}
|
|
5595
|
-
});
|
|
5596
|
-
}
|
|
5597
|
-
// Collect all fileIds that need to be fetched
|
|
5598
|
-
const fileIds = filteredDocuments.filter((doc) => doc.fileId.source.value).map((doc) => doc.fileId.source.value);
|
|
5599
|
-
// Fetch all file info at once (need URL for media viewer)
|
|
5600
|
-
const fileInfosMap = new Map();
|
|
5601
|
-
if (fileIds.length > 0) {
|
|
5602
|
-
const infos = await Promise.all(fileIds.map((id) => this.fileService.getInfo(id)));
|
|
5603
|
-
infos.forEach((info) => {
|
|
5604
|
-
if (info?.fileId) {
|
|
5605
|
-
fileInfosMap.set(info.fileId, info);
|
|
5606
|
-
}
|
|
5607
|
-
});
|
|
5608
|
-
}
|
|
5609
5592
|
// Convert documents to AXPFileListItem[] format for the gallery widget
|
|
5610
|
-
const fileListItems =
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
}
|
|
5617
|
-
return {
|
|
5618
|
-
id: doc.id ?? '',
|
|
5619
|
-
name: doc.name,
|
|
5620
|
-
size: doc.size,
|
|
5621
|
-
status: 'attached',
|
|
5622
|
-
source: {
|
|
5623
|
-
kind: 'url',
|
|
5624
|
-
value: url,
|
|
5625
|
-
},
|
|
5626
|
-
};
|
|
5593
|
+
const fileListItems = filteredDocuments.map((doc) => ({
|
|
5594
|
+
id: doc.id ?? '',
|
|
5595
|
+
name: doc.name,
|
|
5596
|
+
size: doc.size,
|
|
5597
|
+
status: 'attached',
|
|
5598
|
+
source: doc.fileId?.source,
|
|
5627
5599
|
}));
|
|
5628
5600
|
// Calculate start index
|
|
5629
5601
|
const startIndex = isVirtualFolder
|
|
@@ -7180,55 +7152,321 @@ const attachmentsPlugin = {
|
|
|
7180
7152
|
},
|
|
7181
7153
|
};
|
|
7182
7154
|
|
|
7183
|
-
|
|
7155
|
+
/** Extract metadata for server (metaDataForm) from widget item (meta or metaDataForm). */
|
|
7156
|
+
function getMetaDataFormForServer(item) {
|
|
7157
|
+
if (item?.meta?.metaDataForm != null)
|
|
7158
|
+
return item.meta.metaDataForm;
|
|
7159
|
+
if (item?.metaDataForm != null)
|
|
7160
|
+
return item.metaDataForm;
|
|
7161
|
+
if (item?.meta != null && typeof item.meta === 'object' && !Array.isArray(item.meta))
|
|
7162
|
+
return item.meta;
|
|
7163
|
+
return undefined;
|
|
7164
|
+
}
|
|
7165
|
+
/** Resolve list of attachment field names from entity extensions.attachments. */
|
|
7166
|
+
function getAttachmentFields(attachCfg) {
|
|
7167
|
+
if (!attachCfg || typeof attachCfg !== 'object')
|
|
7168
|
+
return [];
|
|
7169
|
+
if (typeof attachCfg.field === 'string')
|
|
7170
|
+
return [attachCfg.field];
|
|
7171
|
+
return Object.keys(attachCfg).filter((k) => k && typeof k === 'string');
|
|
7172
|
+
}
|
|
7173
|
+
/** Fallback: get attachment field names from properties with file-uploader interface (when extensions.attachments is missing e.g. cached def). */
|
|
7174
|
+
function getAttachmentFieldsFromProperties(def) {
|
|
7175
|
+
const props = def?.properties;
|
|
7176
|
+
if (!Array.isArray(props))
|
|
7177
|
+
return [];
|
|
7178
|
+
return props
|
|
7179
|
+
.filter((p) => p?.schema?.interface?.type === 'file-uploader' && p?.name)
|
|
7180
|
+
.map((p) => p.name);
|
|
7181
|
+
}
|
|
7182
|
+
/**
|
|
7183
|
+
* Handles file list fields configured via entity.extensions.attachments.
|
|
7184
|
+
* Preserves metaDataForm from widget; uploads pending blobs after persistence and writes final references.
|
|
7185
|
+
* Runs before file-cast (order 25) so blobs are uploaded before file-cast sees the data.
|
|
7186
|
+
*/
|
|
7187
|
+
// Run before file-cast (order 25) so blobs are uploaded and refs written before file-cast sees the data
|
|
7188
|
+
const attachmentsUploadMiddleware = {
|
|
7189
|
+
target: { ops: ['create', 'update'], order: 22 },
|
|
7190
|
+
execute: async (ctx, next) => {
|
|
7191
|
+
const registry = inject(AXPEntityDefinitionRegistryService);
|
|
7192
|
+
const storage = inject(AXPFileStorageService);
|
|
7193
|
+
const [moduleName, entityNameOnly] = ctx.entityName.split('.');
|
|
7194
|
+
const def = await registry.resolve(moduleName, entityNameOnly).catch(() => null);
|
|
7195
|
+
const attachCfg = def?.extensions?.attachments;
|
|
7196
|
+
let fields = getAttachmentFields(attachCfg);
|
|
7197
|
+
if (!fields.length && def)
|
|
7198
|
+
fields = getAttachmentFieldsFromProperties(def);
|
|
7199
|
+
if (!fields.length) {
|
|
7200
|
+
await next();
|
|
7201
|
+
return;
|
|
7202
|
+
}
|
|
7203
|
+
const pendingByField = ctx.locals.attach_pending ?? {};
|
|
7204
|
+
ctx.locals.attach_pending = pendingByField;
|
|
7205
|
+
if (ctx.data && typeof ctx.data === 'object') {
|
|
7206
|
+
for (const field of fields) {
|
|
7207
|
+
const list = Array.isArray(ctx.data[field]) ? ctx.data[field] : [];
|
|
7208
|
+
pendingByField[field] = [];
|
|
7209
|
+
const normalized = [];
|
|
7210
|
+
for (const item of list) {
|
|
7211
|
+
const metaDataForm = getMetaDataFormForServer(item);
|
|
7212
|
+
if (item?.source?.kind === 'blob' && item.source.value instanceof Blob) {
|
|
7213
|
+
const blob = item.source.value;
|
|
7214
|
+
const name = item.name || `file-${Date.now()}`;
|
|
7215
|
+
pendingByField[field].push({ fileItem: { ...item, name, metaDataForm }, blob });
|
|
7216
|
+
const entry = {
|
|
7217
|
+
tempId: item.id,
|
|
7218
|
+
name,
|
|
7219
|
+
size: item.size ?? blob.size,
|
|
7220
|
+
status: 'pending_upload',
|
|
7221
|
+
};
|
|
7222
|
+
if (metaDataForm)
|
|
7223
|
+
entry.metaDataForm = metaDataForm;
|
|
7224
|
+
normalized.push(entry);
|
|
7225
|
+
}
|
|
7226
|
+
else if (item?.source?.kind === 'fileId' && item.id && typeof item.source.value === 'string') {
|
|
7227
|
+
const entry = {
|
|
7228
|
+
id: item.id,
|
|
7229
|
+
name: item.name,
|
|
7230
|
+
size: item.size,
|
|
7231
|
+
status: item.status || 'uploaded',
|
|
7232
|
+
source: { kind: 'fileId', value: item.source.value },
|
|
7233
|
+
};
|
|
7234
|
+
if (metaDataForm)
|
|
7235
|
+
entry.metaDataForm = metaDataForm;
|
|
7236
|
+
normalized.push(entry);
|
|
7237
|
+
}
|
|
7238
|
+
else if (item?.id && item?.name) {
|
|
7239
|
+
const entry = {
|
|
7240
|
+
id: item.id,
|
|
7241
|
+
name: item.name,
|
|
7242
|
+
size: item.size,
|
|
7243
|
+
status: item.status || 'uploaded',
|
|
7244
|
+
source: item.source ? { kind: item.source.kind, value: item.source.value } : undefined,
|
|
7245
|
+
};
|
|
7246
|
+
if (metaDataForm)
|
|
7247
|
+
entry.metaDataForm = metaDataForm;
|
|
7248
|
+
normalized.push(entry);
|
|
7249
|
+
}
|
|
7250
|
+
}
|
|
7251
|
+
const dataForBackend = normalized.filter((x) => x.status !== 'pending_upload');
|
|
7252
|
+
ctx.data[field] = dataForBackend;
|
|
7253
|
+
}
|
|
7254
|
+
}
|
|
7255
|
+
await next();
|
|
7256
|
+
const refId = ctx.op === 'create' ? String(ctx.result) : String(ctx.id);
|
|
7257
|
+
const refType = ctx.entityName;
|
|
7258
|
+
for (const field of fields) {
|
|
7259
|
+
const pending = pendingByField[field] ?? [];
|
|
7260
|
+
if (!pending.length)
|
|
7261
|
+
continue;
|
|
7262
|
+
if (!storage)
|
|
7263
|
+
continue;
|
|
7264
|
+
const finalRefs = (ctx.data[field] ?? []).filter((x) => x.status !== 'pending_upload');
|
|
7265
|
+
for (const { fileItem, blob } of pending) {
|
|
7266
|
+
const metaDataForm = fileItem.metaDataForm ?? getMetaDataFormForServer(fileItem);
|
|
7267
|
+
try {
|
|
7268
|
+
const info = await storage.save({
|
|
7269
|
+
file: blob,
|
|
7270
|
+
refId,
|
|
7271
|
+
refType,
|
|
7272
|
+
category: '',
|
|
7273
|
+
name: fileItem.name,
|
|
7274
|
+
});
|
|
7275
|
+
await storage.commit(info.fileId);
|
|
7276
|
+
const entry = {
|
|
7277
|
+
id: info.fileId,
|
|
7278
|
+
name: info.name || fileItem.name,
|
|
7279
|
+
size: info.size || blob.size,
|
|
7280
|
+
type: info.mimeType || blob.type,
|
|
7281
|
+
status: 'uploaded',
|
|
7282
|
+
source: { kind: 'fileId', value: info.fileId },
|
|
7283
|
+
};
|
|
7284
|
+
if (metaDataForm)
|
|
7285
|
+
entry.metaDataForm = metaDataForm;
|
|
7286
|
+
finalRefs.push(entry);
|
|
7287
|
+
}
|
|
7288
|
+
catch (err) {
|
|
7289
|
+
finalRefs.push({
|
|
7290
|
+
tempId: fileItem.id,
|
|
7291
|
+
name: fileItem.name,
|
|
7292
|
+
size: fileItem.size,
|
|
7293
|
+
type: blob.type,
|
|
7294
|
+
status: 'upload_failed',
|
|
7295
|
+
error: err?.message,
|
|
7296
|
+
});
|
|
7297
|
+
}
|
|
7298
|
+
}
|
|
7299
|
+
const entityId = ctx.op === 'create' ? ctx.result : ctx.id;
|
|
7300
|
+
if (entityId != null) {
|
|
7301
|
+
const payload = { [field]: finalRefs };
|
|
7302
|
+
const withMeta = finalRefs.filter((r) => r?.metaDataForm != null).length;
|
|
7303
|
+
console.log('[attachments-upload] ذخیره — الان میخوام ctx.backend.updateOne بزنم (پچ با metaDataForm)', {
|
|
7304
|
+
entityName: ctx.entityName,
|
|
7305
|
+
entityId,
|
|
7306
|
+
field,
|
|
7307
|
+
finalRefsLength: finalRefs.length,
|
|
7308
|
+
withMetaCount: withMeta,
|
|
7309
|
+
payloadSample: payload[field]?.map((r, i) => ({ i, hasMeta: !!r?.metaDataForm })),
|
|
7310
|
+
});
|
|
7311
|
+
try {
|
|
7312
|
+
await ctx.backend.updateOne(ctx.entityName, entityId, payload);
|
|
7313
|
+
console.log('[attachments-upload] ذخیره — ctx.backend.updateOne انجام شد (ok)');
|
|
7314
|
+
}
|
|
7315
|
+
catch (err) {
|
|
7316
|
+
console.warn('[attachments-upload] ذخیره — ctx.backend.updateOne خطا', err);
|
|
7317
|
+
// Result already persisted; optional patch for final refs failed
|
|
7318
|
+
}
|
|
7319
|
+
}
|
|
7320
|
+
if (typeof ctx.result === 'object' && ctx.result !== null) {
|
|
7321
|
+
ctx.result = { ...ctx.result, [field]: finalRefs };
|
|
7322
|
+
}
|
|
7323
|
+
}
|
|
7324
|
+
},
|
|
7325
|
+
};
|
|
7326
|
+
|
|
7327
|
+
//#region ---- Plugin Guard Utilities ----
|
|
7328
|
+
/**
|
|
7329
|
+
* Check if the 'document' plugin is active (enabled and not excluded) in the payload.
|
|
7330
|
+
*/
|
|
7331
|
+
function isDocumentPluginActive(payload) {
|
|
7332
|
+
const isEnabled = Array.isArray(payload.plugins) && payload.plugins.some((p) => p.name === 'document');
|
|
7333
|
+
const isExcluded = Array.isArray(payload.excludePlugins) && payload.excludePlugins.includes('document');
|
|
7334
|
+
return isEnabled && !isExcluded;
|
|
7335
|
+
}
|
|
7336
|
+
/**
|
|
7337
|
+
* Extract document plugin options from payload.
|
|
7338
|
+
* Returns undefined if plugin is not active or options are missing.
|
|
7339
|
+
*/
|
|
7340
|
+
function getDocumentPluginOptions(payload) {
|
|
7341
|
+
if (!isDocumentPluginActive(payload)) {
|
|
7342
|
+
return undefined;
|
|
7343
|
+
}
|
|
7344
|
+
return (payload.plugins.find((p) => p.name === 'document')?.options ?? {});
|
|
7345
|
+
}
|
|
7346
|
+
/** Resolve list of document type names from plugin options (single or multiple). */
|
|
7347
|
+
function getDocTypeNames(opts) {
|
|
7348
|
+
if (!opts)
|
|
7349
|
+
return [];
|
|
7350
|
+
if (Array.isArray(opts.docTypeNames) && opts.docTypeNames.length > 0)
|
|
7351
|
+
return opts.docTypeNames;
|
|
7352
|
+
if (typeof opts.docTypeName === 'string' && opts.docTypeName.trim())
|
|
7353
|
+
return [opts.docTypeName.trim()];
|
|
7354
|
+
return [];
|
|
7355
|
+
}
|
|
7356
|
+
//#endregion
|
|
7357
|
+
// ---------------- Configure: set accept based on docTypeId / docTypeNames ----------------
|
|
7184
7358
|
const DocumentFileUploaderConfigureProvider = {
|
|
7185
7359
|
key: 'file-uploader.configure',
|
|
7186
7360
|
priority: 0,
|
|
7187
7361
|
async execute(payload) {
|
|
7188
|
-
const
|
|
7189
|
-
const
|
|
7190
|
-
if (!
|
|
7191
|
-
return payload;
|
|
7192
|
-
const opts = (payload.plugins.find((p) => p.name === 'document')?.options ?? {});
|
|
7193
|
-
if (!opts.docTypeName)
|
|
7362
|
+
const opts = getDocumentPluginOptions(payload);
|
|
7363
|
+
const names = getDocTypeNames(opts);
|
|
7364
|
+
if (!names.length)
|
|
7194
7365
|
return payload;
|
|
7195
7366
|
const documentManagementService = inject(AXPDocumentManagementService);
|
|
7196
|
-
const
|
|
7197
|
-
const
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7367
|
+
const allExtensions = [];
|
|
7368
|
+
for (const name of names) {
|
|
7369
|
+
const docType = await documentManagementService.getDocumentTypeByName(name);
|
|
7370
|
+
const selected = docType?.type?.selectedItems ?? [];
|
|
7371
|
+
const extList = selected
|
|
7372
|
+
.map((s) => s?.name)
|
|
7373
|
+
.filter((n) => typeof n === 'string' && n.includes('.'))
|
|
7374
|
+
.map((n) => `.${n.split('.').pop()?.toLowerCase()}`);
|
|
7375
|
+
allExtensions.push(...extList);
|
|
7376
|
+
}
|
|
7377
|
+
const extensions = Array.from(new Set(allExtensions));
|
|
7202
7378
|
payload.overrides = payload.overrides || {};
|
|
7203
7379
|
payload.overrides['accept'] = extensions.join(',');
|
|
7204
7380
|
return payload;
|
|
7205
7381
|
},
|
|
7206
7382
|
};
|
|
7383
|
+
// ---------------- Actions: one "Upload" button per document type (replaces generic Upload from Device) ----------------
|
|
7384
|
+
const DocumentFileUploaderActionsByTypeProvider = {
|
|
7385
|
+
key: 'file-uploader.actions',
|
|
7386
|
+
priority: 5,
|
|
7387
|
+
execute: async (payload) => {
|
|
7388
|
+
const opts = getDocumentPluginOptions({
|
|
7389
|
+
plugins: payload.plugins,
|
|
7390
|
+
excludePlugins: payload.excludePlugins ?? [],
|
|
7391
|
+
capabilities: payload.capabilities,
|
|
7392
|
+
});
|
|
7393
|
+
const docTypeNames = getDocTypeNames(opts);
|
|
7394
|
+
if (docTypeNames.length === 0)
|
|
7395
|
+
return payload;
|
|
7396
|
+
const documentManagementService = inject(AXPDocumentManagementService);
|
|
7397
|
+
const documentDialogService = inject(AXMDocumentDialogService);
|
|
7398
|
+
const fileService = inject(AXFileService);
|
|
7399
|
+
const docTypes = await Promise.all(docTypeNames.map((name) => documentManagementService.getDocumentTypeByName(name)));
|
|
7400
|
+
const byTypeActions = docTypes
|
|
7401
|
+
.filter((dt) => dt != null)
|
|
7402
|
+
.map((docType) => {
|
|
7403
|
+
const selected = docType?.type?.selectedItems ?? [];
|
|
7404
|
+
const accept = Array.from(new Set(selected
|
|
7405
|
+
.map((s) => s?.name)
|
|
7406
|
+
.filter((n) => typeof n === 'string' && n.includes('.'))
|
|
7407
|
+
.map((n) => `.${n.split('.').pop()?.toLowerCase()}`))).join(',');
|
|
7408
|
+
const typeName = docType?.name;
|
|
7409
|
+
const title = docType?.title ?? typeName;
|
|
7410
|
+
const hasMeta = Array.isArray(docType?.metaDataList?.groups) &&
|
|
7411
|
+
docType.metaDataList.groups.length > 0;
|
|
7412
|
+
return {
|
|
7413
|
+
plugin: 'document',
|
|
7414
|
+
global: false,
|
|
7415
|
+
text: title,
|
|
7416
|
+
icon: 'fa-light fa-file-arrow-up',
|
|
7417
|
+
run: async (capabilities) => {
|
|
7418
|
+
const files = await fileService.choose({
|
|
7419
|
+
multiple: payload.options?.multiple ?? true,
|
|
7420
|
+
accept: accept || undefined,
|
|
7421
|
+
});
|
|
7422
|
+
if (files.length === 0)
|
|
7423
|
+
return;
|
|
7424
|
+
const fileItems = files.map((file) => ({
|
|
7425
|
+
id: AXPDataGenerator.uuid(),
|
|
7426
|
+
name: file.name,
|
|
7427
|
+
size: file.size,
|
|
7428
|
+
type: file.type,
|
|
7429
|
+
status: 'attached',
|
|
7430
|
+
source: { kind: 'blob', value: file },
|
|
7431
|
+
__documentTypeName: typeName,
|
|
7432
|
+
}));
|
|
7433
|
+
if (hasMeta) {
|
|
7434
|
+
const result = await documentDialogService.openAttachmentDialogWithoutSave('Document Type Choose File', {
|
|
7435
|
+
documentType: docType,
|
|
7436
|
+
files: fileItems,
|
|
7437
|
+
});
|
|
7438
|
+
if (result.data?.cancel != null && !result.data.cancel && result.data?.files) {
|
|
7439
|
+
result.data.files.forEach((f, i) => {
|
|
7440
|
+
if (fileItems[i])
|
|
7441
|
+
set(fileItems[i], 'metaDataForm', f?.metaDataForm);
|
|
7442
|
+
});
|
|
7443
|
+
}
|
|
7444
|
+
else if (result.data?.cancel) {
|
|
7445
|
+
return;
|
|
7446
|
+
}
|
|
7447
|
+
}
|
|
7448
|
+
capabilities.addFiles(fileItems);
|
|
7449
|
+
},
|
|
7450
|
+
};
|
|
7451
|
+
});
|
|
7452
|
+
payload.actions = payload.actions.filter((a) => a.plugin !== 'upload-from-computer');
|
|
7453
|
+
payload.actions = [...byTypeActions, ...payload.actions];
|
|
7454
|
+
return payload;
|
|
7455
|
+
},
|
|
7456
|
+
};
|
|
7207
7457
|
// --------------- After Files Added: scaffold for post-add processing ---------------
|
|
7208
7458
|
const DocumentFileUploaderBeforeFilesAddedProvider = {
|
|
7209
7459
|
key: 'file-uploader.beforeFilesAdded',
|
|
7210
7460
|
priority: 0,
|
|
7211
7461
|
async execute(payload) {
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
excludePlugins: payload.excludePlugins,
|
|
7217
|
-
newFiles: payload.newFiles,
|
|
7218
|
-
});
|
|
7219
|
-
const isEnabled = Array.isArray(payload.plugins) && payload.plugins.some((p) => p.name === 'document');
|
|
7220
|
-
const isExcluded = Array.isArray(payload.excludePlugins) && payload.excludePlugins.includes('document');
|
|
7221
|
-
if (!isEnabled || isExcluded)
|
|
7222
|
-
return payload;
|
|
7223
|
-
const opts = (payload.plugins.find((p) => p.name === 'document')?.options ?? {});
|
|
7224
|
-
// Debug: trace resolved options
|
|
7225
|
-
// eslint-disable-next-line no-console
|
|
7226
|
-
console.log('[DocumentFileUploaderBeforeFilesAdded] options', opts);
|
|
7227
|
-
if (!opts.docTypeName)
|
|
7462
|
+
const opts = getDocumentPluginOptions(payload);
|
|
7463
|
+
const docTypeName = payload.newFiles[0]?.__documentTypeName ??
|
|
7464
|
+
opts?.docTypeName;
|
|
7465
|
+
if (!docTypeName)
|
|
7228
7466
|
return payload;
|
|
7229
7467
|
const injector = inject(Injector);
|
|
7230
7468
|
const documentManagementService = injector.get(AXPDocumentManagementService);
|
|
7231
|
-
const docType = await documentManagementService.getDocumentTypeByName(
|
|
7469
|
+
const docType = await documentManagementService.getDocumentTypeByName(docTypeName);
|
|
7232
7470
|
const documentDialogService = injector.get(AXMDocumentDialogService);
|
|
7233
7471
|
const result = await documentDialogService.openAttachmentDialogWithoutSave('Document Type Choose File', {
|
|
7234
7472
|
documentType: docType,
|
|
@@ -7247,41 +7485,18 @@ const DocumentFileUploaderEditDialogAfterFormProvider = {
|
|
|
7247
7485
|
key: 'file-uploader.edit-dialog.groups.after-form',
|
|
7248
7486
|
priority: 0,
|
|
7249
7487
|
async execute(payload) {
|
|
7250
|
-
// Debug: trace edit-dialog hook entry
|
|
7251
|
-
// eslint-disable-next-line no-console
|
|
7252
|
-
console.log('[DocumentFileUploaderEditDialogAfterForm] payload (before)', {
|
|
7253
|
-
plugins: payload.plugins,
|
|
7254
|
-
excludePlugins: payload.excludePlugins,
|
|
7255
|
-
file: payload.file,
|
|
7256
|
-
groups: payload.groups,
|
|
7257
|
-
});
|
|
7258
|
-
const isEnabled = Array.isArray(payload.plugins) && payload.plugins.some((p) => p.name === 'document');
|
|
7259
|
-
const isExcluded = Array.isArray(payload.excludePlugins) && payload.excludePlugins.includes('document');
|
|
7260
|
-
if (!isEnabled || isExcluded)
|
|
7261
|
-
return payload;
|
|
7262
7488
|
const metaObj = payload.file?.metaDataForm;
|
|
7263
|
-
|
|
7264
|
-
const
|
|
7265
|
-
// Debug: trace resolved options and meta object
|
|
7266
|
-
// eslint-disable-next-line no-console
|
|
7267
|
-
console.log('[DocumentFileUploaderEditDialogAfterForm] options & meta', {
|
|
7268
|
-
options: opts,
|
|
7269
|
-
metaObj,
|
|
7270
|
-
});
|
|
7489
|
+
const opts = getDocumentPluginOptions(payload);
|
|
7490
|
+
const docTypeName = payload.file?.__documentTypeName ?? opts?.docTypeName;
|
|
7271
7491
|
const injector = inject(Injector);
|
|
7272
7492
|
const documentManagementService = injector.get(AXPDocumentManagementService);
|
|
7273
|
-
const docType =
|
|
7274
|
-
? await documentManagementService.getDocumentTypeByName(
|
|
7493
|
+
const docType = docTypeName
|
|
7494
|
+
? await documentManagementService.getDocumentTypeByName(docTypeName)
|
|
7275
7495
|
: undefined;
|
|
7276
|
-
// Debug: trace loaded document type and final decision
|
|
7277
|
-
// eslint-disable-next-line no-console
|
|
7278
|
-
console.log('[DocumentFileUploaderEditDialogAfterForm] loaded docType', {
|
|
7279
|
-
docTypeName: opts.docTypeName,
|
|
7280
|
-
hasMetaObj: !!metaObj && Object.keys(metaObj).length > 0,
|
|
7281
|
-
docType,
|
|
7282
|
-
});
|
|
7283
7496
|
if (!docType && (!metaObj || Object.keys(metaObj).length === 0))
|
|
7284
7497
|
return payload;
|
|
7498
|
+
const metaDataList = docType?.metaDataList ?? { groups: [] };
|
|
7499
|
+
const hasDefinitions = Array.isArray(metaDataList.groups) && metaDataList.groups.length > 0;
|
|
7285
7500
|
const fields = [
|
|
7286
7501
|
{
|
|
7287
7502
|
path: 'metaDataForm',
|
|
@@ -7289,11 +7504,7 @@ const DocumentFileUploaderEditDialogAfterFormProvider = {
|
|
|
7289
7504
|
widget: {
|
|
7290
7505
|
name: 'metaDataForm',
|
|
7291
7506
|
type: 'meta-data-form-editor',
|
|
7292
|
-
|
|
7293
|
-
// - documentType.metaDataList structure is used directly in other dialogs:
|
|
7294
|
-
// AXMDocumentDialogService → field.customWidget('meta-data-form-editor', documentType?.metaDataList)
|
|
7295
|
-
// - So we pass the whole metaDataList object here as well for consistency.
|
|
7296
|
-
options: { definitions: docType?.metaDataList },
|
|
7507
|
+
options: metaDataList,
|
|
7297
7508
|
defaultValue: metaObj,
|
|
7298
7509
|
},
|
|
7299
7510
|
},
|
|
@@ -7303,19 +7514,8 @@ const DocumentFileUploaderEditDialogAfterFormProvider = {
|
|
|
7303
7514
|
title: docType?.title ?? '@document-management:terms.common.meta-data',
|
|
7304
7515
|
parameters: fields,
|
|
7305
7516
|
};
|
|
7306
|
-
// metaDataList is an object with a `groups` array; align condition with that structure
|
|
7307
|
-
const hasDefinitions = !!docType &&
|
|
7308
|
-
!!docType.metaDataList &&
|
|
7309
|
-
Array.isArray(docType.metaDataList.groups) &&
|
|
7310
|
-
docType.metaDataList.groups.length > 0;
|
|
7311
7517
|
if (hasDefinitions) {
|
|
7312
7518
|
payload.groups = [...(payload.groups ?? []), group];
|
|
7313
|
-
// Debug: confirm metadata group injection
|
|
7314
|
-
// eslint-disable-next-line no-console
|
|
7315
|
-
console.log('[DocumentFileUploaderEditDialogAfterForm] metadata group injected', {
|
|
7316
|
-
group,
|
|
7317
|
-
groupsAfter: payload.groups,
|
|
7318
|
-
});
|
|
7319
7519
|
}
|
|
7320
7520
|
return payload;
|
|
7321
7521
|
},
|
|
@@ -7410,6 +7610,7 @@ class AXMDocumentManagementModule {
|
|
|
7410
7610
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMDocumentManagementModule, providers: [
|
|
7411
7611
|
// Module-specific providers (not part of manifest system)
|
|
7412
7612
|
{ provide: AXP_ENTITY_ACTION_PLUGIN, multi: true, useValue: attachmentsPlugin },
|
|
7613
|
+
{ provide: AXP_ENTITY_STORAGE_MIDDLEWARE, multi: true, useValue: attachmentsUploadMiddleware },
|
|
7413
7614
|
{
|
|
7414
7615
|
provide: ROUTES,
|
|
7415
7616
|
multi: true,
|
|
@@ -7420,6 +7621,11 @@ class AXMDocumentManagementModule {
|
|
|
7420
7621
|
useValue: p,
|
|
7421
7622
|
multi: true,
|
|
7422
7623
|
})),
|
|
7624
|
+
{
|
|
7625
|
+
provide: AXP_FILE_ACTION_PROVIDER,
|
|
7626
|
+
useValue: DocumentFileUploaderActionsByTypeProvider,
|
|
7627
|
+
multi: true,
|
|
7628
|
+
},
|
|
7423
7629
|
// Module Manifest Provider
|
|
7424
7630
|
{
|
|
7425
7631
|
provide: AXP_MODULE_MANIFEST_PROVIDER,
|
|
@@ -7508,6 +7714,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7508
7714
|
providers: [
|
|
7509
7715
|
// Module-specific providers (not part of manifest system)
|
|
7510
7716
|
{ provide: AXP_ENTITY_ACTION_PLUGIN, multi: true, useValue: attachmentsPlugin },
|
|
7717
|
+
{ provide: AXP_ENTITY_STORAGE_MIDDLEWARE, multi: true, useValue: attachmentsUploadMiddleware },
|
|
7511
7718
|
{
|
|
7512
7719
|
provide: ROUTES,
|
|
7513
7720
|
multi: true,
|
|
@@ -7518,6 +7725,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
7518
7725
|
useValue: p,
|
|
7519
7726
|
multi: true,
|
|
7520
7727
|
})),
|
|
7728
|
+
{
|
|
7729
|
+
provide: AXP_FILE_ACTION_PROVIDER,
|
|
7730
|
+
useValue: DocumentFileUploaderActionsByTypeProvider,
|
|
7731
|
+
multi: true,
|
|
7732
|
+
},
|
|
7521
7733
|
// Module Manifest Provider
|
|
7522
7734
|
{
|
|
7523
7735
|
provide: AXP_MODULE_MANIFEST_PROVIDER,
|