@acorex/modules 20.5.0-next.0 → 20.5.0-next.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,11 +1,11 @@
1
1
  import { AXP_PERMISSION_DEFINITION_PROVIDER, AXPSessionService } from '@acorex/platform/auth';
2
- import { AXPEntityCommandScope, createQueryView, AXPRefreshEvent, createAllQueryView, AXPEntityQueryType, AXPVersioningService, AXPSettingService, AXPSearchService, AXPLockService, AXPHomePageService, AXPSearchCommandProvider, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER } from '@acorex/platform/common';
2
+ import { AXPEntityCommandScope, createQueryView, AXPRefreshEvent, createAllQueryView, AXPEntityQueryType, AXPVersioningService, AXPSettingService, AXPSearchService, AXPHomePageService, AXPSearchCommandProvider, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER, AXPLockService } from '@acorex/platform/common';
3
3
  import * as i1$2 from '@acorex/platform/core';
4
4
  import { AXPExpressionEvaluatorService, getSmart, AXPPlatformScope, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER } from '@acorex/platform/core';
5
5
  import { ensureListActions, actionExists, AXPEntityDefinitionRegistryService, AXP_ENTITY_ACTION_PLUGIN, AXMEntityCrudServiceImpl, entityMasterCrudActions, entityMasterDeleteAction, AXP_ENTITY_DEFINITION_LOADER, AXP_ENTITY_STORAGE_BACKEND, AXP_ENTITY_STORAGE_MIDDLEWARE, AXPEntityService } from '@acorex/platform/layout/entity';
6
6
  import { AXPWidgetsModule } from '@acorex/platform/layout/widgets';
7
7
  import * as i0 from '@angular/core';
8
- import { inject, Injectable, NgModule, Injector, runInInjectionContext, input, signal, ViewEncapsulation, Component, InjectionToken, HostListener, computed } from '@angular/core';
8
+ import { inject, Injector, Injectable, NgModule, runInInjectionContext, input, signal, ViewEncapsulation, Component, InjectionToken, HostListener, computed } from '@angular/core';
9
9
  import * as i1 from '@acorex/platform/workflow';
10
10
  import { createWorkFlowEvent, AXPWorkflowAction, AXPWorkflowModule, AXPWorkflowService } from '@acorex/platform/workflow';
11
11
  import { AXDialogService } from '@acorex/components/dialog';
@@ -28,8 +28,45 @@ import { get, set } from 'lodash-es';
28
28
  import { provideCommandSetups } from '@acorex/platform/runtime';
29
29
  import { AXTextBoxModule } from '@acorex/components/text-box';
30
30
  import { Subject, firstValueFrom } from 'rxjs';
31
- import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
32
31
  import { AXCalendarService } from '@acorex/core/date-time';
32
+ import { AXPLayoutBuilderService } from '@acorex/platform/layout/builder';
33
+
34
+ const config = {
35
+ i18n: 'common',
36
+ module: 'Common',
37
+ };
38
+ const RootConfig = {
39
+ config,
40
+ module: {
41
+ route: 'common',
42
+ name: config.module,
43
+ title: '@common:module-name',
44
+ icon: 'fa-light fa-file-invoice',
45
+ },
46
+ entities: {},
47
+ };
48
+
49
+ //#region ---- Common Module Entity Provider ----
50
+ class AXMCommonModuleEntityProvider {
51
+ constructor() {
52
+ this.injector = inject(Injector);
53
+ }
54
+ preload() {
55
+ const module = RootConfig.module.name;
56
+ return Array.from(Object.values(RootConfig.entities)).map((entity) => ({
57
+ module: module,
58
+ entity: entity.name,
59
+ }));
60
+ }
61
+ async get(moduleName, entityName) {
62
+ return null;
63
+ }
64
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
65
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider }); }
66
+ }
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider, decorators: [{
68
+ type: Injectable
69
+ }] });
33
70
 
34
71
  const AXPWidgetsList = {
35
72
  Editors: {
@@ -3947,525 +3984,193 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
3947
3984
  }]
3948
3985
  }] });
3949
3986
 
3950
- const lockGuardMiddleware = {
3951
- target: { ops: ['update', 'delete'], order: 10 },
3952
- execute: async (ctx, next) => {
3953
- const lockService = inject(AXPLockService);
3954
- const session = inject(AXPSessionService);
3955
- const lock = await lockService.check({ refId: ctx.id, refType: ctx.entityName });
3956
- if (lock) {
3957
- const info = await lockService.getInfo({ refId: ctx.id, refType: ctx.entityName });
3958
- if (info && session.user && info.lockedBy.id !== session.user.id) {
3959
- throw new Error('This record is locked and cannot be edited.');
3960
- }
3987
+ const primaryPlugin = {
3988
+ name: 'primary',
3989
+ order: 66,
3990
+ apply: (ctx) => {
3991
+ ensureListActions(ctx);
3992
+ //#region ---- Add isPrimary Property ----
3993
+ // Ensure settings group exists
3994
+ const groupId = 'settings';
3995
+ const groups = ctx.groups.list() ?? [];
3996
+ if (!groups.some((g) => g.id === groupId)) {
3997
+ ctx.groups.add({ id: groupId, title: '@general:terms.interface.settings' });
3961
3998
  }
3962
- await next();
3999
+ // Add isPrimary property if it doesn't exist
4000
+ const props = ctx.properties.list();
4001
+ if (!props.some((p) => p.name === 'isPrimary')) {
4002
+ ctx.properties.add({
4003
+ name: 'isPrimary',
4004
+ title: '@general:terms.status.states.is-primary',
4005
+ groupId,
4006
+ schema: {
4007
+ dataType: 'boolean',
4008
+ interface: {
4009
+ type: AXPWidgetsList.Editors.ToggleSwitch,
4010
+ options: {
4011
+ // Default to false (not primary)
4012
+ defaultValue: false,
4013
+ negative: false,
4014
+ nullValue: false,
4015
+ },
4016
+ },
4017
+ },
4018
+ validations: [],
4019
+ options: {
4020
+ sort: { enabled: true },
4021
+ filter: {
4022
+ advance: { enabled: true },
4023
+ inline: { enabled: true }
4024
+ }
4025
+ }
4026
+ });
4027
+ }
4028
+ //#endregion
4029
+ // Add isPrimary to columns for list view
4030
+ const columns = ctx.columns.list() ?? [];
4031
+ if (!columns.some((c) => c.name === 'isPrimary')) {
4032
+ ctx.columns.add({
4033
+ name: 'isPrimary',
4034
+ title: '@general:terms.status.states.is-primary',
4035
+ width: 100,
4036
+ sortable: true,
4037
+ filterable: true,
4038
+ });
4039
+ }
4040
+ //#endregion
4041
+ //#region ---- Add Primary Actions ----
4042
+ ctx.interfaces.update((i) => {
4043
+ const setPrimaryCmdName = 'set-primary-entity';
4044
+ // Add set primary action to list view
4045
+ const listActions = i.master.list.actions;
4046
+ if (!actionExists(listActions, setPrimaryCmdName)) {
4047
+ listActions.push({
4048
+ title: '@general:actions.set-primary.title',
4049
+ command: {
4050
+ name: setPrimaryCmdName,
4051
+ options: {
4052
+ refId: '{{ context.eval("id") }}',
4053
+ refType: `${ctx.entity.module}.${ctx.entity.name}`,
4054
+ },
4055
+ },
4056
+ priority: 'secondary',
4057
+ type: 'update',
4058
+ scope: AXPEntityCommandScope.Individual,
4059
+ hidden: `{{ context.eval("isPrimary") }}`,
4060
+ });
4061
+ }
4062
+ // Add set primary action to single view
4063
+ const singleActions = i.master?.single?.actions || [];
4064
+ if (!actionExists(singleActions, setPrimaryCmdName)) {
4065
+ singleActions.push({
4066
+ title: '@general:actions.set-primary.title',
4067
+ command: {
4068
+ name: setPrimaryCmdName,
4069
+ options: {
4070
+ refId: '{{ context.eval("id") }}',
4071
+ refType: `${ctx.entity.module}.${ctx.entity.name}`,
4072
+ },
4073
+ },
4074
+ priority: 'secondary',
4075
+ type: 'update',
4076
+ scope: AXPEntityCommandScope.Individual,
4077
+ hidden: `{{ context.eval("isPrimary") }}`,
4078
+ });
4079
+ }
4080
+ return i;
4081
+ });
4082
+ //#endregion
4083
+ //#region ---- Update Interface Layouts ----
4084
+ // Ensure create view includes isPrimary
4085
+ ctx.interfaces.master.create.update((create) => {
4086
+ const next = create ?? { sections: [], properties: [] };
4087
+ next.sections = next.sections ?? [];
4088
+ if (!next.sections.some((s) => s.id === groupId)) {
4089
+ next.sections.push({ id: groupId });
4090
+ }
4091
+ next.properties = next.properties ?? [];
4092
+ if (!next.properties.some((p) => p.name === 'isPrimary')) {
4093
+ next.properties.push({
4094
+ name: 'isPrimary',
4095
+ layout: {
4096
+ positions: { lg: { colSpan: 6, order: 90 } },
4097
+ },
4098
+ });
4099
+ }
4100
+ return next;
4101
+ });
4102
+ // Ensure update view includes isPrimary
4103
+ ctx.interfaces.master.modify.update((update) => {
4104
+ const next = update ?? { sections: [], properties: [] };
4105
+ next.sections = next.sections ?? [];
4106
+ if (!next.sections.some((s) => s.id === groupId)) {
4107
+ next.sections.push({ id: groupId });
4108
+ }
4109
+ next.properties = next.properties ?? [];
4110
+ if (!next.properties.some((p) => p.name === 'isPrimary')) {
4111
+ next.properties.push({
4112
+ name: 'isPrimary',
4113
+ layout: {
4114
+ positions: { lg: { colSpan: 6, order: 90 } },
4115
+ },
4116
+ });
4117
+ }
4118
+ return next;
4119
+ });
4120
+ // Ensure single view includes isPrimary
4121
+ ctx.interfaces.master.single.update((single) => {
4122
+ const next = single ?? { title: ctx.entity.title, sections: [], properties: [] };
4123
+ next.sections = next.sections ?? [];
4124
+ if (!next.sections.some((s) => s.id === groupId)) {
4125
+ next.sections.push({ id: groupId, order: 150 });
4126
+ }
4127
+ next.properties = next.properties ?? [];
4128
+ if (!next.properties.some((p) => p.name === 'isPrimary')) {
4129
+ next.properties.push({
4130
+ name: 'isPrimary',
4131
+ layout: {
4132
+ positions: { lg: { colSpan: 6, order: 90 } },
4133
+ },
4134
+ });
4135
+ }
4136
+ return next;
4137
+ });
4138
+ // Add primary view to show only primary items
4139
+ ctx.interfaces.master.list.update((list) => {
4140
+ const next = list ?? { actions: [], views: [] };
4141
+ next.views = next.views ?? [];
4142
+ // Check if primary view already exists
4143
+ if (!next.views.some((v) => v.name === 'primary')) {
4144
+ next.views.push(createQueryView('primary', '@general:terms.status.states.is-primary', false, {
4145
+ conditions: [
4146
+ {
4147
+ name: 'isPrimary',
4148
+ operator: { type: 'equal' },
4149
+ value: true,
4150
+ hidden: true
4151
+ },
4152
+ ],
4153
+ sorts: [
4154
+ { name: 'updatedAt', dir: 'desc' },
4155
+ { name: 'title', dir: 'asc' },
4156
+ ],
4157
+ }));
4158
+ }
4159
+ return next;
4160
+ });
4161
+ //#endregion
3963
4162
  },
3964
4163
  };
3965
4164
 
3966
- class AXMLockPopupWorkflowAction extends AXPWorkflowAction {
3967
- constructor() {
3968
- super(...arguments);
3969
- this.translationService = inject(AXTranslationService);
3970
- this.layoutBuilder = inject(AXPLayoutBuilderService);
3971
- this.lockService = inject(AXPLockService);
3972
- this.sessionService = inject(AXPSessionService);
3973
- }
3974
- async execute(context) {
3975
- const refId = context.getVariable('options.refId');
3976
- const refType = context.getVariable('options.refType');
3977
- const durationOptions = [
3978
- {
3979
- value: '1h',
3980
- text: await this.translationService.translateAsync('@lock-system:lock.duration.options.1h'),
3981
- hours: 1,
3982
- },
3983
- {
3984
- value: '1d',
3985
- text: await this.translationService.translateAsync('@lock-system:lock.duration.options.1d'),
3986
- hours: 24,
3987
- },
4165
+ class AXPPrimaryPluginModule {
4166
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
4167
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule }); }
4168
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule, providers: [
4169
+ // Register the primary plugin
3988
4170
  {
3989
- value: 'infinite',
3990
- text: await this.translationService.translateAsync('@lock-system:lock.duration.options.infinite'),
3991
- },
3992
- ];
3993
- const dialogTitle = await this.translationService.translateAsync('@lock-system:lock.dialog.title');
3994
- const dialogRef = await this.layoutBuilder
3995
- .create()
3996
- .dialog(dialog => {
3997
- dialog
3998
- .setTitle(dialogTitle)
3999
- .setContext({ duration: '1h', reason: '' })
4000
- .content(flex => {
4001
- flex
4002
- .setDirection('column')
4003
- .formField('@lock-system:lock.duration.title', field => {
4004
- field.path('duration');
4005
- field.selectBox({
4006
- valueField: 'value',
4007
- textField: 'text',
4008
- dataSource: durationOptions,
4009
- validations: [{ rule: 'required' }],
4010
- });
4011
- })
4012
- .formField('@lock-system:lock.reason.title', field => {
4013
- field.path('reason');
4014
- field.largeTextBox({
4015
- rows: 3,
4016
- placeholder: '@lock-system:lock.reason.placeholder',
4017
- });
4018
- });
4019
- })
4020
- .setActions(actions => {
4021
- actions.cancel('@lock-system:lock.dialog.cancel');
4022
- const confirmAction = {
4023
- title: '@lock-system:lock.dialog.confirm',
4024
- color: 'primary',
4025
- command: { name: 'submit', options: { validate: true } },
4026
- };
4027
- actions.custom(confirmAction);
4028
- });
4029
- })
4030
- .show();
4031
- const action = dialogRef.action();
4032
- if (action === 'cancel') {
4033
- context.setOutput('isCanceled', true);
4034
- dialogRef.close();
4035
- return;
4036
- }
4037
- const form = dialogRef.context();
4038
- const selected = form?.duration ?? '1h';
4039
- const selectedDuration = durationOptions.find((d) => d.value === selected);
4040
- const expireAt = selectedDuration?.hours
4041
- ? new Date(Date.now() + selectedDuration.hours * 60 * 60 * 1000)
4042
- : undefined;
4043
- await this.lockService.lock({
4044
- refId,
4045
- refType,
4046
- type: 'user',
4047
- date: new Date().toISOString(),
4048
- expireAt,
4049
- lockedBy: {
4050
- id: this.sessionService.user?.id ?? 'system',
4051
- type: 'oidc.users',
4052
- },
4053
- });
4054
- dialogRef.close();
4055
- context.setOutput('isCanceled', false);
4056
- context.setOutput('lockDuration', form?.duration ?? '1h');
4057
- context.setOutput('lockReason', form?.reason ?? '');
4058
- }
4059
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
4060
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction }); }
4061
- }
4062
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction, decorators: [{
4063
- type: Injectable
4064
- }] });
4065
- const AXMLockPopupWorkflow = {
4066
- startStepId: 'lock-popup',
4067
- steps: {
4068
- 'lock-popup': {
4069
- action: 'AXMLockPopupWorkflowAction',
4070
- nextSteps: [
4071
- {
4072
- conditions: [{ type: 'SINGLE', expression: 'context.getOutput("isCanceled") == false' }],
4073
- nextStepId: 'successToast',
4074
- },
4075
- ],
4076
- },
4077
- successToast: {
4078
- id: 'successToast',
4079
- action: 'AXPToastAction',
4080
- input: {
4081
- color: 'success',
4082
- title: 'workflow.entity-modified-title',
4083
- content: 'workflow.entity-modified-body',
4084
- },
4085
- nextSteps: [
4086
- {
4087
- conditions: [],
4088
- nextStepId: 'modifyConfirmed',
4089
- },
4090
- ],
4091
- },
4092
- modifyConfirmed: {
4093
- id: 'modifyConfirmed',
4094
- action: 'AXPEntityModifyConfirmedAction',
4095
- },
4096
- },
4097
- };
4098
-
4099
- class AXMUnlockConfirmWorkflowAction extends AXPWorkflowAction {
4100
- constructor() {
4101
- super(...arguments);
4102
- this.dialogService = inject(AXDialogService);
4103
- this.translationService = inject(AXTranslationService);
4104
- this.lockService = inject(AXPLockService);
4105
- this.sessionService = inject(AXPSessionService);
4106
- }
4107
- async execute(context) {
4108
- const refId = context.getVariable('options.refId');
4109
- const refType = context.getVariable('options.refType');
4110
- // Show confirmation dialog
4111
- const dialogResult = await this.dialogService.confirm(await this.translationService.translateAsync('@lock-system:unlock.dialog.title'), await this.translationService.translateAsync('@lock-system:unlock.dialog.description'), 'warning', 'horizontal', false, 'cancel');
4112
- if (dialogResult.result) {
4113
- try {
4114
- // Perform unlock
4115
- await this.lockService.unlock({
4116
- refId: refId,
4117
- refType: refType,
4118
- type: 'user',
4119
- });
4120
- context.setOutput('isCanceled', false);
4121
- context.setOutput('unlocked', true);
4122
- }
4123
- catch (error) {
4124
- console.error('Unlock failed:', error);
4125
- // Show error dialog
4126
- await this.dialogService.alert(await this.translationService.translateAsync('@lock-system:unlock.error.title'), await this.translationService.translateAsync('@lock-system:unlock.error.description'), 'danger');
4127
- context.setOutput('isCanceled', true);
4128
- context.setOutput('unlocked', false);
4129
- }
4130
- }
4131
- else {
4132
- context.setOutput('isCanceled', true);
4133
- context.setOutput('unlocked', false);
4134
- }
4135
- }
4136
- }
4137
- const AXMUnlockConfirmWorkflow = {
4138
- startStepId: 'unlock-confirm',
4139
- steps: {
4140
- 'unlock-confirm': {
4141
- action: 'AXMUnlockConfirmWorkflowAction',
4142
- nextSteps: [
4143
- {
4144
- conditions: [{ type: 'SINGLE', expression: 'context.getOutput("unlocked") == true' }],
4145
- nextStepId: 'successToast',
4146
- },
4147
- ],
4148
- },
4149
- successToast: {
4150
- id: 'successToast',
4151
- action: 'AXPToastAction',
4152
- input: {
4153
- color: 'success',
4154
- title: 'workflow.entity-modified-title',
4155
- content: 'workflow.entity-modified-body',
4156
- },
4157
- nextSteps: [
4158
- {
4159
- conditions: [],
4160
- nextStepId: 'modifyConfirmed',
4161
- },
4162
- ],
4163
- },
4164
- modifyConfirmed: {
4165
- id: 'modifyConfirmed',
4166
- action: 'AXPEntityModifyConfirmedAction',
4167
- },
4168
- },
4169
- };
4170
-
4171
- class AXMLockEvaluatorScopeProvider {
4172
- constructor() {
4173
- this.lockService = inject(AXPLockService);
4174
- }
4175
- async provide(context) {
4176
- context.addScope('lock', {
4177
- check: async (refId, refType) => {
4178
- const lock = await this.lockService.check({
4179
- refId, refType
4180
- });
4181
- return lock;
4182
- }
4183
- });
4184
- }
4185
- }
4186
-
4187
- const lockPlugin = {
4188
- name: 'lock',
4189
- order: 50,
4190
- apply: (ctx) => {
4191
- ensureListActions(ctx);
4192
- ctx.interfaces.update((i) => {
4193
- const actions = i.master.list.actions;
4194
- ctx.properties.list().forEach(p => {
4195
- if (p.schema.interface) {
4196
- p.schema.interface.options = {
4197
- ...p.schema.interface.options,
4198
- readonly: `{{ lock.check(context.eval("id"), "${ctx.entity.module}.${ctx.entity.name}") }}`
4199
- };
4200
- }
4201
- });
4202
- if (!actions.some((a) => a.name === 'lock-entity')) {
4203
- actions.push({
4204
- title: '@lock-system:lock.title',
4205
- name: 'lock-entity',
4206
- command: {
4207
- name: 'lock-popup',
4208
- options: {
4209
- refId: '{{ context.eval("id") }}',
4210
- refType: `${ctx.entity.module}.${ctx.entity.name}`,
4211
- },
4212
- },
4213
- priority: 'secondary',
4214
- type: 'lock',
4215
- scope: AXPEntityCommandScope.Individual,
4216
- hidden: `{{ lock.check(context.eval("id"), "${ctx.entity.module}.${ctx.entity.name}") }}`,
4217
- });
4218
- }
4219
- if (!actions.some((a) => a.name === 'unlock-entity')) {
4220
- actions.push({
4221
- title: '@lock-system:unlock.title',
4222
- name: 'unlock-entity',
4223
- command: {
4224
- name: 'unlock-confirm',
4225
- options: {
4226
- refId: '{{ context.eval("id") }}',
4227
- refType: `${ctx.entity.module}.${ctx.entity.name}`,
4228
- },
4229
- },
4230
- priority: 'secondary',
4231
- type: 'unlock',
4232
- scope: AXPEntityCommandScope.Individual,
4233
- hidden: `{{ (await lock.check(context.eval("id"), "${ctx.entity.module}.${ctx.entity.name}")) == false }}`,
4234
- });
4235
- }
4236
- return i;
4237
- });
4238
- },
4239
- };
4240
-
4241
- class AXMLockSystemModule {
4242
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockSystemModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
4243
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXMLockSystemModule, imports: [i1.AXPWorkflowModule] }); }
4244
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockSystemModule, providers: [
4245
- { provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, multi: true, useClass: AXMLockEvaluatorScopeProvider },
4246
- { provide: AXP_ENTITY_ACTION_PLUGIN, multi: true, useValue: lockPlugin },
4247
- { provide: AXP_ENTITY_STORAGE_MIDDLEWARE, multi: true, useValue: lockGuardMiddleware },
4248
- ], imports: [AXPWorkflowModule.forChild({
4249
- actions: {
4250
- AXMLockPopupWorkflowAction,
4251
- AXMUnlockConfirmWorkflowAction,
4252
- },
4253
- workflows: {
4254
- 'lock-popup': AXMLockPopupWorkflow,
4255
- 'unlock-confirm': AXMUnlockConfirmWorkflow,
4256
- },
4257
- })] }); }
4258
- }
4259
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockSystemModule, decorators: [{
4260
- type: NgModule,
4261
- args: [{
4262
- imports: [
4263
- AXPWorkflowModule.forChild({
4264
- actions: {
4265
- AXMLockPopupWorkflowAction,
4266
- AXMUnlockConfirmWorkflowAction,
4267
- },
4268
- workflows: {
4269
- 'lock-popup': AXMLockPopupWorkflow,
4270
- 'unlock-confirm': AXMUnlockConfirmWorkflow,
4271
- },
4272
- }),
4273
- ],
4274
- providers: [
4275
- { provide: AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, multi: true, useClass: AXMLockEvaluatorScopeProvider },
4276
- { provide: AXP_ENTITY_ACTION_PLUGIN, multi: true, useValue: lockPlugin },
4277
- { provide: AXP_ENTITY_STORAGE_MIDDLEWARE, multi: true, useValue: lockGuardMiddleware },
4278
- ],
4279
- }]
4280
- }] });
4281
-
4282
- const primaryPlugin = {
4283
- name: 'primary',
4284
- order: 66,
4285
- apply: (ctx) => {
4286
- ensureListActions(ctx);
4287
- //#region ---- Add isPrimary Property ----
4288
- // Ensure settings group exists
4289
- const groupId = 'settings';
4290
- const groups = ctx.groups.list() ?? [];
4291
- if (!groups.some((g) => g.id === groupId)) {
4292
- ctx.groups.add({ id: groupId, title: '@general:terms.interface.settings' });
4293
- }
4294
- // Add isPrimary property if it doesn't exist
4295
- const props = ctx.properties.list();
4296
- if (!props.some((p) => p.name === 'isPrimary')) {
4297
- ctx.properties.add({
4298
- name: 'isPrimary',
4299
- title: '@general:terms.status.states.is-primary',
4300
- groupId,
4301
- schema: {
4302
- dataType: 'boolean',
4303
- interface: {
4304
- type: AXPWidgetsList.Editors.ToggleSwitch,
4305
- options: {
4306
- // Default to false (not primary)
4307
- defaultValue: false,
4308
- negative: false,
4309
- nullValue: false,
4310
- },
4311
- },
4312
- },
4313
- validations: [],
4314
- options: {
4315
- sort: { enabled: true },
4316
- filter: {
4317
- advance: { enabled: true },
4318
- inline: { enabled: true }
4319
- }
4320
- }
4321
- });
4322
- }
4323
- //#endregion
4324
- // Add isPrimary to columns for list view
4325
- const columns = ctx.columns.list() ?? [];
4326
- if (!columns.some((c) => c.name === 'isPrimary')) {
4327
- ctx.columns.add({
4328
- name: 'isPrimary',
4329
- title: '@general:terms.status.states.is-primary',
4330
- width: 100,
4331
- sortable: true,
4332
- filterable: true,
4333
- });
4334
- }
4335
- //#endregion
4336
- //#region ---- Add Primary Actions ----
4337
- ctx.interfaces.update((i) => {
4338
- const setPrimaryCmdName = 'set-primary-entity';
4339
- // Add set primary action to list view
4340
- const listActions = i.master.list.actions;
4341
- if (!actionExists(listActions, setPrimaryCmdName)) {
4342
- listActions.push({
4343
- title: '@general:actions.set-primary.title',
4344
- command: {
4345
- name: setPrimaryCmdName,
4346
- options: {
4347
- refId: '{{ context.eval("id") }}',
4348
- refType: `${ctx.entity.module}.${ctx.entity.name}`,
4349
- },
4350
- },
4351
- priority: 'secondary',
4352
- type: 'update',
4353
- scope: AXPEntityCommandScope.Individual,
4354
- hidden: `{{ context.eval("isPrimary") }}`,
4355
- });
4356
- }
4357
- // Add set primary action to single view
4358
- const singleActions = i.master?.single?.actions || [];
4359
- if (!actionExists(singleActions, setPrimaryCmdName)) {
4360
- singleActions.push({
4361
- title: '@general:actions.set-primary.title',
4362
- command: {
4363
- name: setPrimaryCmdName,
4364
- options: {
4365
- refId: '{{ context.eval("id") }}',
4366
- refType: `${ctx.entity.module}.${ctx.entity.name}`,
4367
- },
4368
- },
4369
- priority: 'secondary',
4370
- type: 'update',
4371
- scope: AXPEntityCommandScope.Individual,
4372
- hidden: `{{ context.eval("isPrimary") }}`,
4373
- });
4374
- }
4375
- return i;
4376
- });
4377
- //#endregion
4378
- //#region ---- Update Interface Layouts ----
4379
- // Ensure create view includes isPrimary
4380
- ctx.interfaces.master.create.update((create) => {
4381
- const next = create ?? { sections: [], properties: [] };
4382
- next.sections = next.sections ?? [];
4383
- if (!next.sections.some((s) => s.id === groupId)) {
4384
- next.sections.push({ id: groupId });
4385
- }
4386
- next.properties = next.properties ?? [];
4387
- if (!next.properties.some((p) => p.name === 'isPrimary')) {
4388
- next.properties.push({
4389
- name: 'isPrimary',
4390
- layout: {
4391
- positions: { lg: { colSpan: 6, order: 90 } },
4392
- },
4393
- });
4394
- }
4395
- return next;
4396
- });
4397
- // Ensure update view includes isPrimary
4398
- ctx.interfaces.master.modify.update((update) => {
4399
- const next = update ?? { sections: [], properties: [] };
4400
- next.sections = next.sections ?? [];
4401
- if (!next.sections.some((s) => s.id === groupId)) {
4402
- next.sections.push({ id: groupId });
4403
- }
4404
- next.properties = next.properties ?? [];
4405
- if (!next.properties.some((p) => p.name === 'isPrimary')) {
4406
- next.properties.push({
4407
- name: 'isPrimary',
4408
- layout: {
4409
- positions: { lg: { colSpan: 6, order: 90 } },
4410
- },
4411
- });
4412
- }
4413
- return next;
4414
- });
4415
- // Ensure single view includes isPrimary
4416
- ctx.interfaces.master.single.update((single) => {
4417
- const next = single ?? { title: ctx.entity.title, sections: [], properties: [] };
4418
- next.sections = next.sections ?? [];
4419
- if (!next.sections.some((s) => s.id === groupId)) {
4420
- next.sections.push({ id: groupId, order: 150 });
4421
- }
4422
- next.properties = next.properties ?? [];
4423
- if (!next.properties.some((p) => p.name === 'isPrimary')) {
4424
- next.properties.push({
4425
- name: 'isPrimary',
4426
- layout: {
4427
- positions: { lg: { colSpan: 6, order: 90 } },
4428
- },
4429
- });
4430
- }
4431
- return next;
4432
- });
4433
- // Add primary view to show only primary items
4434
- ctx.interfaces.master.list.update((list) => {
4435
- const next = list ?? { actions: [], views: [] };
4436
- next.views = next.views ?? [];
4437
- // Check if primary view already exists
4438
- if (!next.views.some((v) => v.name === 'primary')) {
4439
- next.views.push(createQueryView('primary', '@general:terms.status.states.is-primary', false, {
4440
- conditions: [
4441
- {
4442
- name: 'isPrimary',
4443
- operator: { type: 'equal' },
4444
- value: true,
4445
- hidden: true
4446
- },
4447
- ],
4448
- sorts: [
4449
- { name: 'updatedAt', dir: 'desc' },
4450
- { name: 'title', dir: 'asc' },
4451
- ],
4452
- }));
4453
- }
4454
- return next;
4455
- });
4456
- //#endregion
4457
- },
4458
- };
4459
-
4460
- class AXPPrimaryPluginModule {
4461
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
4462
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule }); }
4463
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPPrimaryPluginModule, providers: [
4464
- // Register the primary plugin
4465
- {
4466
- provide: AXP_ENTITY_ACTION_PLUGIN,
4467
- useValue: primaryPlugin,
4468
- multi: true,
4171
+ provide: AXP_ENTITY_ACTION_PLUGIN,
4172
+ useValue: primaryPlugin,
4173
+ multi: true,
4469
4174
  },
4470
4175
  ] }); }
4471
4176
  }
@@ -4638,43 +4343,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4638
4343
  }]
4639
4344
  }] });
4640
4345
 
4641
- const config = {
4642
- i18n: 'common',
4643
- module: 'Common',
4644
- };
4645
- const RootConfig = {
4646
- config,
4647
- module: {
4648
- route: 'common',
4649
- name: config.module,
4650
- title: '@common:module-name',
4651
- icon: 'fa-light fa-file-invoice',
4652
- },
4653
- entities: {},
4654
- };
4655
-
4656
- //#region ---- Common Module Entity Provider ----
4657
- class AXMCommonModuleEntityProvider {
4658
- constructor() {
4659
- this.injector = inject(Injector);
4660
- }
4661
- preload() {
4662
- const module = RootConfig.module.name;
4663
- return Array.from(Object.values(RootConfig.entities)).map((entity) => ({
4664
- module: module,
4665
- entity: entity.name,
4666
- }));
4667
- }
4668
- async get(moduleName, entityName) {
4669
- return null;
4670
- }
4671
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4672
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider }); }
4673
- }
4674
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModuleEntityProvider, decorators: [{
4675
- type: Injectable
4676
- }] });
4677
-
4678
4346
  const AXPCommonMenuKeys = {
4679
4347
  Home: 'app:home',
4680
4348
  };
@@ -4781,8 +4449,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4781
4449
 
4782
4450
  class AXMCommonModule {
4783
4451
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
4784
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModule, imports: [AXMLockSystemModule,
4785
- AXPExtraPropertiesModule,
4452
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: AXMCommonModule, imports: [AXPExtraPropertiesModule,
4786
4453
  AXPCategoryModule,
4787
4454
  AXPGlobalSearchModule,
4788
4455
  AXPWidgetsModule,
@@ -4832,8 +4499,7 @@ class AXMCommonModule {
4832
4499
  useClass: AXMCommonModuleEntityProvider,
4833
4500
  multi: true,
4834
4501
  },
4835
- ], imports: [AXMLockSystemModule,
4836
- AXPExtraPropertiesModule,
4502
+ ], imports: [AXPExtraPropertiesModule,
4837
4503
  AXPCategoryModule,
4838
4504
  AXPGlobalSearchModule,
4839
4505
  AXPWidgetsModule,
@@ -4852,7 +4518,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4852
4518
  type: NgModule,
4853
4519
  args: [{
4854
4520
  imports: [
4855
- AXMLockSystemModule,
4856
4521
  AXPExtraPropertiesModule,
4857
4522
  AXPCategoryModule,
4858
4523
  AXPGlobalSearchModule,
@@ -4910,6 +4575,211 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
4910
4575
  }]
4911
4576
  }] });
4912
4577
 
4578
+ class AXMLockPopupWorkflowAction extends AXPWorkflowAction {
4579
+ constructor() {
4580
+ super(...arguments);
4581
+ this.translationService = inject(AXTranslationService);
4582
+ this.layoutBuilder = inject(AXPLayoutBuilderService);
4583
+ this.lockService = inject(AXPLockService);
4584
+ this.sessionService = inject(AXPSessionService);
4585
+ }
4586
+ async execute(context) {
4587
+ const refId = context.getVariable('options.refId');
4588
+ const refType = context.getVariable('options.refType');
4589
+ const durationOptions = [
4590
+ {
4591
+ value: '1h',
4592
+ text: await this.translationService.translateAsync('@lock-system:lock.duration.options.1h'),
4593
+ hours: 1,
4594
+ },
4595
+ {
4596
+ value: '1d',
4597
+ text: await this.translationService.translateAsync('@lock-system:lock.duration.options.1d'),
4598
+ hours: 24,
4599
+ },
4600
+ {
4601
+ value: 'infinite',
4602
+ text: await this.translationService.translateAsync('@lock-system:lock.duration.options.infinite'),
4603
+ },
4604
+ ];
4605
+ const dialogTitle = await this.translationService.translateAsync('@lock-system:lock.dialog.title');
4606
+ const dialogRef = await this.layoutBuilder
4607
+ .create()
4608
+ .dialog(dialog => {
4609
+ dialog
4610
+ .setTitle(dialogTitle)
4611
+ .setContext({ duration: '1h', reason: '' })
4612
+ .content(flex => {
4613
+ flex
4614
+ .setDirection('column')
4615
+ .formField('@lock-system:lock.duration.title', field => {
4616
+ field.path('duration');
4617
+ field.selectBox({
4618
+ valueField: 'value',
4619
+ textField: 'text',
4620
+ dataSource: durationOptions,
4621
+ validations: [{ rule: 'required' }],
4622
+ });
4623
+ })
4624
+ .formField('@lock-system:lock.reason.title', field => {
4625
+ field.path('reason');
4626
+ field.largeTextBox({
4627
+ rows: 3,
4628
+ placeholder: '@lock-system:lock.reason.placeholder',
4629
+ });
4630
+ });
4631
+ })
4632
+ .setActions(actions => {
4633
+ actions.cancel('@lock-system:lock.dialog.cancel');
4634
+ const confirmAction = {
4635
+ title: '@lock-system:lock.dialog.confirm',
4636
+ color: 'primary',
4637
+ command: { name: 'submit', options: { validate: true } },
4638
+ };
4639
+ actions.custom(confirmAction);
4640
+ });
4641
+ })
4642
+ .show();
4643
+ const action = dialogRef.action();
4644
+ if (action === 'cancel') {
4645
+ context.setOutput('isCanceled', true);
4646
+ dialogRef.close();
4647
+ return;
4648
+ }
4649
+ const form = dialogRef.context();
4650
+ const selected = form?.duration ?? '1h';
4651
+ const selectedDuration = durationOptions.find((d) => d.value === selected);
4652
+ const expireAt = selectedDuration?.hours
4653
+ ? new Date(Date.now() + selectedDuration.hours * 60 * 60 * 1000)
4654
+ : undefined;
4655
+ await this.lockService.lock({
4656
+ refId,
4657
+ refType,
4658
+ type: 'user',
4659
+ date: new Date().toISOString(),
4660
+ expireAt,
4661
+ lockedBy: {
4662
+ id: this.sessionService.user?.id ?? 'system',
4663
+ type: 'oidc.users',
4664
+ },
4665
+ });
4666
+ dialogRef.close();
4667
+ context.setOutput('isCanceled', false);
4668
+ context.setOutput('lockDuration', form?.duration ?? '1h');
4669
+ context.setOutput('lockReason', form?.reason ?? '');
4670
+ }
4671
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
4672
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction }); }
4673
+ }
4674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXMLockPopupWorkflowAction, decorators: [{
4675
+ type: Injectable
4676
+ }] });
4677
+ const AXMLockPopupWorkflow = {
4678
+ startStepId: 'lock-popup',
4679
+ steps: {
4680
+ 'lock-popup': {
4681
+ action: 'AXMLockPopupWorkflowAction',
4682
+ nextSteps: [
4683
+ {
4684
+ conditions: [{ type: 'SINGLE', expression: 'context.getOutput("isCanceled") == false' }],
4685
+ nextStepId: 'successToast',
4686
+ },
4687
+ ],
4688
+ },
4689
+ successToast: {
4690
+ id: 'successToast',
4691
+ action: 'AXPToastAction',
4692
+ input: {
4693
+ color: 'success',
4694
+ title: 'workflow.entity-modified-title',
4695
+ content: 'workflow.entity-modified-body',
4696
+ },
4697
+ nextSteps: [
4698
+ {
4699
+ conditions: [],
4700
+ nextStepId: 'modifyConfirmed',
4701
+ },
4702
+ ],
4703
+ },
4704
+ modifyConfirmed: {
4705
+ id: 'modifyConfirmed',
4706
+ action: 'AXPEntityModifyConfirmedAction',
4707
+ },
4708
+ },
4709
+ };
4710
+
4711
+ class AXMUnlockConfirmWorkflowAction extends AXPWorkflowAction {
4712
+ constructor() {
4713
+ super(...arguments);
4714
+ this.dialogService = inject(AXDialogService);
4715
+ this.translationService = inject(AXTranslationService);
4716
+ this.lockService = inject(AXPLockService);
4717
+ this.sessionService = inject(AXPSessionService);
4718
+ }
4719
+ async execute(context) {
4720
+ const refId = context.getVariable('options.refId');
4721
+ const refType = context.getVariable('options.refType');
4722
+ // Show confirmation dialog
4723
+ const dialogResult = await this.dialogService.confirm(await this.translationService.translateAsync('@lock-system:unlock.dialog.title'), await this.translationService.translateAsync('@lock-system:unlock.dialog.description'), 'warning', 'horizontal', false, 'cancel');
4724
+ if (dialogResult.result) {
4725
+ try {
4726
+ // Perform unlock
4727
+ await this.lockService.unlock({
4728
+ refId: refId,
4729
+ refType: refType,
4730
+ type: 'user',
4731
+ });
4732
+ context.setOutput('isCanceled', false);
4733
+ context.setOutput('unlocked', true);
4734
+ }
4735
+ catch (error) {
4736
+ console.error('Unlock failed:', error);
4737
+ // Show error dialog
4738
+ await this.dialogService.alert(await this.translationService.translateAsync('@lock-system:unlock.error.title'), await this.translationService.translateAsync('@lock-system:unlock.error.description'), 'danger');
4739
+ context.setOutput('isCanceled', true);
4740
+ context.setOutput('unlocked', false);
4741
+ }
4742
+ }
4743
+ else {
4744
+ context.setOutput('isCanceled', true);
4745
+ context.setOutput('unlocked', false);
4746
+ }
4747
+ }
4748
+ }
4749
+ const AXMUnlockConfirmWorkflow = {
4750
+ startStepId: 'unlock-confirm',
4751
+ steps: {
4752
+ 'unlock-confirm': {
4753
+ action: 'AXMUnlockConfirmWorkflowAction',
4754
+ nextSteps: [
4755
+ {
4756
+ conditions: [{ type: 'SINGLE', expression: 'context.getOutput("unlocked") == true' }],
4757
+ nextStepId: 'successToast',
4758
+ },
4759
+ ],
4760
+ },
4761
+ successToast: {
4762
+ id: 'successToast',
4763
+ action: 'AXPToastAction',
4764
+ input: {
4765
+ color: 'success',
4766
+ title: 'workflow.entity-modified-title',
4767
+ content: 'workflow.entity-modified-body',
4768
+ },
4769
+ nextSteps: [
4770
+ {
4771
+ conditions: [],
4772
+ nextStepId: 'modifyConfirmed',
4773
+ },
4774
+ ],
4775
+ },
4776
+ modifyConfirmed: {
4777
+ id: 'modifyConfirmed',
4778
+ action: 'AXPEntityModifyConfirmedAction',
4779
+ },
4780
+ },
4781
+ };
4782
+
4913
4783
  /**
4914
4784
  * Generated bundle index. Do not edit.
4915
4785
  */