@acorex/modules 20.7.3 → 20.7.5

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.
Files changed (20) hide show
  1. package/document-management/index.d.ts +3 -2
  2. package/fesm2022/acorex-modules-document-management.mjs +132 -54
  3. package/fesm2022/acorex-modules-document-management.mjs.map +1 -1
  4. package/fesm2022/{acorex-modules-human-capital-management-leave-request.entity-CITYAroH.mjs → acorex-modules-human-capital-management-leave-request.entity-Dn2LLbuq.mjs} +20 -3
  5. package/fesm2022/acorex-modules-human-capital-management-leave-request.entity-Dn2LLbuq.mjs.map +1 -0
  6. package/fesm2022/acorex-modules-human-capital-management.mjs +558 -103
  7. package/fesm2022/acorex-modules-human-capital-management.mjs.map +1 -1
  8. package/fesm2022/{acorex-modules-task-management-task-board.page-D7dEWzjn.mjs → acorex-modules-task-management-task-board.page-CIlxqtgJ.mjs} +90 -14
  9. package/fesm2022/acorex-modules-task-management-task-board.page-CIlxqtgJ.mjs.map +1 -0
  10. package/fesm2022/acorex-modules-task-management.mjs +1 -1
  11. package/fesm2022/{acorex-modules-workflow-management-index-vstmaa5b.mjs → acorex-modules-workflow-management-index-BIl8No8o.mjs} +16 -10
  12. package/fesm2022/acorex-modules-workflow-management-index-BIl8No8o.mjs.map +1 -0
  13. package/fesm2022/acorex-modules-workflow-management.mjs +36 -4
  14. package/fesm2022/acorex-modules-workflow-management.mjs.map +1 -1
  15. package/human-capital-management/index.d.ts +58 -1
  16. package/package.json +2 -2
  17. package/workflow-management/index.d.ts +2 -0
  18. package/fesm2022/acorex-modules-human-capital-management-leave-request.entity-CITYAroH.mjs.map +0 -1
  19. package/fesm2022/acorex-modules-task-management-task-board.page-D7dEWzjn.mjs.map +0 -1
  20. package/fesm2022/acorex-modules-workflow-management-index-vstmaa5b.mjs.map +0 -1
@@ -10,7 +10,7 @@ import * as _acorex_platform_common from '@acorex/platform/common';
10
10
  import { AXPEntity, AXPFileStorageService, AXPFilterOperatorMiddlewareService, AXPFileType, AXPFileTypeInfoProvider, AXPFileTypeProviderService, AXPMenuProvider, AXPMenuProviderContext, AXPSearchCommandProvider, AXPSearchResult, AXPSettingDefinitionProvider, AXPSettingDefinitionProviderContext } from '@acorex/platform/common';
11
11
  import { AXPEntityModel, AXMEntityCrudServiceImpl, AXPEntityDefinitionLoader, AXPEntityDefinitionPreloader, AXPEntityPreloadEntity } from '@acorex/platform/layout/entity';
12
12
  import * as _acorex_platform_core from '@acorex/platform/core';
13
- import { AXPFileListItem, AXPMetaData, AXPApplicationUserReference, AXPPlatformScope, AXPQueryRequest, AXPActionMenuItem, AXPDeviceService, AXPBackButton, AXPBreadcrumbItem, AXPExecuteCommand } from '@acorex/platform/core';
13
+ import { AXPFileListItem, AXPMetaData, AXPApplicationUserReference, AXPPlatformScope, AXPQueryRequest, AXPHookService, AXPActionMenuItem, AXPDeviceService, AXPBackButton, AXPBreadcrumbItem, AXPExecuteCommand } from '@acorex/platform/core';
14
14
  import * as _acorex_platform_themes_shared from '@acorex/platform/themes/shared';
15
15
  import * as _ngrx_signals from '@ngrx/signals';
16
16
  import * as _acorex_components_menu from '@acorex/components/menu';
@@ -514,6 +514,7 @@ declare class AXMDocumentManagerService implements AXMDocumentManagerServiceInte
514
514
  protected reviewService: AXMReviewService;
515
515
  protected attachmentsService: DocumentAttachmentsService;
516
516
  protected filterMiddlewareService: AXPFilterOperatorMiddlewareService;
517
+ protected hooks: AXPHookService | null;
517
518
  private scopedDriveCache;
518
519
  private buildPathCache;
519
520
  /**
@@ -618,7 +619,7 @@ declare class AXMDocumentManagerService implements AXMDocumentManagerServiceInte
618
619
  */
619
620
  openFile(node: AXMDocumentExplorerNode): Promise<void>;
620
621
  /**
621
- * Downloads a file
622
+ * Downloads a file using the same logic as file-uploader component
622
623
  */
623
624
  downloadFile(node: AXMDocumentExplorerNode): Promise<void>;
624
625
  /**
@@ -1,7 +1,7 @@
1
1
  import { AXPSessionService, AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex/platform/auth';
2
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';
3
- import { AXPPlatformScope, AXPDataGenerator, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, AXPDeviceService, resolvePlatformScopeKey, resolvePlatformScopeName } from '@acorex/platform/core';
4
- import { AXPSearchCommandProvider, createAllQueryView, createQueryView, AXPEntityCommandScope, AXPEntityQueryType, AXPFileTypeProviderService, AXP_FILE_TYPE_INFO_PROVIDER, AXPFileStorageService, AXPFilterOperatorMiddlewareService, AXPSettingsService, AXPLockService, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER } from '@acorex/platform/common';
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
+ 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';
6
6
  import { Injectable, inject, Injector, NgModule, ChangeDetectionStrategy, Component, signal, viewChild, computed, input, effect, ViewEncapsulation, untracked, HostListener } from '@angular/core';
7
7
  import * as i3$3 from '@acorex/core/translation';
@@ -4403,6 +4403,7 @@ class AXMDocumentManagerService {
4403
4403
  this.reviewService = inject(AXMReviewService);
4404
4404
  this.attachmentsService = inject(DocumentAttachmentsService);
4405
4405
  this.filterMiddlewareService = inject(AXPFilterOperatorMiddlewareService);
4406
+ this.hooks = inject(AXPHookService, { optional: true });
4406
4407
  //#endregion
4407
4408
  //#region ---- Private Properties ----
4408
4409
  this.scopedDriveCache = new Map();
@@ -4830,32 +4831,117 @@ class AXMDocumentManagerService {
4830
4831
  const file = await this.documentService.getOne(node.id);
4831
4832
  }
4832
4833
  /**
4833
- * Downloads a file
4834
+ * Downloads a file using the same logic as file-uploader component
4834
4835
  */
4835
4836
  async downloadFile(node) {
4836
- // const file = await this.documentService.getOne(node.id);
4837
- if (node.fileId) {
4838
- if (node.fileId.source?.value &&
4839
- typeof node.fileId.source.value === 'string' &&
4840
- node.fileId.source.value?.startsWith('http')) {
4841
- const link = document.createElement('a');
4842
- link.href = node.fileId.source.value;
4843
- link.download = node.name;
4844
- document.body.appendChild(link);
4845
- link.click();
4846
- document.body.removeChild(link);
4847
- return;
4848
- }
4849
- const fileInfo = await this.fileService.getInfo(node.fileId.id ?? '');
4837
+ if (!node.fileId) {
4838
+ console.error('File ID is undefined, cannot download.', node);
4839
+ return;
4840
+ }
4841
+ const file = {
4842
+ ...node.fileId,
4843
+ name: node.fileId.name ?? node.name,
4844
+ };
4845
+ // Run BeforeDownload hook if available
4846
+ // if (this.hooks) {
4847
+ // try {
4848
+ // await this.hooks.runAsync<any>('file-uploader.fileItem.before-download', {
4849
+ // host: undefined,
4850
+ // file,
4851
+ // plugins: [],
4852
+ // excludePlugins: [],
4853
+ // });
4854
+ // } catch {
4855
+ // // Ignore hook errors
4856
+ // }
4857
+ // }
4858
+ if (!file.source) {
4859
+ console.error('File source is undefined, cannot download.', file);
4860
+ return;
4861
+ }
4862
+ const triggerDownload = (blob, fileName) => {
4863
+ const url = URL.createObjectURL(blob);
4850
4864
  const link = document.createElement('a');
4851
- link.href = fileInfo.url ?? '';
4852
- link.download = node.name; // Set the desired file name
4865
+ link.href = url;
4866
+ link.download = fileName;
4853
4867
  document.body.appendChild(link);
4854
4868
  link.click();
4855
4869
  document.body.removeChild(link);
4870
+ URL.revokeObjectURL(url);
4871
+ };
4872
+ switch (file.source.kind) {
4873
+ case 'blob':
4874
+ if (file.source.value instanceof Blob) {
4875
+ triggerDownload(file.source.value, file.name ?? node.name ?? 'download');
4876
+ }
4877
+ else {
4878
+ console.error('Source kind is blob, but value is not a Blob.', file);
4879
+ }
4880
+ break;
4881
+ case 'fileId':
4882
+ if (typeof file.source.value === 'string') {
4883
+ try {
4884
+ const fileInfo = await this.fileService.getInfo(file.source.value);
4885
+ if (fileInfo && fileInfo.url) {
4886
+ const link = document.createElement('a');
4887
+ link.href = fileInfo.url;
4888
+ link.download = file.name ?? node.name ?? fileInfo.name ?? 'download';
4889
+ link.target = '_blank';
4890
+ document.body.appendChild(link);
4891
+ link.click();
4892
+ document.body.removeChild(link);
4893
+ }
4894
+ else if (fileInfo && fileInfo.binary instanceof Blob) {
4895
+ triggerDownload(fileInfo.binary, file.name ?? node.name ?? fileInfo.name ?? 'download');
4896
+ }
4897
+ else {
4898
+ console.error('Could not retrieve file for download from fileId:', fileInfo);
4899
+ }
4900
+ }
4901
+ catch (error) {
4902
+ console.error('Error downloading file by fileId:', file.source.value, error);
4903
+ }
4904
+ }
4905
+ else {
4906
+ console.error('Source kind is fileId, but value is not a string ID.', file);
4907
+ }
4908
+ break;
4909
+ case 'url':
4910
+ if (typeof file.source.value === 'string') {
4911
+ const link = document.createElement('a');
4912
+ link.href = file.source.value;
4913
+ link.download = file.name ?? node.name ?? 'download';
4914
+ link.target = '_blank';
4915
+ document.body.appendChild(link);
4916
+ link.click();
4917
+ document.body.removeChild(link);
4918
+ }
4919
+ else {
4920
+ console.error('Source kind is url, but value is not a string URL.', file);
4921
+ }
4922
+ break;
4923
+ case 'reference':
4924
+ console.error('Download not supported for source kind: reference', file);
4925
+ break;
4926
+ case 'preview':
4927
+ case 'none':
4928
+ default:
4929
+ console.error(`Download not supported for source kind: ${file.source.kind}`, file);
4930
+ break;
4856
4931
  }
4857
- else {
4858
- throw new Error('File ID is required');
4932
+ // Run AfterDownload hook if available
4933
+ if (this.hooks) {
4934
+ try {
4935
+ await this.hooks.runAsync('file-uploader.fileItem.after-download', {
4936
+ host: undefined,
4937
+ file,
4938
+ plugins: [],
4939
+ excludePlugins: [],
4940
+ });
4941
+ }
4942
+ catch {
4943
+ // Ignore hook errors
4944
+ }
4859
4945
  }
4860
4946
  }
4861
4947
  //#endregion
@@ -5439,7 +5525,7 @@ class AXMDocumentManagerService {
5439
5525
  return ext && ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'pdf'].includes(ext);
5440
5526
  });
5441
5527
  // Fetch documents with null fileId.source.value
5442
- const documentsWithNullFileId = filteredDocuments.filter((doc) => doc.fileId?.source?.kind === 'fileId' && !doc.fileId.source.value);
5528
+ const documentsWithNullFileId = filteredDocuments.filter((doc) => !doc.fileId.source.value);
5443
5529
  // Fetch missing documents and replace them in the array
5444
5530
  if (documentsWithNullFileId.length > 0) {
5445
5531
  const fetchedDocuments = await Promise.all(documentsWithNullFileId.map((doc) => this.documentService.getOne(doc.id)));
@@ -5453,7 +5539,7 @@ class AXMDocumentManagerService {
5453
5539
  }
5454
5540
  // Collect all fileIds that need to be fetched
5455
5541
  const fileIds = filteredDocuments
5456
- .filter((doc) => doc.fileId?.source?.kind === 'fileId' && doc.fileId.source.value)
5542
+ .filter((doc) => doc.fileId.source.value)
5457
5543
  .map((doc) => doc.fileId.source.value);
5458
5544
  // Fetch all file info at once (need URL for media viewer)
5459
5545
  const fileInfosMap = new Map();
@@ -6697,9 +6783,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6697
6783
  ], template: "<!-- Breadcrumbs Section -->\n<div class=\"__breadcrumb ax-xs\">\n <!-- Desktop Breadcrumb -->\n @for (item of vm.currentPath(); track item.id; let i = $index;let last = $last) {\n <!-- Navigation Button -->\n <ax-button look=\"blank\" (onClick)=\"vm.navigateToFolder(item.id)\" [text]=\"item.name\" [disabled]=\"last\">\n @if(i === 0) {\n <ax-icon icon=\"fa-light fa-cloud\"></ax-icon>\n }@else {\n <ax-icon icon=\"fa-light fa-folder-closed\"></ax-icon>\n }\n </ax-button>\n <!-- Separator -->\n @if(!last) {\n <i class=\"far fa-chevron-right rtl:ax-rotate-180 fa-fw fa-xs ax-me-2\"></i>\n }\n <!-- End Navigation Button -->\n }\n</div>\n", styles: [":host{display:flex;width:100%;align-items:center}:host .__nav{display:flex;flex-direction:row;align-items:center;gap:.25rem;border-inline-end-width:1px;padding-inline-start:.25rem;padding-inline-end:.5rem}:host .__breadcrumb{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;padding-inline-start:.5rem;padding-inline-end:.25rem}:host .__breadcrumb .ax-state-disabled button,:host .__breadcrumb .ax-state-loading button{cursor:default!important}\n"] }]
6698
6784
  }] });
6699
6785
 
6700
- const UploadFromDriveHookProvider = {
6786
+ const UploadFromDriveActionProvider = {
6701
6787
  key: 'file-uploader.actions',
6702
- priority: 0,
6788
+ priority: 2,
6703
6789
  execute: (payload) => {
6704
6790
  const driveService = inject(AXMDocumentManagerService);
6705
6791
  const fileStorageService = inject(AXPFileStorageService);
@@ -6712,7 +6798,7 @@ const UploadFromDriveHookProvider = {
6712
6798
  global: true,
6713
6799
  textKey: '@document-management:actions.choose-from-drive',
6714
6800
  icon: 'fa-light fa-file-arrow-up',
6715
- run: async ({ host }) => {
6801
+ run: async (capabilities) => {
6716
6802
  const result = await driveService.showChooseFileDialog(AXPPlatformScope.Tenant);
6717
6803
  if (!result || result.length === 0) {
6718
6804
  return;
@@ -6724,29 +6810,25 @@ const UploadFromDriveHookProvider = {
6724
6810
  const dialogResult = await dialogService.confirm(dialogTitle, dialogMessage, 'primary', 'horizontal', false, 'cancel');
6725
6811
  // Yes/Okay -> clone, No/Cancel -> by-reference
6726
6812
  const attachmentType = dialogResult.result ? 'clone' : 'by-reference';
6727
- // Add files to host with uploading status
6728
- host.setValue([
6729
- ...(host.getValue() ?? []),
6730
- ...result.map((item) => ({
6731
- ...(item.fileId ?? {}),
6732
- status: 'uploading',
6733
- })),
6734
- ]);
6813
+ // Add files with uploading status
6814
+ const initialFiles = result.map((item) => ({
6815
+ ...(item.fileId ?? {}),
6816
+ status: 'uploading',
6817
+ }));
6818
+ capabilities.addFiles(initialFiles);
6735
6819
  // Process files based on attachment type
6736
6820
  for await (const item of result) {
6737
6821
  if (item.type === 'folder') {
6738
6822
  continue;
6739
6823
  }
6740
- const currentFiles = host.getValue();
6741
- const fileIndex = currentFiles.findIndex((f) => f.id === (item.fileId?.id ?? ''));
6742
- if (fileIndex === -1) {
6824
+ const fileId = item.fileId?.id ?? '';
6825
+ const currentFile = capabilities.getFileById(fileId);
6826
+ if (!currentFile) {
6743
6827
  continue;
6744
6828
  }
6745
6829
  if (attachmentType === 'by-reference') {
6746
6830
  // By reference: just set documentId
6747
- const updatedFiles = [...currentFiles];
6748
- updatedFiles[fileIndex] = {
6749
- ...updatedFiles[fileIndex],
6831
+ capabilities.updateFileById(fileId, {
6750
6832
  status: 'attached',
6751
6833
  source: {
6752
6834
  kind: 'reference',
@@ -6755,33 +6837,27 @@ const UploadFromDriveHookProvider = {
6755
6837
  type: 'document',
6756
6838
  },
6757
6839
  },
6758
- };
6759
- host.setValue(updatedFiles);
6840
+ });
6760
6841
  }
6761
6842
  else {
6762
6843
  // Clone: get file info and create blob
6763
6844
  try {
6764
- const storageInfo = await fileStorageService.getInfo(item.fileId?.id ?? '');
6845
+ const storageInfo = await fileStorageService.getInfo(fileId);
6765
6846
  if (!storageInfo) {
6766
- const currentFiles = host.getValue();
6767
- host.setValue(currentFiles.filter((f) => f.id !== (item.fileId?.id ?? '')));
6847
+ capabilities.removeFile(currentFile);
6768
6848
  continue;
6769
6849
  }
6770
- const updatedFiles = [...currentFiles];
6771
- updatedFiles[fileIndex] = {
6772
- ...updatedFiles[fileIndex],
6850
+ capabilities.updateFileById(fileId, {
6773
6851
  id: AXPDataGenerator.uuid(),
6774
6852
  status: 'attached',
6775
6853
  source: {
6776
6854
  kind: 'blob',
6777
6855
  value: new Blob([storageInfo.binary], { type: storageInfo.mimeType }),
6778
6856
  },
6779
- };
6780
- host.setValue(updatedFiles);
6857
+ });
6781
6858
  }
6782
6859
  catch {
6783
- const currentFiles = host.getValue();
6784
- host.setValue(currentFiles.filter((f) => f.id !== (item.fileId?.id ?? '')));
6860
+ capabilities.removeFile(currentFile);
6785
6861
  }
6786
6862
  }
6787
6863
  }
@@ -6796,7 +6872,8 @@ class AXMDriveChooseModule {
6796
6872
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMDriveChooseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
6797
6873
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.16", ngImport: i0, type: AXMDriveChooseModule }); }
6798
6874
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMDriveChooseModule, providers: [
6799
- { provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, useValue: UploadFromDriveHookProvider, multi: true }
6875
+ { provide: AXP_FILE_ACTION_PROVIDER, useValue: UploadFromComputerActionProvider, multi: true },
6876
+ { provide: AXP_FILE_ACTION_PROVIDER, useValue: UploadFromDriveActionProvider, multi: true }
6800
6877
  ] }); }
6801
6878
  }
6802
6879
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AXMDriveChooseModule, decorators: [{
@@ -6804,7 +6881,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6804
6881
  args: [{
6805
6882
  imports: [],
6806
6883
  providers: [
6807
- { provide: AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, useValue: UploadFromDriveHookProvider, multi: true }
6884
+ { provide: AXP_FILE_ACTION_PROVIDER, useValue: UploadFromComputerActionProvider, multi: true },
6885
+ { provide: AXP_FILE_ACTION_PROVIDER, useValue: UploadFromDriveActionProvider, multi: true }
6808
6886
  ]
6809
6887
  }]
6810
6888
  }] });