@acorex/platform 20.4.2 → 20.5.0-next.0

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,265 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, computed, input, effect, Directive, EventEmitter, HostListener, Output, ViewContainerRef, ElementRef, Injector, runInInjectionContext, provideAppInitializer, signal, Pipe } from '@angular/core';
1
3
  import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
2
4
  import { get, isPlainObject, set, isArray, merge, isNil, isObjectLike, transform, isEmpty, isEqual, differenceWith, union, cloneDeep, isUndefined, endsWith, startsWith, includes, lte, gte, lt, gt, orderBy } from 'lodash-es';
3
- import * as i0 from '@angular/core';
4
- import { computed, InjectionToken, inject, Injectable, input, effect, Directive, EventEmitter, HostListener, Output, ViewContainerRef, ElementRef, provideAppInitializer, signal, Pipe, Injector, runInInjectionContext } from '@angular/core';
5
5
  import { Subject, interval } from 'rxjs';
6
6
  import { AXCalendarService } from '@acorex/core/date-time';
7
7
  import { startWith, map } from 'rxjs/operators';
8
8
 
9
+ const AXP_ACTIVITY_LOG_PROVIDER = new InjectionToken('AXP_ACTIVITY_LOGS_PROVIDER');
10
+ class AXPActivityLogService {
11
+ constructor() {
12
+ this.providers = inject(AXP_ACTIVITY_LOG_PROVIDER, { optional: true });
13
+ }
14
+ async getHistory(refId, refType, options) {
15
+ return (await Promise.all(this.providers?.map((p) => p.getHistory(refId, refType, options)) ?? [])).flat();
16
+ }
17
+ async getHistoryByIds(refId, refType, ids) {
18
+ return (await Promise.all(this.providers?.map((p) => p.getHistoryByIds(refId, refType, ids)) ?? [])).flat();
19
+ }
20
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
21
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, providedIn: 'root' }); }
22
+ }
23
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, decorators: [{
24
+ type: Injectable,
25
+ args: [{ providedIn: 'root' }]
26
+ }] });
27
+
28
+ class AXPActivityLogProvider {
29
+ }
30
+
31
+ //#region ---- Color Palette Provider ----
32
+ /**
33
+ * Abstract class for color palette providers
34
+ * Implement this to provide palettes from different sources (system, app, module, etc.)
35
+ */
36
+ class AXPColorPaletteProvider {
37
+ }
38
+ /**
39
+ * Injection token for color palette providers
40
+ * Use this to register multiple palette providers
41
+ */
42
+ const AXP_COLOR_PALETTE_PROVIDER = new InjectionToken('AXP_COLOR_PALETTE_PROVIDER');
43
+ //#endregion
44
+
45
+ //#region ---- Color Palette Service ----
46
+ /**
47
+ * Service for managing color palettes from multiple providers
48
+ * Aggregates palettes from all registered providers
49
+ */
50
+ class AXPColorPaletteService {
51
+ constructor() {
52
+ //#region ---- Dependencies ----
53
+ this.providers = inject(AXP_COLOR_PALETTE_PROVIDER, { optional: true }) ?? [];
54
+ //#endregion
55
+ //#region ---- State ----
56
+ this.cache = null;
57
+ }
58
+ //#endregion
59
+ //#region ---- Public API ----
60
+ /**
61
+ * Get all palettes from all providers
62
+ * @param options Filter options
63
+ * @returns Promise of palettes
64
+ */
65
+ async getPalettes(options) {
66
+ if (!this.cache) {
67
+ await this.loadPalettes();
68
+ }
69
+ let palettes = this.cache;
70
+ // Apply category filter
71
+ if (options?.category) {
72
+ palettes = palettes.filter((palette) => palette.category === options.category);
73
+ }
74
+ // Apply search filter
75
+ if (options?.search) {
76
+ const searchLower = options.search.toLowerCase();
77
+ palettes = palettes.filter((palette) => palette.name.toLowerCase().includes(searchLower) ||
78
+ palette.title.toLowerCase().includes(searchLower) ||
79
+ palette.description?.toLowerCase().includes(searchLower));
80
+ }
81
+ return palettes;
82
+ }
83
+ /**
84
+ * Get a palette by name
85
+ * @param name The unique name of the palette
86
+ * @returns Promise of palette or undefined if not found
87
+ */
88
+ async getPalette(name) {
89
+ if (!this.cache) {
90
+ await this.loadPalettes();
91
+ }
92
+ return this.cache.find((p) => p.name === name);
93
+ }
94
+ /**
95
+ * Get palettes by category
96
+ * @param category The category to filter by
97
+ * @returns Promise of palettes in the specified category
98
+ */
99
+ async getByCategory(category) {
100
+ return this.getPalettes({ category });
101
+ }
102
+ /**
103
+ * Check if a palette exists
104
+ * @param name The unique name of the palette
105
+ * @returns Promise of true if the palette exists
106
+ */
107
+ async has(name) {
108
+ const palette = await this.getPalette(name);
109
+ return palette !== undefined;
110
+ }
111
+ /**
112
+ * Reload palettes from all providers
113
+ */
114
+ async reload() {
115
+ this.cache = null;
116
+ await this.loadPalettes();
117
+ }
118
+ //#endregion
119
+ //#region ---- Private Methods ----
120
+ /**
121
+ * Load palettes from all providers
122
+ */
123
+ async loadPalettes() {
124
+ const allPalettes = [];
125
+ for (const provider of this.providers) {
126
+ try {
127
+ const palettes = await provider.provide();
128
+ allPalettes.push(...palettes);
129
+ }
130
+ catch (error) {
131
+ console.error(`Error loading palettes from provider ${provider.name}:`, error);
132
+ }
133
+ }
134
+ // Remove duplicates based on name
135
+ const uniquePalettes = allPalettes.filter((palette, index, self) => index === self.findIndex((p) => p.name === palette.name));
136
+ this.cache = uniquePalettes;
137
+ }
138
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPColorPaletteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
139
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPColorPaletteService, providedIn: 'root' }); }
140
+ }
141
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPColorPaletteService, decorators: [{
142
+ type: Injectable,
143
+ args: [{
144
+ providedIn: 'root',
145
+ }]
146
+ }] });
147
+
148
+ //#region ---- Color Palette Types ----
149
+ //#endregion
150
+
151
+ //#region ---- Default System Palettes Provider ----
152
+ /**
153
+ * Default system color palette provider
154
+ * Provides built-in color palettes
155
+ */
156
+ class AXPDefaultColorPalettesProvider extends AXPColorPaletteProvider {
157
+ constructor() {
158
+ super(...arguments);
159
+ this.name = 'system';
160
+ }
161
+ async provide() {
162
+ return [
163
+ {
164
+ name: 'material-design',
165
+ title: 'Material Design',
166
+ category: 'material',
167
+ description: 'Google Material Design color palette',
168
+ colors: [
169
+ '#F44336', // Red
170
+ '#E91E63', // Pink
171
+ '#9C27B0', // Purple
172
+ '#673AB7', // Deep Purple
173
+ '#3F51B5', // Indigo
174
+ '#2196F3', // Blue
175
+ '#03A9F4', // Light Blue
176
+ '#00BCD4', // Cyan
177
+ '#009688', // Teal
178
+ '#4CAF50', // Green
179
+ '#8BC34A', // Light Green
180
+ '#CDDC39', // Lime
181
+ '#FFEB3B', // Yellow
182
+ '#FFC107', // Amber
183
+ '#FF9800', // Orange
184
+ '#FF5722', // Deep Orange
185
+ ],
186
+ },
187
+ {
188
+ name: 'pastel',
189
+ title: 'Pastel Colors',
190
+ category: 'theme',
191
+ description: 'Soft pastel color palette',
192
+ colors: [
193
+ '#FFB3BA', // Light Pink
194
+ '#FFDFBA', // Light Peach
195
+ '#FFFFBA', // Light Yellow
196
+ '#BAFFC9', // Light Green
197
+ '#BAE1FF', // Light Blue
198
+ '#E0BBE4', // Light Purple
199
+ '#FFDFD3', // Light Coral
200
+ '#D4F1F4', // Light Cyan
201
+ ],
202
+ },
203
+ {
204
+ name: 'vibrant',
205
+ title: 'Vibrant Colors',
206
+ category: 'theme',
207
+ description: 'Bold and vibrant color palette',
208
+ colors: [
209
+ '#FF6B6B', // Vibrant Red
210
+ '#4ECDC4', // Vibrant Teal
211
+ '#45B7D1', // Vibrant Blue
212
+ '#FFA07A', // Vibrant Salmon
213
+ '#98D8C8', // Vibrant Mint
214
+ '#F7DC6F', // Vibrant Yellow
215
+ '#BB8FCE', // Vibrant Purple
216
+ '#85C1E2', // Vibrant Sky Blue
217
+ ],
218
+ },
219
+ {
220
+ name: 'earth-tones',
221
+ title: 'Earth Tones',
222
+ category: 'theme',
223
+ description: 'Natural earth tone color palette',
224
+ colors: [
225
+ '#8B4513', // Saddle Brown
226
+ '#A0522D', // Sienna
227
+ '#D2691E', // Chocolate
228
+ '#CD853F', // Peru
229
+ '#DEB887', // Burlywood
230
+ '#F5DEB3', // Wheat
231
+ '#556B2F', // Dark Olive Green
232
+ '#6B8E23', // Olive Drab
233
+ ],
234
+ },
235
+ {
236
+ name: 'monochrome',
237
+ title: 'Monochrome',
238
+ category: 'theme',
239
+ description: 'Grayscale color palette',
240
+ colors: [
241
+ '#000000', // Black
242
+ '#262626', // Very Dark Gray
243
+ '#404040', // Dark Gray
244
+ '#595959', // Medium Dark Gray
245
+ '#737373', // Medium Gray
246
+ '#8C8C8C', // Light Medium Gray
247
+ '#A6A6A6', // Light Gray
248
+ '#BFBFBF', // Very Light Gray
249
+ '#D9D9D9', // Lighter Gray
250
+ '#F2F2F2', // Almost White
251
+ '#FFFFFF', // White
252
+ ],
253
+ },
254
+ ];
255
+ }
256
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDefaultColorPalettesProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
257
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDefaultColorPalettesProvider }); }
258
+ }
259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDefaultColorPalettesProvider, decorators: [{
260
+ type: Injectable
261
+ }] });
262
+
9
263
  function extractNestedFieldsWildcard(obj, basePath, fields) {
10
264
  const result = {};
11
265
  if (fields.length === 1 && fields[0] === '*') {
@@ -712,6 +966,152 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
712
966
  }]
713
967
  }] });
714
968
 
969
+ const AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER = new InjectionToken('AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER');
970
+
971
+ //#region ---- Imports ----
972
+ //#endregion
973
+ class AXPDistributedEventListenerService {
974
+ constructor() {
975
+ //#region ---- Providers & Caches ----
976
+ this.listenerProviders = inject(AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, { optional: true }) || [];
977
+ this.injector = inject(Injector);
978
+ /** Cache for listeners by key. */
979
+ this.listenersByKey = new Map();
980
+ /** Flag to track if providers have been loaded */
981
+ this.providersLoaded = false;
982
+ }
983
+ //#endregion
984
+ //#region ---- Public API ----
985
+ /**
986
+ * Dispatches an event to all registered listeners for the given key.
987
+ * @param key The event key.
988
+ * @param data The event data to pass to listeners.
989
+ */
990
+ async dispatch(key, data) {
991
+ const providers = await this.resolveProviders();
992
+ const matched = providers.filter(p => p.key === key);
993
+ if (!matched.length) {
994
+ return;
995
+ }
996
+ for (const provider of matched) {
997
+ try {
998
+ await Promise.resolve(runInInjectionContext(this.injector, () => provider.execute(data)));
999
+ }
1000
+ catch (err) {
1001
+ console.error(`[AXPDistributedEventListenerService] Provider for key='${key}' failed`, err);
1002
+ }
1003
+ }
1004
+ }
1005
+ /**
1006
+ * Dispatch with async response (first matching provider, with retry/timeout)
1007
+ */
1008
+ async dispatchAsync(key, data, options = {
1009
+ timeout: 60_000,
1010
+ retries: 3,
1011
+ retryDelay: 1000,
1012
+ }) {
1013
+ const providers = await this.resolveProviders();
1014
+ const matched = providers.filter(p => p.key === key);
1015
+ if (!matched.length) {
1016
+ throw new Error(`No provider found for key='${key}'`);
1017
+ }
1018
+ const attempt = (n) => {
1019
+ return new Promise((resolve, reject) => {
1020
+ let finished = false;
1021
+ const timer = setTimeout(() => {
1022
+ if (!finished) {
1023
+ if (n < options.retries) {
1024
+ resolve(attempt(n + 1));
1025
+ }
1026
+ else {
1027
+ reject(new Error(`Timeout: no response for key='${key}' after ${options.retries} attempts.`));
1028
+ }
1029
+ }
1030
+ }, options.timeout);
1031
+ try {
1032
+ const provider = matched[0];
1033
+ const result = runInInjectionContext(this.injector, () => provider.execute(data));
1034
+ Promise.resolve(result)
1035
+ .then((r) => {
1036
+ finished = true;
1037
+ clearTimeout(timer);
1038
+ resolve(r);
1039
+ })
1040
+ .catch(err => {
1041
+ finished = true;
1042
+ clearTimeout(timer);
1043
+ reject(err);
1044
+ });
1045
+ }
1046
+ catch (err) {
1047
+ clearTimeout(timer);
1048
+ reject(err);
1049
+ }
1050
+ });
1051
+ };
1052
+ return attempt(0);
1053
+ }
1054
+ /**
1055
+ * Resolve all providers (handle both direct provider and Promise<provider>)
1056
+ */
1057
+ async resolveProviders() {
1058
+ return Promise.all(this.listenerProviders.map(p => p instanceof Promise ? p : Promise.resolve(p)));
1059
+ }
1060
+ /**
1061
+ * Returns all listeners for a specific event key.
1062
+ * @param key The event key.
1063
+ * @returns Array of listeners for the key.
1064
+ */
1065
+ async getListeners(key) {
1066
+ await this.ensureProvidersLoaded();
1067
+ return this.listenersByKey.get(key) || [];
1068
+ }
1069
+ /**
1070
+ * Returns all registered event keys.
1071
+ * @returns Array of all event keys that have listeners.
1072
+ */
1073
+ async getRegisteredKeys() {
1074
+ await this.ensureProvidersLoaded();
1075
+ return Array.from(this.listenersByKey.keys());
1076
+ }
1077
+ //#endregion
1078
+ //#region ---- Private Methods ----
1079
+ /**
1080
+ * Ensures that all providers have been loaded and cached.
1081
+ */
1082
+ async ensureProvidersLoaded() {
1083
+ if (this.providersLoaded) {
1084
+ return;
1085
+ }
1086
+ // Resolve all providers
1087
+ const resolvedProviders = await Promise.all(this.listenerProviders);
1088
+ // Group listeners by key
1089
+ for (const provider of resolvedProviders) {
1090
+ if (provider) {
1091
+ const existingListeners = this.listenersByKey.get(provider.key) || [];
1092
+ existingListeners.push(provider);
1093
+ this.listenersByKey.set(provider.key, existingListeners);
1094
+ }
1095
+ }
1096
+ this.providersLoaded = true;
1097
+ }
1098
+ //#endregion
1099
+ //#region ---- Cache Management ----
1100
+ /** Clears the listeners cache and forces reload on next access. */
1101
+ clearListenersCache() {
1102
+ this.listenersByKey.clear();
1103
+ this.providersLoaded = false;
1104
+ }
1105
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1106
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, providedIn: 'root' }); }
1107
+ }
1108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, decorators: [{
1109
+ type: Injectable,
1110
+ args: [{
1111
+ providedIn: 'root',
1112
+ }]
1113
+ }] });
1114
+
715
1115
  class AXPBroadcastEventService {
716
1116
  constructor() {
717
1117
  this.eventSubjects = new Map();
@@ -991,6 +1391,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
991
1391
  args: [{ providedIn: 'root' }]
992
1392
  }] });
993
1393
 
1394
+ class AXPHookService {
1395
+ constructor() {
1396
+ this.listenerProviders = inject(AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, { optional: true }) || [];
1397
+ this.injector = inject(Injector);
1398
+ }
1399
+ /**
1400
+ * Resolve all providers (handle both direct providers and Promise<provider>)
1401
+ */
1402
+ async resolveProviders() {
1403
+ return Promise.all(this.listenerProviders.map(p => p instanceof Promise ? p : Promise.resolve(p)));
1404
+ }
1405
+ /**
1406
+ * Fire sync hooks (fire-and-forget).
1407
+ * All providers with the given key will be executed.
1408
+ * Execution is not awaited.
1409
+ */
1410
+ fire(key, data) {
1411
+ this.resolveProviders().then(providers => {
1412
+ providers
1413
+ .filter(p => p.key === key)
1414
+ .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0))
1415
+ .forEach(p => {
1416
+ try {
1417
+ runInInjectionContext(this.injector, () => p.execute(data));
1418
+ }
1419
+ catch (err) {
1420
+ console.error(`[AXPHookService] Hook '${key}' failed`, err);
1421
+ }
1422
+ });
1423
+ });
1424
+ }
1425
+ /**
1426
+ * Run async hooks sequentially (waterfall).
1427
+ * The output of each hook is passed as input to the next hook.
1428
+ * Returns the final merged data after all hooks are executed.
1429
+ */
1430
+ async runAsync(key, initialData) {
1431
+ const providers = (await this.resolveProviders())
1432
+ .filter(p => p.key === key)
1433
+ .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
1434
+ let data = initialData;
1435
+ for (const p of providers) {
1436
+ data = await Promise.resolve(runInInjectionContext(this.injector, () => p.execute(data)));
1437
+ }
1438
+ return data;
1439
+ }
1440
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1441
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, providedIn: 'root' }); }
1442
+ }
1443
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, decorators: [{
1444
+ type: Injectable,
1445
+ args: [{ providedIn: 'root' }]
1446
+ }] });
1447
+
994
1448
  class AXPAppStartUpService {
995
1449
  constructor() {
996
1450
  this.tasks = [];
@@ -998,35 +1452,197 @@ class AXPAppStartUpService {
998
1452
  registerTask(task) {
999
1453
  this.tasks.push(task);
1000
1454
  }
1001
- async runAllTasks() {
1002
- for (const task of this.tasks.sort((a, b) => a.priority - b.priority)) {
1003
- console.log(`Running "${task.statusText}" with priority "${task.priority}"`);
1004
- this.updateStatus(task.statusText);
1005
- await task.run();
1455
+ async runAllTasks() {
1456
+ for (const task of this.tasks.sort((a, b) => a.priority - b.priority)) {
1457
+ console.log(`Running "${task.statusText}" with priority "${task.priority}"`);
1458
+ this.updateStatus(task.statusText);
1459
+ await task.run();
1460
+ }
1461
+ }
1462
+ updateStatus(status) {
1463
+ const loadingText = document.querySelector('#loadingText');
1464
+ if (loadingText) {
1465
+ loadingText.innerHTML = status;
1466
+ }
1467
+ }
1468
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1469
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, providedIn: 'root' }); }
1470
+ }
1471
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, decorators: [{
1472
+ type: Injectable,
1473
+ args: [{
1474
+ providedIn: 'root',
1475
+ }]
1476
+ }] });
1477
+ function initAppFactory(appInitService) {
1478
+ return () => appInitService.runAllTasks();
1479
+ }
1480
+ const AXPAppStartUpProvider = provideAppInitializer(() => {
1481
+ const initializerFn = initAppFactory(inject(AXPAppStartUpService));
1482
+ return initializerFn();
1483
+ });
1484
+
1485
+ //#region ---- Tag Types ----
1486
+ //#endregion
1487
+
1488
+ //#region ---- Tag Provider ----
1489
+ /**
1490
+ * Abstract class for tag providers
1491
+ * Implement this to provide tags from different sources (system, tenant, user, etc.)
1492
+ */
1493
+ class AXPTagProvider {
1494
+ /**
1495
+ * Create a new tag (optional - not all providers support creation)
1496
+ * @param tag Tag to create
1497
+ * @returns Created tag with id
1498
+ */
1499
+ async create(tag) {
1500
+ throw new Error(`Provider ${this.name} does not support tag creation`);
1501
+ }
1502
+ /**
1503
+ * Update an existing tag (optional)
1504
+ * @param tag Tag to update
1505
+ * @returns Updated tag
1506
+ */
1507
+ async update(tag) {
1508
+ throw new Error(`Provider ${this.name} does not support tag updates`);
1509
+ }
1510
+ /**
1511
+ * Delete a tag (optional)
1512
+ * @param id Tag id to delete
1513
+ */
1514
+ async delete(id) {
1515
+ throw new Error(`Provider ${this.name} does not support tag deletion`);
1516
+ }
1517
+ }
1518
+ /**
1519
+ * Injection token for tag providers
1520
+ * Use this to register multiple tag providers
1521
+ */
1522
+ const AXP_TAG_PROVIDER = new InjectionToken('AXP_TAG_PROVIDER');
1523
+ //#endregion
1524
+
1525
+ //#region ---- Tag Service ----
1526
+ /**
1527
+ * Service for managing tags from multiple providers
1528
+ * Aggregates tags from all registered providers
1529
+ */
1530
+ class AXPTagService {
1531
+ constructor() {
1532
+ //#region ---- Dependencies ----
1533
+ this.providers = inject(AXP_TAG_PROVIDER, { optional: true }) ?? [];
1534
+ //#endregion
1535
+ //#region ---- State ----
1536
+ this.cache = null;
1537
+ }
1538
+ //#endregion
1539
+ //#region ---- Public API ----
1540
+ /**
1541
+ * Get all tags from all providers
1542
+ * @param options Filter options
1543
+ * @returns Promise of tags
1544
+ */
1545
+ async getTags(options) {
1546
+ if (!this.cache) {
1547
+ await this.loadTags();
1548
+ }
1549
+ let tags = this.cache;
1550
+ // Apply scope filter
1551
+ if (options?.scope && options.scope.length > 0) {
1552
+ tags = tags.filter((tag) => tag.scope && options.scope.includes(tag.scope));
1553
+ }
1554
+ // Apply search filter
1555
+ if (options?.search) {
1556
+ const searchLower = options.search.toLowerCase();
1557
+ tags = tags.filter((tag) => tag.title.toLowerCase().includes(searchLower) ||
1558
+ tag.description?.toLowerCase().includes(searchLower));
1559
+ }
1560
+ return tags;
1561
+ }
1562
+ /**
1563
+ * Create a new tag using the appropriate provider
1564
+ * @param tag Tag to create
1565
+ * @param providerName Provider to use (defaults to first writable provider)
1566
+ * @returns Created tag
1567
+ */
1568
+ async createTag(tag, providerName) {
1569
+ const provider = providerName
1570
+ ? this.providers.find((p) => p.name === providerName)
1571
+ : this.providers.find((p) => p.create);
1572
+ if (!provider || !provider.create) {
1573
+ throw new Error('No writable tag provider available');
1574
+ }
1575
+ const createdTag = await provider.create(tag);
1576
+ // Invalidate cache
1577
+ this.cache = null;
1578
+ return createdTag;
1579
+ }
1580
+ /**
1581
+ * Update an existing tag
1582
+ * @param tag Tag to update
1583
+ * @returns Updated tag
1584
+ */
1585
+ async updateTag(tag) {
1586
+ const provider = this.providers.find((p) => p.name === tag.scope && p.update);
1587
+ if (!provider || !provider.update) {
1588
+ throw new Error(`No provider found for updating tag with scope: ${tag.scope}`);
1589
+ }
1590
+ const updatedTag = await provider.update(tag);
1591
+ // Invalidate cache
1592
+ this.cache = null;
1593
+ return updatedTag;
1594
+ }
1595
+ /**
1596
+ * Delete a tag
1597
+ * @param tagId Tag id to delete
1598
+ * @param scope Tag scope
1599
+ */
1600
+ async deleteTag(tagId, scope) {
1601
+ const provider = this.providers.find((p) => p.name === scope && p.delete);
1602
+ if (!provider || !provider.delete) {
1603
+ throw new Error(`No provider found for deleting tag with scope: ${scope}`);
1006
1604
  }
1605
+ await provider.delete(tagId);
1606
+ // Invalidate cache
1607
+ this.cache = null;
1007
1608
  }
1008
- updateStatus(status) {
1009
- const loadingText = document.querySelector('#loadingText');
1010
- if (loadingText) {
1011
- loadingText.innerHTML = status;
1609
+ /**
1610
+ * Reload tags from all providers
1611
+ */
1612
+ async reload() {
1613
+ this.cache = null;
1614
+ await this.loadTags();
1615
+ }
1616
+ //#endregion
1617
+ //#region ---- Private Methods ----
1618
+ /**
1619
+ * Load tags from all providers
1620
+ */
1621
+ async loadTags() {
1622
+ debugger;
1623
+ const allTags = [];
1624
+ for (const provider of this.providers) {
1625
+ try {
1626
+ const tags = await provider.provide();
1627
+ allTags.push(...tags);
1628
+ }
1629
+ catch (error) {
1630
+ console.error(`Error loading tags from provider ${provider.name}:`, error);
1631
+ }
1012
1632
  }
1633
+ // Remove duplicates based on title (case-insensitive)
1634
+ const uniqueTags = allTags.filter((tag, index, self) => index === self.findIndex((t) => t.title.toLowerCase() === tag.title.toLowerCase()));
1635
+ this.cache = uniqueTags;
1013
1636
  }
1014
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1015
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, providedIn: 'root' }); }
1637
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPTagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1638
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPTagService, providedIn: 'root' }); }
1016
1639
  }
1017
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPAppStartUpService, decorators: [{
1640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPTagService, decorators: [{
1018
1641
  type: Injectable,
1019
1642
  args: [{
1020
1643
  providedIn: 'root',
1021
1644
  }]
1022
1645
  }] });
1023
- function initAppFactory(appInitService) {
1024
- return () => appInitService.runAllTasks();
1025
- }
1026
- const AXPAppStartUpProvider = provideAppInitializer(() => {
1027
- const initializerFn = initAppFactory(inject(AXPAppStartUpService));
1028
- return initializerFn();
1029
- });
1030
1646
 
1031
1647
  /**
1032
1648
  * Additional suggested generic actions for future consideration:
@@ -2382,231 +2998,9 @@ function extractTextFromHtml(value) {
2382
2998
  return div.textContent || div.innerText || '';
2383
2999
  }
2384
3000
 
2385
- const AXP_ACTIVITY_LOG_PROVIDER = new InjectionToken('AXP_ACTIVITY_LOGS_PROVIDER');
2386
- class AXPActivityLogService {
2387
- constructor() {
2388
- this.providers = inject(AXP_ACTIVITY_LOG_PROVIDER, { optional: true });
2389
- }
2390
- async getHistory(refId, refType, options) {
2391
- return (await Promise.all(this.providers?.map((p) => p.getHistory(refId, refType, options)) ?? [])).flat();
2392
- }
2393
- async getHistoryByIds(refId, refType, ids) {
2394
- return (await Promise.all(this.providers?.map((p) => p.getHistoryByIds(refId, refType, ids)) ?? [])).flat();
2395
- }
2396
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2397
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, providedIn: 'root' }); }
2398
- }
2399
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPActivityLogService, decorators: [{
2400
- type: Injectable,
2401
- args: [{ providedIn: 'root' }]
2402
- }] });
2403
-
2404
- class AXPActivityLogProvider {
2405
- }
2406
-
2407
- const AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER = new InjectionToken('AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER');
2408
-
2409
- //#region ---- Imports ----
2410
- //#endregion
2411
- class AXPDistributedEventListenerService {
2412
- constructor() {
2413
- //#region ---- Providers & Caches ----
2414
- this.listenerProviders = inject(AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, { optional: true }) || [];
2415
- this.injector = inject(Injector);
2416
- /** Cache for listeners by key. */
2417
- this.listenersByKey = new Map();
2418
- /** Flag to track if providers have been loaded */
2419
- this.providersLoaded = false;
2420
- }
2421
- //#endregion
2422
- //#region ---- Public API ----
2423
- /**
2424
- * Dispatches an event to all registered listeners for the given key.
2425
- * @param key The event key.
2426
- * @param data The event data to pass to listeners.
2427
- */
2428
- async dispatch(key, data) {
2429
- const providers = await this.resolveProviders();
2430
- const matched = providers.filter(p => p.key === key);
2431
- if (!matched.length) {
2432
- return;
2433
- }
2434
- for (const provider of matched) {
2435
- try {
2436
- await Promise.resolve(runInInjectionContext(this.injector, () => provider.execute(data)));
2437
- }
2438
- catch (err) {
2439
- console.error(`[AXPDistributedEventListenerService] Provider for key='${key}' failed`, err);
2440
- }
2441
- }
2442
- }
2443
- /**
2444
- * Dispatch with async response (first matching provider, with retry/timeout)
2445
- */
2446
- async dispatchAsync(key, data, options = {
2447
- timeout: 60_000,
2448
- retries: 3,
2449
- retryDelay: 1000,
2450
- }) {
2451
- const providers = await this.resolveProviders();
2452
- const matched = providers.filter(p => p.key === key);
2453
- if (!matched.length) {
2454
- throw new Error(`No provider found for key='${key}'`);
2455
- }
2456
- const attempt = (n) => {
2457
- return new Promise((resolve, reject) => {
2458
- let finished = false;
2459
- const timer = setTimeout(() => {
2460
- if (!finished) {
2461
- if (n < options.retries) {
2462
- resolve(attempt(n + 1));
2463
- }
2464
- else {
2465
- reject(new Error(`Timeout: no response for key='${key}' after ${options.retries} attempts.`));
2466
- }
2467
- }
2468
- }, options.timeout);
2469
- try {
2470
- const provider = matched[0];
2471
- const result = runInInjectionContext(this.injector, () => provider.execute(data));
2472
- Promise.resolve(result)
2473
- .then((r) => {
2474
- finished = true;
2475
- clearTimeout(timer);
2476
- resolve(r);
2477
- })
2478
- .catch(err => {
2479
- finished = true;
2480
- clearTimeout(timer);
2481
- reject(err);
2482
- });
2483
- }
2484
- catch (err) {
2485
- clearTimeout(timer);
2486
- reject(err);
2487
- }
2488
- });
2489
- };
2490
- return attempt(0);
2491
- }
2492
- /**
2493
- * Resolve all providers (handle both direct provider and Promise<provider>)
2494
- */
2495
- async resolveProviders() {
2496
- return Promise.all(this.listenerProviders.map(p => p instanceof Promise ? p : Promise.resolve(p)));
2497
- }
2498
- /**
2499
- * Returns all listeners for a specific event key.
2500
- * @param key The event key.
2501
- * @returns Array of listeners for the key.
2502
- */
2503
- async getListeners(key) {
2504
- await this.ensureProvidersLoaded();
2505
- return this.listenersByKey.get(key) || [];
2506
- }
2507
- /**
2508
- * Returns all registered event keys.
2509
- * @returns Array of all event keys that have listeners.
2510
- */
2511
- async getRegisteredKeys() {
2512
- await this.ensureProvidersLoaded();
2513
- return Array.from(this.listenersByKey.keys());
2514
- }
2515
- //#endregion
2516
- //#region ---- Private Methods ----
2517
- /**
2518
- * Ensures that all providers have been loaded and cached.
2519
- */
2520
- async ensureProvidersLoaded() {
2521
- if (this.providersLoaded) {
2522
- return;
2523
- }
2524
- // Resolve all providers
2525
- const resolvedProviders = await Promise.all(this.listenerProviders);
2526
- // Group listeners by key
2527
- for (const provider of resolvedProviders) {
2528
- if (provider) {
2529
- const existingListeners = this.listenersByKey.get(provider.key) || [];
2530
- existingListeners.push(provider);
2531
- this.listenersByKey.set(provider.key, existingListeners);
2532
- }
2533
- }
2534
- this.providersLoaded = true;
2535
- }
2536
- //#endregion
2537
- //#region ---- Cache Management ----
2538
- /** Clears the listeners cache and forces reload on next access. */
2539
- clearListenersCache() {
2540
- this.listenersByKey.clear();
2541
- this.providersLoaded = false;
2542
- }
2543
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2544
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, providedIn: 'root' }); }
2545
- }
2546
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDistributedEventListenerService, decorators: [{
2547
- type: Injectable,
2548
- args: [{
2549
- providedIn: 'root',
2550
- }]
2551
- }] });
2552
-
2553
- class AXPHookService {
2554
- constructor() {
2555
- this.listenerProviders = inject(AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, { optional: true }) || [];
2556
- this.injector = inject(Injector);
2557
- }
2558
- /**
2559
- * Resolve all providers (handle both direct providers and Promise<provider>)
2560
- */
2561
- async resolveProviders() {
2562
- return Promise.all(this.listenerProviders.map(p => p instanceof Promise ? p : Promise.resolve(p)));
2563
- }
2564
- /**
2565
- * Fire sync hooks (fire-and-forget).
2566
- * All providers with the given key will be executed.
2567
- * Execution is not awaited.
2568
- */
2569
- fire(key, data) {
2570
- this.resolveProviders().then(providers => {
2571
- providers
2572
- .filter(p => p.key === key)
2573
- .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0))
2574
- .forEach(p => {
2575
- try {
2576
- runInInjectionContext(this.injector, () => p.execute(data));
2577
- }
2578
- catch (err) {
2579
- console.error(`[AXPHookService] Hook '${key}' failed`, err);
2580
- }
2581
- });
2582
- });
2583
- }
2584
- /**
2585
- * Run async hooks sequentially (waterfall).
2586
- * The output of each hook is passed as input to the next hook.
2587
- * Returns the final merged data after all hooks are executed.
2588
- */
2589
- async runAsync(key, initialData) {
2590
- const providers = (await this.resolveProviders())
2591
- .filter(p => p.key === key)
2592
- .sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0));
2593
- let data = initialData;
2594
- for (const p of providers) {
2595
- data = await Promise.resolve(runInInjectionContext(this.injector, () => p.execute(data)));
2596
- }
2597
- return data;
2598
- }
2599
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2600
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, providedIn: 'root' }); }
2601
- }
2602
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPHookService, decorators: [{
2603
- type: Injectable,
2604
- args: [{ providedIn: 'root' }]
2605
- }] });
2606
-
2607
3001
  /**
2608
3002
  * Generated bundle index. Do not edit.
2609
3003
  */
2610
3004
 
2611
- export { AXHighlightService, AXPActivityLogProvider, AXPActivityLogService, AXPAppStartUpProvider, AXPAppStartUpService, AXPBroadcastEventService, AXPComponentLogoConfig, AXPContentCheckerDirective, AXPContextChangeEvent, AXPContextStore, AXPCountdownPipe, AXPDataGenerator, AXPDataSourceDefinitionProviderService, AXPDblClickDirective, AXPDistributedEventListenerService, AXPElementDataDirective, AXPExportTemplateToken, AXPExpressionEvaluatorScopeProviderContext, AXPExpressionEvaluatorScopeProviderService, AXPExpressionEvaluatorService, AXPGridLayoutDirective, AXPHookService, AXPImageUrlLogoConfig, AXPPlatformScope, AXPSystemActionType, AXPSystemActions, AXP_ACTIVITY_LOG_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, applyFilterArray, applyPagination, applyQueryArray, applySortArray, applySystemActionDefault, cleanDeep, extractNestedFieldsWildcard, extractTextFromHtml, extractValue, getActionButton, getChangedPaths, getDetailedChanges, getEnumValues, getNestedKeys, getSmart, getSystemActions, objectKeyValueTransforms, resolveActionLook, resolvePlatformScopeKey, resolvePlatformScopeName, setSmart };
3005
+ export { AXHighlightService, AXPActivityLogProvider, AXPActivityLogService, AXPAppStartUpProvider, AXPAppStartUpService, AXPBroadcastEventService, AXPColorPaletteProvider, AXPColorPaletteService, AXPComponentLogoConfig, AXPContentCheckerDirective, AXPContextChangeEvent, AXPContextStore, AXPCountdownPipe, AXPDataGenerator, AXPDataSourceDefinitionProviderService, AXPDblClickDirective, AXPDefaultColorPalettesProvider, AXPDistributedEventListenerService, AXPElementDataDirective, AXPExportTemplateToken, AXPExpressionEvaluatorScopeProviderContext, AXPExpressionEvaluatorScopeProviderService, AXPExpressionEvaluatorService, AXPGridLayoutDirective, AXPHookService, AXPImageUrlLogoConfig, AXPPlatformScope, AXPSystemActionType, AXPSystemActions, AXPTagProvider, AXPTagService, AXP_ACTIVITY_LOG_PROVIDER, AXP_COLOR_PALETTE_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_TAG_PROVIDER, applyFilterArray, applyPagination, applyQueryArray, applySortArray, applySystemActionDefault, cleanDeep, extractNestedFieldsWildcard, extractTextFromHtml, extractValue, getActionButton, getChangedPaths, getDetailedChanges, getEnumValues, getNestedKeys, getSmart, getSystemActions, objectKeyValueTransforms, resolveActionLook, resolvePlatformScopeKey, resolvePlatformScopeName, setSmart };
2612
3006
  //# sourceMappingURL=acorex-platform-core.mjs.map