@acorex/platform 20.0.0-next.0 → 20.0.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.
Files changed (26) hide show
  1. package/common/index.d.ts +1 -0
  2. package/fesm2022/acorex-platform-common.mjs +3 -1
  3. package/fesm2022/acorex-platform-common.mjs.map +1 -1
  4. package/fesm2022/acorex-platform-layout-components.mjs +717 -459
  5. package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
  6. package/fesm2022/acorex-platform-layout-entity.mjs +24 -31
  7. package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
  8. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-BFIGLwd9.mjs +115 -0
  9. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-BFIGLwd9.mjs.map +1 -0
  10. package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-PKLs3XdV.mjs → acorex-platform-themes-default-entity-master-list-view.component-BuyMyK_I.mjs} +29 -7
  11. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-BuyMyK_I.mjs.map +1 -0
  12. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-CHHmHz2a.mjs +108 -0
  13. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-CHHmHz2a.mjs.map +1 -0
  14. package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-IcmkHgp5.mjs → acorex-platform-themes-default-entity-master-single-view.component-CnjDBPeT.mjs} +6 -3
  15. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-CnjDBPeT.mjs.map +1 -0
  16. package/fesm2022/acorex-platform-themes-default.mjs +14 -11
  17. package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
  18. package/layout/components/index.d.ts +296 -250
  19. package/layout/entity/index.d.ts +2 -3
  20. package/package.json +1 -1
  21. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-DKihQPlU.mjs +0 -112
  22. package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-DKihQPlU.mjs.map +0 -1
  23. package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-PKLs3XdV.mjs.map +0 -1
  24. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DwDxUQfZ.mjs +0 -105
  25. package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-DwDxUQfZ.mjs.map +0 -1
  26. package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-IcmkHgp5.mjs.map +0 -1
@@ -1,277 +1,198 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, signal, input, computed, ViewEncapsulation, Component, effect, Directive, ChangeDetectionStrategy, viewChild, contentChild, ElementRef, Injector, ViewContainerRef, runInInjectionContext, Optional, Inject, NgModule } from '@angular/core';
3
- import { BehaviorSubject, timer, Subject, takeUntil } from 'rxjs';
4
- import { tap } from 'rxjs/operators';
5
- import { AXBadgeModule, AXBadgeComponent } from '@acorex/components/badge';
6
- import * as i1 from '@acorex/components/avatar';
7
- import { AXAvatarModule } from '@acorex/components/avatar';
8
- import * as i2 from '@acorex/components/decorators';
9
- import { AXDecoratorModule } from '@acorex/components/decorators';
10
- import * as i3 from '@acorex/components/image';
11
- import { AXImageModule } from '@acorex/components/image';
12
- import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
13
- import { AXPExpressionEvaluatorService, AXPContextStore, getSystemActions } from '@acorex/platform/core';
14
- import { sortBy } from 'lodash-es';
1
+ import * as i3$2 from '@acorex/components/button';
15
2
  import { AXButtonModule } from '@acorex/components/button';
16
3
  import { AXCommonModule } from '@acorex/cdk/common';
17
- import * as i3$1 from '@acorex/core/translation';
4
+ import * as i4 from '@acorex/components/decorators';
5
+ import { AXDecoratorModule } from '@acorex/components/decorators';
6
+ import * as i3 from '@acorex/core/translation';
18
7
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
19
- import * as i4 from '@acorex/components/skeleton';
8
+ import * as i4$1 from '@acorex/components/skeleton';
20
9
  import { AXSkeletonModule } from '@acorex/components/skeleton';
21
10
  import * as i5 from '@acorex/core/format';
22
11
  import { AXFormatModule } from '@acorex/core/format';
12
+ import { getSystemActions, AXPExpressionEvaluatorService, AXPContextStore } from '@acorex/platform/core';
23
13
  import { AXPWorkflowService } from '@acorex/platform/workflow';
24
- import * as i1$1 from '@angular/common';
14
+ import * as i1 from '@angular/common';
25
15
  import { CommonModule } from '@angular/common';
16
+ import * as i0 from '@angular/core';
17
+ import { inject, input, signal, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, computed, Injectable, Directive, viewChild, contentChild, ElementRef, Injector, ViewContainerRef, runInInjectionContext, Optional, Inject, NgModule, output, linkedSignal, untracked, ViewChildren } from '@angular/core';
26
18
  import { AXAccordionCdkModule } from '@acorex/cdk/accordion';
27
19
  import { AXTagModule } from '@acorex/components/tag';
20
+ import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
21
+ import * as i10 from '@acorex/components/badge';
22
+ import { AXBadgeComponent, AXBadgeModule } from '@acorex/components/badge';
28
23
  import { AXFormModule } from '@acorex/components/form';
29
24
  import { AXTextBoxModule } from '@acorex/components/text-box';
30
- import * as i3$2 from '@acorex/components/check-box';
25
+ import * as i3$1 from '@acorex/components/check-box';
31
26
  import { AXCheckBoxModule } from '@acorex/components/check-box';
32
- import * as i2$1 from '@acorex/components/label';
27
+ import * as i2 from '@acorex/components/label';
33
28
  import { AXLabelModule } from '@acorex/components/label';
34
29
  import * as i5$1 from '@acorex/platform/layout/builder';
35
30
  import { AXPLayoutBuilderModule } from '@acorex/platform/layout/builder';
31
+ import { sortBy } from 'lodash-es';
32
+ import * as i9 from '@acorex/cdk/list-navigation';
33
+ import { AXListNavigationModule } from '@acorex/cdk/list-navigation';
34
+ import * as i6 from '@acorex/components/popover';
35
+ import { AXPopoverModule } from '@acorex/components/popover';
36
+ import { AXSelectionListModule } from '@acorex/components/selection-list';
37
+ import * as i7 from '@acorex/components/tag-box';
38
+ import { AXTagBoxModule } from '@acorex/components/tag-box';
39
+ import { AXCalendarService } from '@acorex/core/date-time';
40
+ import { AXPFilterOperatorMiddlewareService, ALL_DEFAULT_OPERATORS } from '@acorex/platform/common';
41
+ import * as i2$1 from '@angular/forms';
42
+ import { FormsModule } from '@angular/forms';
43
+ import { BehaviorSubject, timer, Subject, takeUntil } from 'rxjs';
44
+ import { tap } from 'rxjs/operators';
45
+ import * as i1$1 from '@acorex/components/avatar';
46
+ import { AXAvatarModule } from '@acorex/components/avatar';
47
+ import * as i3$3 from '@acorex/components/image';
48
+ import { AXImageModule } from '@acorex/components/image';
36
49
 
37
- const AXP_USER_AVATAR_PROVIDER = new InjectionToken('AXP_USER_AVATAR_PROVIDER', {
38
- providedIn: 'root',
39
- factory: () => {
40
- return new AXPUserAvatarProviderDefault();
41
- }
42
- });
43
- class AXPUserAvatarProviderDefault {
44
- provide(userId) {
45
- return Promise.resolve({
46
- id: userId,
47
- username: 'johndoe',
48
- firstName: 'John',
49
- lastName: 'Doe',
50
- status: 'online',
51
- avatarUrl: 'https://via.placeholder.com/150',
52
- });
53
- }
54
- }
55
-
56
- class AXPUserAvatarService {
50
+ //#region ---- Component Definition ----
51
+ class AXPActivityLogComponent {
52
+ //#endregion
53
+ //#region ---- Constructor & Lifecycle ----
57
54
  constructor() {
58
- this.provider = inject(AXP_USER_AVATAR_PROVIDER);
59
- // Cache configuration
60
- this.cacheExpiryTime = 5 * 60 * 1000; // 5 minutes in milliseconds
61
- this.refreshInterval = 3 * 60 * 1000; // 3 minutes in milliseconds
62
- // Cache storage
63
- this.cache = new Map();
55
+ //#endregion
56
+ //#region ---- Services & Dependencies ----
57
+ this.translateService = inject(AXTranslationService);
58
+ this.workflowService = inject(AXPWorkflowService);
59
+ //#endregion
60
+ //#region ---- Input Properties ----
61
+ /**
62
+ * Array of activity logs to display
63
+ */
64
+ this.activities = input([]);
65
+ /**
66
+ * Whether the component is in loading state
67
+ */
68
+ this.loading = input(false);
69
+ //#endregion
70
+ //#region ---- Component Properties ----
71
+ this.i18nScope = 'activity-log';
72
+ this.Object = Object;
73
+ /**
74
+ * Set of expanded activity IDs
75
+ */
76
+ this.expandedItems = signal(new Set());
77
+ /**
78
+ * Flag to track if component has been initialized
79
+ */
80
+ this.isInitialized = signal(false);
81
+ /**
82
+ * Set of items that have been manually toggled (for animation control)
83
+ */
84
+ this.manuallyToggledItems = signal(new Set());
85
+ // Auto-expand top 5 items when activities change
86
+ effect(() => {
87
+ const activities = this.activities();
88
+ const currentExpanded = this.expandedItems();
89
+ const initialized = this.isInitialized();
90
+ // Only auto-expand if not initialized and activities exist
91
+ if (!initialized && activities.length > 0 && currentExpanded.size === 0) {
92
+ const top5Ids = activities.slice(0, 5).map((activity) => activity.id);
93
+ this.expandedItems.set(new Set(top5Ids));
94
+ this.isInitialized.set(true);
95
+ }
96
+ });
64
97
  }
98
+ //#endregion
99
+ //#region ---- Utility Methods ----
65
100
  /**
66
- * Gets user information with caching and auto-refresh
67
- * @param userId The username to fetch information for
68
- * @returns Observable that emits user avatar data
101
+ * Gets the appropriate CSS class for the change type
69
102
  */
70
- getUserInfo$(userId) {
71
- // Check if we have a cached entry
72
- if (!this.cache.has(userId) || this.isExpired(userId)) {
73
- // Create a new cache entry with default values
74
- const defaultData = {
75
- id: userId,
76
- status: 'offline',
77
- username: '',
78
- firstName: '',
79
- lastName: ''
80
- };
81
- const subject = new BehaviorSubject(defaultData);
82
- this.cache.set(userId, {
83
- data: defaultData,
84
- timestamp: Date.now(),
85
- subject
86
- });
87
- // Fetch fresh data immediately
88
- this.fetchAndUpdateCache(userId);
89
- // Set up auto refresh
90
- timer(this.refreshInterval, this.refreshInterval)
91
- .pipe(tap(() => this.fetchAndUpdateCache(userId)))
92
- .subscribe();
93
- }
94
- return this.cache.get(userId).subject.asObservable();
103
+ getChangeClasses(changeType) {
104
+ const action = getSystemActions(changeType);
105
+ return {
106
+ surface: action?.color ? `ax-${action.color}-surface` : 'ax-muted-surface',
107
+ text: action?.color ? `ax-text-${action.color}` : 'ax-text-muted',
108
+ icon: action?.icon ? `${action.icon}` : 'fa-light fa-pen'
109
+ };
95
110
  }
96
111
  /**
97
- * Gets user information (Promise-based for backward compatibility)
98
- * @param userId The username to fetch information for
99
- * @returns Promise that resolves to user avatar data
100
- */
101
- async getUserInfo(userId) {
102
- // Check if we have an unexpired cached entry
103
- if (this.cache.has(userId) && !this.isExpired(userId)) {
104
- return this.cache.get(userId).data;
105
- }
106
- // Fetch fresh data and cache it
107
- return this.fetchAndUpdateCache(userId);
112
+ * Checks if an activity item is expanded
113
+ */
114
+ isExpanded(activityId) {
115
+ return this.expandedItems().has(activityId);
108
116
  }
109
117
  /**
110
- * Clears the entire cache or a specific user's cache
111
- * @param userId Optional username to clear specific cache
112
- */
113
- clearCache(userId) {
114
- if (userId) {
115
- this.cache.delete(userId);
118
+ * Toggles the expanded state of an activity item
119
+ */
120
+ toggleExpanded(activityId) {
121
+ const currentExpanded = new Set(this.expandedItems());
122
+ const currentManuallyToggled = new Set(this.manuallyToggledItems());
123
+ // Mark this item as manually toggled for animation purposes
124
+ currentManuallyToggled.add(activityId);
125
+ this.manuallyToggledItems.set(currentManuallyToggled);
126
+ if (currentExpanded.has(activityId)) {
127
+ currentExpanded.delete(activityId);
116
128
  }
117
129
  else {
118
- this.cache.clear();
130
+ currentExpanded.add(activityId);
119
131
  }
132
+ this.expandedItems.set(currentExpanded);
120
133
  }
121
134
  /**
122
- * Force refresh data for a specific username
123
- * @param userId The username to refresh
124
- * @returns Promise that resolves to the refreshed data
135
+ * Checks if an item should have expand/collapse animation
125
136
  */
126
- async refreshUserInfo(userId) {
127
- return this.fetchAndUpdateCache(userId);
137
+ shouldAnimate(activityId) {
138
+ return this.manuallyToggledItems().has(activityId);
128
139
  }
129
140
  /**
130
- * Checks if a cache entry is expired
141
+ * Checks if an activity has expandable content (changes)
131
142
  */
132
- isExpired(userId) {
133
- const entry = this.cache.get(userId);
134
- if (!entry)
135
- return true;
136
- return (Date.now() - entry.timestamp) > this.cacheExpiryTime;
143
+ hasExpandableContent(activity) {
144
+ return activity.changes && activity.changes.length > 0;
137
145
  }
146
+ //#endregion
147
+ //#region ---- Compare Methods ----
138
148
  /**
139
- * Fetches data from provider and updates the cache
149
+ * Handles the compare action for an activity
140
150
  */
141
- async fetchAndUpdateCache(userId) {
142
- try {
143
- const data = await this.provider.provide(userId);
144
- if (!data) {
145
- throw new Error(`User info not found for ${userId}`);
146
- }
147
- const entry = this.cache.get(userId);
148
- // Update the cache entry
149
- if (entry) {
150
- entry.data = data;
151
- entry.timestamp = Date.now();
152
- entry.subject.next(data);
153
- }
154
- else {
155
- // Create a new cache entry if needed
156
- const subject = new BehaviorSubject(data);
157
- this.cache.set(userId, {
158
- data,
159
- timestamp: Date.now(),
160
- subject
161
- });
151
+ async handleCompare(activity, event) {
152
+ event.stopPropagation(); // Prevent expanding/collapsing when clicking compare
153
+ // Get the previous activity for comparison
154
+ const currentIndex = this.activities().findIndex(a => a.id === activity.id);
155
+ if (currentIndex <= 0)
156
+ return; // No previous activity to compare with
157
+ const previousActivity = this.activities()[currentIndex - 1];
158
+ const ids = [
159
+ previousActivity.id,
160
+ activity.id
161
+ ];
162
+ // Execute the compare workflow
163
+ await this.workflowService.execute('show-entity-record-versions-compare', {
164
+ entity: activity.reference.type,
165
+ data: {
166
+ refId: activity.reference.id,
167
+ refType: activity.reference.type,
168
+ ids: ids
162
169
  }
163
- return data;
164
- }
165
- catch (error) {
166
- console.error(`Error fetching user info for ${userId}:`, error);
167
- throw error;
168
- }
170
+ });
169
171
  }
170
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
171
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, providedIn: 'root' }); }
172
+ /**
173
+ * Checks if an activity can be compared (has a previous version)
174
+ */
175
+ canCompare(activity) {
176
+ const currentIndex = this.activities().findIndex(a => a.id === activity.id);
177
+ return currentIndex > 0; // Can compare if not the first activity
178
+ }
179
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPActivityLogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
180
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPActivityLogComponent, isStandalone: true, selector: "axp-activity-log", inputs: { activities: { classPropertyName: "activities", publicName: "activities", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"axp-activity-log ax-accent2\" *translate=\"let t\">\n\n <!-- Activity Log Content -->\n <div class=\"__content\">\n\n <!-- Loading State -->\n @if (loading()) {\n <div class=\"__loading\">\n @for (item of [1,2,3,4]; track $index) {\n <div class=\"__item\">\n <ax-skeleton [animated]=\"true\" class=\"__avatar\"></ax-skeleton>\n <div class=\"__content\">\n <ax-skeleton [animated]=\"true\" class=\"__title\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__subtitle\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__description\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__time\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Activity Feed -->\n @if (!loading() && activities().length > 0) {\n <div class=\"__feed\">\n @for (activity of activities(); track activity.id) {\n @let changeClasses = getChangeClasses(activity.changeType);\n @let isItemExpanded = isExpanded(activity.id);\n @let hasExpandableContentItem = hasExpandableContent(activity);\n <div class=\"__item\" [class.__collapsed]=\"!isItemExpanded\" [class.__expandable]=\"hasExpandableContentItem\">\n\n <div\n class=\"ax-size-10 ax-rounded-full ax-border ax-flex ax-items-center ax-justify-center ax-lightest-surface \">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}} fa-solid\"></i>\n </div>\n\n <!-- Activity Content -->\n <div class=\"__content\">\n <!-- Main Activity Info -->\n <div class=\"__main-info\">\n\n <!-- User and Action with Toggle Button -->\n <div class=\"__action-line __header-line\" (click)=\"toggleExpanded(activity.id)\">\n <span class=\"__user-name\">{{ activity.user.title }}</span>\n <span class=\"__action-type\">\n {{ t(`actions.${activity.changeType}.title`, {\n scope: 'general' }) | async }}\n </span>\n <span class=\"__action-text\">\n {{ activity.title | translate | async }}\n </span>\n\n <!-- Compare Button -->\n @if (canCompare(activity)) {\n <button type=\"button\" class=\"__compare-button\" (click)=\"handleCompare(activity, $event)\"\n [attr.aria-label]=\"t('compare.title', { scope: i18nScope }) | async\">\n <i class=\"fa-solid fa-code-compare\"></i>\n </button>\n }\n\n <!-- Toggle Button (only show if there's expandable content) -->\n @if (hasExpandableContentItem) {\n <button type=\"button\" class=\"__toggle-button\" [attr.aria-expanded]=\"isItemExpanded\"\n [attr.aria-label]=\"isItemExpanded ? 'Collapse details' : 'Expand details'\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!isItemExpanded\"\n [class.fa-chevron-up]=\"isItemExpanded\"></i>\n </button>\n }\n </div>\n\n <!-- Expandable Description/Changes -->\n @if (hasExpandableContentItem && isItemExpanded && activity.changes.length > 0) {\n <div class=\"__action-lines __expandable-content\"\n [class.__animated]=\"shouldAnimate(activity.id)\">\n @for (change of activity.changes; track $index) {\n @let changeClasses = getChangeClasses(change.type);\n <div class=\"__action-line\">\n <div class=\"ax-rounded-full ax-size-7 ax-grid ax-place-items-center\">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}}\"></i>\n </div>\n <span class=\"__action-text\">{{\n change.description | translate | async }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Time -->\n <div class=\"__time\">\n {{ activity.date | format: 'datetime' : 'short' | async }}\n </div>\n\n </div>\n\n </div>\n }\n </div>\n }\n\n <!-- Empty State -->\n @if (!loading() && activities().length === 0) {\n <div class=\"__empty\">\n <div class=\"__icon\">\n <ax-icon icon=\"fa-light fa-history\" class=\"__svg\"></ax-icon>\n </div>\n <div class=\"__content\">\n <h4 class=\"__title\">{{ t('no-history.title', { scope: i18nScope }) | async }}</h4>\n <p class=\"__message\">{{ t('no-history.message', { scope: i18nScope }) | async }}\n </p>\n </div>\n </div>\n }\n\n </div>\n</div>\n\n<!-- \n\nax-success-surface\nax-primary-surface\nax-danger-surface\nax-warning-surface\nax-info-surface\nax-muted-surface\nax-text-success\n\n -->", styles: [".axp-activity-log{height:100%;width:100%}.axp-activity-log .__content .__loading>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item{display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__loading .__item .__avatar{height:3rem;width:3rem;flex-shrink:0;border-radius:9999px}.axp-activity-log .__content .__loading .__item .__content{flex:1 1 0%}.axp-activity-log .__content .__loading .__item .__content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item .__content .__title{height:1rem;width:75%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__subtitle{height:.75rem;width:50%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__description{height:.75rem;width:83.333333%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__time{height:.75rem;width:25%;border-radius:.25rem}.axp-activity-log .__content .__feed{position:relative}.axp-activity-log .__content .__feed>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__feed:before{content:\"\";position:absolute;inset-inline-start:1.25rem;top:.5rem;bottom:.5rem;width:0px;border-left:1px solid rgba(var(--ax-sys-color-border-surface));z-index:0}.axp-activity-log .__content .__feed .__item{position:relative;display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__feed .__item axp-user-avatar{position:relative;z-index:10}.axp-activity-log .__content .__feed .__item .__content{min-width:0px;flex:1 1 0%}.axp-activity-log .__content .__feed .__item .__content .__main-info{margin-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{margin-top:.25rem;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;line-height:1.5}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__user-name{font-weight:600}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-type,.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line{align-items:center;border-radius:.375rem;padding:.25rem .5rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button{margin-left:.5rem;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:hover{background-color:rgb(var(--ax-sys-color-primary-surface));color:rgb(var(--ax-sys-color-on-primary-surface));border-color:rgb(var(--ax-sys-color-border-primary-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button i{font-size:.75rem;line-height:1rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button{margin-left:auto;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button i{font-size:.75rem;line-height:1rem;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines{margin-top:.5rem;margin-bottom:.5rem;display:flex;flex-direction:column;font-size:.875rem;line-height:1.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content{overflow:hidden}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content.__animated{transition-property:all;transition-duration:.3s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(.4,0,.2,1);animation:slideDown .3s ease-out}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line{display:flex;align-items:center;gap:.5rem;padding-top:.25rem;padding-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__time{padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-activity-log .__content .__feed .__item.__collapsed .__expandable-content{display:none}.axp-activity-log .__content .__feed .__item.__expandable .__header-line{cursor:pointer}.axp-activity-log .__content .__empty{display:flex;height:12rem;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-activity-log .__content .__empty .__icon{margin-bottom:1rem}.axp-activity-log .__content .__empty .__icon .__svg{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__message{max-width:20rem;line-height:1.625;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.axp-activity-log .__content .__feed .__item{gap:.625rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{flex-wrap:nowrap}}@keyframes slideDown{0%{opacity:0;max-height:0;transform:translateY(-10px)}to{opacity:1;max-height:200px;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }, { kind: "directive", type: i3.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i4$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i5.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXAccordionCdkModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
172
181
  }
173
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, decorators: [{
174
- type: Injectable,
175
- args: [{
176
- providedIn: 'root',
177
- }]
178
- }] });
179
-
180
- class AXPUserAvatarComponent {
181
- constructor() {
182
- this.userAvatarService = inject(AXPUserAvatarService);
183
- this.destroy$ = new Subject();
184
- this.userInfo = signal(null);
185
- this.size = input(40);
186
- this.userId = input('');
187
- this.src = signal('');
188
- this.userName = computed(() => this.userInfo()?.username || '');
189
- this.firstName = computed(() => this.userInfo()?.firstName || 'Root');
190
- this.lastName = computed(() => this.userInfo()?.lastName || 'User');
191
- this.title = computed(() => `${this.firstName()} ${this.lastName()}`);
192
- this.isOnline = computed(() => this.userInfo()?.status === 'online');
193
- this.avatarText = computed(() => this.getInitials());
194
- this.avatarColor = computed(() => this.pickColor(this.avatarText()));
195
- this.hasPicture = signal(false);
196
- }
197
- onImageError(event) {
198
- this.hasPicture.set(false);
199
- }
200
- onImageLoad(event) {
201
- this.hasPicture.set(true);
202
- }
203
- ngOnInit() {
204
- this.loadUserData();
205
- }
206
- ngOnDestroy() {
207
- this.destroy$.next();
208
- this.destroy$.complete();
209
- }
210
- loadUserData() {
211
- // Skip if no username provided
212
- if (!this.userId()) {
213
- return;
214
- }
215
- // Subscribe to the user info observable to get real-time updates
216
- this.userAvatarService
217
- .getUserInfo$(this.userId())
218
- .pipe(takeUntil(this.destroy$))
219
- .subscribe((userData) => {
220
- this.userInfo.set(userData);
221
- // This is a placeholder - replace with your actual avatar URL logic
222
- this.generateAvatarSrc();
223
- });
224
- }
225
- /**
226
- * Generate avatar image source
227
- * This is a placeholder - implement based on your actual requirements
228
- */
229
- generateAvatarSrc() {
230
- // Example: Check if the user has a custom avatar URL
231
- // If not, generate a placeholder using initials
232
- if (this.userInfo()?.avatarUrl) {
233
- this.src.set(this.userInfo()?.avatarUrl);
234
- }
235
- else {
236
- // Generate a placeholder - you could use an external service like UI Avatars
237
- // or implement your own logic
238
- const initials = this.getInitials();
239
- this.src.set(`https://avatar.iran.liara.run/username?username=${encodeURIComponent(initials)}`);
240
- }
241
- }
242
- /**
243
- * Get initials from first and last name
244
- */
245
- getInitials() {
246
- const firstInitial = this.firstName().charAt(0).toUpperCase();
247
- const lastInitial = this.lastName().charAt(0).toUpperCase();
248
- return firstInitial + lastInitial;
249
- }
250
- hashString(str) {
251
- let hash = 0;
252
- for (let i = 0; i < str.length; i++) {
253
- hash = (hash << 5) - hash + str.charCodeAt(i);
254
- hash |= 0;
255
- }
256
- return Math.abs(hash);
257
- }
258
- pickColor(initials) {
259
- const colors = ['primary', 'secondary', 'danger', 'warning', 'success', 'accent1', 'accent2', 'accent3'];
260
- const idx = this.hashString(initials) % colors.length;
261
- return colors[idx];
262
- }
263
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
264
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPUserAvatarComponent, isStandalone: true, selector: "axp-user-avatar", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userId: { classPropertyName: "userId", publicName: "userId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [], ngImport: i0, template: "<ax-avatar #avatar [size]=\"size()\" class=\"ax-cursor-pointer\">\n @if(hasPicture()){\n <ax-image (onError)=\"onImageError($event)\" (onLoad)=\"onImageLoad($event)\" [src]=\"src()\"></ax-image>\n }@else{\n <ax-text class=\"ax-{{ avatarColor() }}-lightest \">\n <small class=\"ax-text-xs ax-font-semibold\">{{ avatarText() }}</small>\n </ax-text>\n }\n</ax-avatar>\n\n<!--\n\nax-primary-lightest\nax-warning-lightest\nax-success-lightest\nax-danger-lightest\nax-secondary-lightest\nax-accent1-lightest\nax-accent2-lightest\nax-accent3-lightest\n\n-->\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i1.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i3.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXBadgeModule }], encapsulation: i0.ViewEncapsulation.None }); }
265
- }
266
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarComponent, decorators: [{
182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPActivityLogComponent, decorators: [{
267
183
  type: Component,
268
- args: [{ selector: 'axp-user-avatar', imports: [
269
- AXAvatarModule,
184
+ args: [{ selector: 'axp-activity-log', standalone: true, imports: [
185
+ CommonModule,
186
+ AXButtonModule,
187
+ AXCommonModule,
270
188
  AXDecoratorModule,
271
- AXImageModule,
272
- AXBadgeModule
273
- ], encapsulation: ViewEncapsulation.None, providers: [], template: "<ax-avatar #avatar [size]=\"size()\" class=\"ax-cursor-pointer\">\n @if(hasPicture()){\n <ax-image (onError)=\"onImageError($event)\" (onLoad)=\"onImageLoad($event)\" [src]=\"src()\"></ax-image>\n }@else{\n <ax-text class=\"ax-{{ avatarColor() }}-lightest \">\n <small class=\"ax-text-xs ax-font-semibold\">{{ avatarText() }}</small>\n </ax-text>\n }\n</ax-avatar>\n\n<!--\n\nax-primary-lightest\nax-warning-lightest\nax-success-lightest\nax-danger-lightest\nax-secondary-lightest\nax-accent1-lightest\nax-accent2-lightest\nax-accent3-lightest\n\n-->\n" }]
274
- }] });
189
+ AXTranslationModule,
190
+ AXSkeletonModule,
191
+ AXFormatModule,
192
+ AXTagModule,
193
+ AXAccordionCdkModule,
194
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"axp-activity-log ax-accent2\" *translate=\"let t\">\n\n <!-- Activity Log Content -->\n <div class=\"__content\">\n\n <!-- Loading State -->\n @if (loading()) {\n <div class=\"__loading\">\n @for (item of [1,2,3,4]; track $index) {\n <div class=\"__item\">\n <ax-skeleton [animated]=\"true\" class=\"__avatar\"></ax-skeleton>\n <div class=\"__content\">\n <ax-skeleton [animated]=\"true\" class=\"__title\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__subtitle\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__description\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__time\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Activity Feed -->\n @if (!loading() && activities().length > 0) {\n <div class=\"__feed\">\n @for (activity of activities(); track activity.id) {\n @let changeClasses = getChangeClasses(activity.changeType);\n @let isItemExpanded = isExpanded(activity.id);\n @let hasExpandableContentItem = hasExpandableContent(activity);\n <div class=\"__item\" [class.__collapsed]=\"!isItemExpanded\" [class.__expandable]=\"hasExpandableContentItem\">\n\n <div\n class=\"ax-size-10 ax-rounded-full ax-border ax-flex ax-items-center ax-justify-center ax-lightest-surface \">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}} fa-solid\"></i>\n </div>\n\n <!-- Activity Content -->\n <div class=\"__content\">\n <!-- Main Activity Info -->\n <div class=\"__main-info\">\n\n <!-- User and Action with Toggle Button -->\n <div class=\"__action-line __header-line\" (click)=\"toggleExpanded(activity.id)\">\n <span class=\"__user-name\">{{ activity.user.title }}</span>\n <span class=\"__action-type\">\n {{ t(`actions.${activity.changeType}.title`, {\n scope: 'general' }) | async }}\n </span>\n <span class=\"__action-text\">\n {{ activity.title | translate | async }}\n </span>\n\n <!-- Compare Button -->\n @if (canCompare(activity)) {\n <button type=\"button\" class=\"__compare-button\" (click)=\"handleCompare(activity, $event)\"\n [attr.aria-label]=\"t('compare.title', { scope: i18nScope }) | async\">\n <i class=\"fa-solid fa-code-compare\"></i>\n </button>\n }\n\n <!-- Toggle Button (only show if there's expandable content) -->\n @if (hasExpandableContentItem) {\n <button type=\"button\" class=\"__toggle-button\" [attr.aria-expanded]=\"isItemExpanded\"\n [attr.aria-label]=\"isItemExpanded ? 'Collapse details' : 'Expand details'\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!isItemExpanded\"\n [class.fa-chevron-up]=\"isItemExpanded\"></i>\n </button>\n }\n </div>\n\n <!-- Expandable Description/Changes -->\n @if (hasExpandableContentItem && isItemExpanded && activity.changes.length > 0) {\n <div class=\"__action-lines __expandable-content\"\n [class.__animated]=\"shouldAnimate(activity.id)\">\n @for (change of activity.changes; track $index) {\n @let changeClasses = getChangeClasses(change.type);\n <div class=\"__action-line\">\n <div class=\"ax-rounded-full ax-size-7 ax-grid ax-place-items-center\">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}}\"></i>\n </div>\n <span class=\"__action-text\">{{\n change.description | translate | async }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Time -->\n <div class=\"__time\">\n {{ activity.date | format: 'datetime' : 'short' | async }}\n </div>\n\n </div>\n\n </div>\n }\n </div>\n }\n\n <!-- Empty State -->\n @if (!loading() && activities().length === 0) {\n <div class=\"__empty\">\n <div class=\"__icon\">\n <ax-icon icon=\"fa-light fa-history\" class=\"__svg\"></ax-icon>\n </div>\n <div class=\"__content\">\n <h4 class=\"__title\">{{ t('no-history.title', { scope: i18nScope }) | async }}</h4>\n <p class=\"__message\">{{ t('no-history.message', { scope: i18nScope }) | async }}\n </p>\n </div>\n </div>\n }\n\n </div>\n</div>\n\n<!-- \n\nax-success-surface\nax-primary-surface\nax-danger-surface\nax-warning-surface\nax-info-surface\nax-muted-surface\nax-text-success\n\n -->", styles: [".axp-activity-log{height:100%;width:100%}.axp-activity-log .__content .__loading>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item{display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__loading .__item .__avatar{height:3rem;width:3rem;flex-shrink:0;border-radius:9999px}.axp-activity-log .__content .__loading .__item .__content{flex:1 1 0%}.axp-activity-log .__content .__loading .__item .__content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item .__content .__title{height:1rem;width:75%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__subtitle{height:.75rem;width:50%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__description{height:.75rem;width:83.333333%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__time{height:.75rem;width:25%;border-radius:.25rem}.axp-activity-log .__content .__feed{position:relative}.axp-activity-log .__content .__feed>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__feed:before{content:\"\";position:absolute;inset-inline-start:1.25rem;top:.5rem;bottom:.5rem;width:0px;border-left:1px solid rgba(var(--ax-sys-color-border-surface));z-index:0}.axp-activity-log .__content .__feed .__item{position:relative;display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__feed .__item axp-user-avatar{position:relative;z-index:10}.axp-activity-log .__content .__feed .__item .__content{min-width:0px;flex:1 1 0%}.axp-activity-log .__content .__feed .__item .__content .__main-info{margin-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{margin-top:.25rem;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;line-height:1.5}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__user-name{font-weight:600}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-type,.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line{align-items:center;border-radius:.375rem;padding:.25rem .5rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button{margin-left:.5rem;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:hover{background-color:rgb(var(--ax-sys-color-primary-surface));color:rgb(var(--ax-sys-color-on-primary-surface));border-color:rgb(var(--ax-sys-color-border-primary-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button i{font-size:.75rem;line-height:1rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button{margin-left:auto;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button i{font-size:.75rem;line-height:1rem;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines{margin-top:.5rem;margin-bottom:.5rem;display:flex;flex-direction:column;font-size:.875rem;line-height:1.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content{overflow:hidden}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content.__animated{transition-property:all;transition-duration:.3s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(.4,0,.2,1);animation:slideDown .3s ease-out}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line{display:flex;align-items:center;gap:.5rem;padding-top:.25rem;padding-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__time{padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-activity-log .__content .__feed .__item.__collapsed .__expandable-content{display:none}.axp-activity-log .__content .__feed .__item.__expandable .__header-line{cursor:pointer}.axp-activity-log .__content .__empty{display:flex;height:12rem;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-activity-log .__content .__empty .__icon{margin-bottom:1rem}.axp-activity-log .__content .__empty .__icon .__svg{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__message{max-width:20rem;line-height:1.625;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.axp-activity-log .__content .__feed .__item{gap:.625rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{flex-wrap:nowrap}}@keyframes slideDown{0%{opacity:0;max-height:0;transform:translateY(-10px)}to{opacity:1;max-height:200px;transform:translateY(0)}}\n"] }]
195
+ }], ctorParameters: () => [] });
275
196
 
276
197
  const AXP_TASK_BADGE_PROVIDERS = new InjectionToken('AXP_TASK_BADGE_PROVIDERS');
277
198
  class AXPTaskBadgeProvider {
@@ -759,6 +680,137 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
759
680
  }]
760
681
  }] });
761
682
 
683
+ class AXPCompareViewComponent {
684
+ constructor() {
685
+ //#region ---- Component Properties ----
686
+ this.inputs = input();
687
+ this.showOnlyChanges = signal(false);
688
+ this.mode = input('compare');
689
+ this.removedObjects = signal([]);
690
+ this.isChangesMode = computed(() => this.mode() === 'changes');
691
+ //#endregion
692
+ //#region ---- Computed Properties ----
693
+ /**
694
+ * Filtered fields based on showOnlyChanges toggle
695
+ */
696
+ this.filteredFields = computed(() => {
697
+ const fields = this.inputs()?.fields ?? [];
698
+ if (!this.showOnlyChanges()) {
699
+ return fields;
700
+ }
701
+ // Filter to show only fields where values differ across objects
702
+ return fields.filter(field => this.hasUnequalValues(field.path));
703
+ });
704
+ this.remainingObjects = computed(() => {
705
+ const objects = this.inputs()?.objects ?? [];
706
+ return objects.filter(obj => !this.removedObjects().includes(obj.id));
707
+ });
708
+ }
709
+ //#endregion
710
+ //#region ---- Utility Methods ----
711
+ /**
712
+ * Check if a field value will change in the next object (to show arrow in current cell)
713
+ */
714
+ hasValueChangingToNext(fieldPath, currentObjectIndex) {
715
+ const objects = this.remainingObjects();
716
+ if (currentObjectIndex >= objects.length - 1)
717
+ return false;
718
+ const currentValue = objects[currentObjectIndex]?.context[fieldPath];
719
+ const nextValue = objects[currentObjectIndex + 1]?.context[fieldPath];
720
+ return !this.areValuesEqual(currentValue, nextValue);
721
+ }
722
+ /**
723
+ * Check if a field value has changed compared to the previous object
724
+ */
725
+ hasValueChangedFromPrevious(fieldPath, currentObjectIndex) {
726
+ const objects = this.remainingObjects();
727
+ if (currentObjectIndex === 0 || objects.length <= 1)
728
+ return false;
729
+ const currentValue = objects[currentObjectIndex]?.context[fieldPath];
730
+ const previousValue = objects[currentObjectIndex - 1]?.context[fieldPath];
731
+ return !this.areValuesEqual(currentValue, previousValue);
732
+ }
733
+ /**
734
+ * Check if a field has unequal values across objects
735
+ */
736
+ hasUnequalValues(fieldPath) {
737
+ const objects = this.remainingObjects();
738
+ if (objects.length <= 1)
739
+ return false;
740
+ const values = objects.map(obj => obj.context[fieldPath]);
741
+ const firstValue = values[0];
742
+ return values.some(value => !this.areValuesEqual(value, firstValue));
743
+ }
744
+ /**
745
+ * Check if a field has equal values across objects
746
+ */
747
+ hasEqualValues(fieldPath) {
748
+ const objects = this.remainingObjects();
749
+ if (objects.length <= 1)
750
+ return false;
751
+ const values = objects.map(obj => obj.context[fieldPath]);
752
+ const firstValue = values[0];
753
+ return values.every(value => this.areValuesEqual(value, firstValue));
754
+ }
755
+ /**
756
+ * Compare two values for equality (deep comparison for objects/arrays)
757
+ */
758
+ areValuesEqual(value1, value2) {
759
+ if (value1 === value2)
760
+ return true;
761
+ if (value1 == null || value2 == null)
762
+ return value1 === value2;
763
+ if (typeof value1 !== typeof value2)
764
+ return false;
765
+ if (typeof value1 === 'object') {
766
+ return JSON.stringify(value1) === JSON.stringify(value2);
767
+ }
768
+ return false;
769
+ }
770
+ /**
771
+ * Toggle the show only changes filter
772
+ */
773
+ toggleShowOnlyChanges() {
774
+ this.showOnlyChanges.update(value => !value);
775
+ }
776
+ /**
777
+ * Remove an object from the comparison
778
+ */
779
+ removeObject(objectId) {
780
+ this.removedObjects.update(objects => [...objects, objectId]);
781
+ }
782
+ //#endregion
783
+ //#region ---- Lifecycle Methods ----
784
+ ngOnInit() {
785
+ }
786
+ ngOnDestroy() {
787
+ }
788
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPCompareViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
789
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPCompareViewComponent, isStandalone: true, selector: "axp-compare-view", inputs: { inputs: { classPropertyName: "inputs", publicName: "inputs", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, providers: [], ngImport: i0, template: "<!--\n #region ---- Compare View Table Layout ----\n-->\n<div class=\"axp-compare-view\">\n <div class=\"__table-container\">\n <table class=\"__table\">\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <th class=\"__field-header\">\n <ax-check-box [value]=\"showOnlyChanges()\" (valueChange)=\"toggleShowOnlyChanges()\"\n class=\"__show-changes-toggle\">\n <ax-label>\n {{ 'compare-view.show-only-differences' | translate: { scope: 'common' } | async }}\n </ax-label>\n </ax-check-box>\n </th>\n @for (obj of remainingObjects(); track obj.id) {\n <th class=\"__object-header\" [attr.data-id]=\"obj.id\">\n <div class=\"__object-title\" [title]=\"obj.description\">\n <span>{{ obj.title | translate | async }}</span>\n @if (remainingObjects().length > 2) {\n <span class=\"__remove-object-button\" (click)=\"removeObject(obj.id)\">\n <i class=\"fa-light fa-times\"></i>\n </span>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"__tbody\">\n @for (field of filteredFields(); track field.path; let i = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"i % 2 === 1\" [class.__row--has-differences]=\"hasUnequalValues(field.path)\"\n [class.__row--has-equal-values]=\"hasEqualValues(field.path)\">\n <td class=\"__field-cell\">\n <div class=\"__field-content\">\n <div class=\"__field-title\">\n {{ field.title | translate | async }}\n </div>\n @if (field.description) {\n <div class=\"__field-description\">{{ field.description }}</div>\n }\n </div>\n </td>\n @for (obj of remainingObjects(); track obj.id; let objIndex = $index) {\n <td class=\"__object-cell\" [attr.data-id]=\"obj.id\"\n [class.__cell--changed]=\"hasValueChangedFromPrevious(field.path, objIndex) && isChangesMode()\">\n @if (obj.context[field.path] !== undefined) {\n <div class=\"__object-content\">\n <axp-widgets-container [context]=\"obj.context\">\n <ng-container axp-widget-renderer [node]=\"field.widget\" [mode]=\"'view'\"></ng-container>\n </axp-widgets-container>\n </div>\n } @else {\n <div class=\"__object-placeholder\">---</div>\n }\n @if (hasValueChangingToNext(field.path, objIndex) && isChangesMode()) {\n <div class=\"__change-indicator\">\n <i class=\"fa-light fa-arrow-right\"></i>\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n<!--\n #endregion\n-->", styles: [".axp-compare-view{display:flex;height:100%;width:100%;flex-direction:column;border-radius:.375rem;border-width:1px;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:relative}.axp-compare-view .__filter-controls{flex-shrink:0;border-bottom-width:1px;padding:1rem;background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}.axp-compare-view .__filter-controls .__show-changes-toggle{font-size:.875rem;line-height:1.25rem}.axp-compare-view .__table-container{flex:1 1 0%;overflow:auto;position:relative}.axp-compare-view .__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.axp-compare-view .__table .__thead{position:-webkit-sticky;position:sticky;top:0;z-index:20}.axp-compare-view .__table .__thead .__header-row .__field-header{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;text-align:left;font-weight:700;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));position:-webkit-sticky;position:sticky;left:0;z-index:25}.axp-compare-view .__table .__thead .__header-row .__object-header{position:relative;border-bottom-width:1px;padding:.75rem 1rem;text-align:center;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));min-width:250px;width:250px}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-description{margin-top:.25rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button{display:flex;width:1.5rem;height:1.5rem;cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));font-size:.875rem;line-height:1.25rem;position:absolute;top:50%;inset-inline-end:0px;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button:hover{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-100),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-danger-600),var(--tw-text-opacity, 1))}.axp-compare-view .__table .__tbody .__row{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-compare-view .__table .__tbody .__row.__row--odd{background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-compare-view .__table .__tbody .__row.__row--has-differences{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{background-color:rgba(var(--ax-sys-color-warning-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{background-color:rgba(var(--ax-sys-color-success-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row .__field-cell{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;vertical-align:top;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:-webkit-sticky;position:sticky;left:0;z-index:15}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content{display:flex;flex-direction:column;gap:.25rem}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-title{font-weight:500}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-description{font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__tbody .__row .__object-cell{border-bottom-width:1px;padding:.75rem 1rem;text-align:center;vertical-align:middle;position:relative}.axp-compare-view .__table .__tbody .__row .__object-cell.__cell--changed .__object-content{border-width:1px;border-style:dashed;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-warning-200),var(--tw-border-opacity, 1));padding:.5rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-content{position:relative;display:flex;align-items:center;justify-content:center}.axp-compare-view .__table .__tbody .__row .__object-cell .__change-indicator{position:absolute;inset-inline-end:-.25rem;top:50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));line-height:1rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-warning-500),var(--tw-text-opacity, 1));font-size:.875rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-placeholder{opacity:.75}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-900),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-900),var(--tw-bg-opacity, 1))}\n"], dependencies: [{ kind: "ngmodule", type:
790
+ // Angular
791
+ CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type:
792
+ // ACoreX
793
+ AXFormModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i2.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i3$1.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type:
794
+ // Platform
795
+ AXPLayoutBuilderModule }, { kind: "component", type: i5$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i5$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }], encapsulation: i0.ViewEncapsulation.None }); }
796
+ }
797
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPCompareViewComponent, decorators: [{
798
+ type: Component,
799
+ args: [{ selector: 'axp-compare-view', imports: [
800
+ // Angular
801
+ CommonModule,
802
+ // ACoreX
803
+ AXFormModule,
804
+ AXTextBoxModule,
805
+ AXButtonModule,
806
+ AXLabelModule,
807
+ AXCheckBoxModule,
808
+ AXTranslationModule,
809
+ // Platform
810
+ AXPLayoutBuilderModule
811
+ ], encapsulation: ViewEncapsulation.None, providers: [], template: "<!--\n #region ---- Compare View Table Layout ----\n-->\n<div class=\"axp-compare-view\">\n <div class=\"__table-container\">\n <table class=\"__table\">\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <th class=\"__field-header\">\n <ax-check-box [value]=\"showOnlyChanges()\" (valueChange)=\"toggleShowOnlyChanges()\"\n class=\"__show-changes-toggle\">\n <ax-label>\n {{ 'compare-view.show-only-differences' | translate: { scope: 'common' } | async }}\n </ax-label>\n </ax-check-box>\n </th>\n @for (obj of remainingObjects(); track obj.id) {\n <th class=\"__object-header\" [attr.data-id]=\"obj.id\">\n <div class=\"__object-title\" [title]=\"obj.description\">\n <span>{{ obj.title | translate | async }}</span>\n @if (remainingObjects().length > 2) {\n <span class=\"__remove-object-button\" (click)=\"removeObject(obj.id)\">\n <i class=\"fa-light fa-times\"></i>\n </span>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"__tbody\">\n @for (field of filteredFields(); track field.path; let i = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"i % 2 === 1\" [class.__row--has-differences]=\"hasUnequalValues(field.path)\"\n [class.__row--has-equal-values]=\"hasEqualValues(field.path)\">\n <td class=\"__field-cell\">\n <div class=\"__field-content\">\n <div class=\"__field-title\">\n {{ field.title | translate | async }}\n </div>\n @if (field.description) {\n <div class=\"__field-description\">{{ field.description }}</div>\n }\n </div>\n </td>\n @for (obj of remainingObjects(); track obj.id; let objIndex = $index) {\n <td class=\"__object-cell\" [attr.data-id]=\"obj.id\"\n [class.__cell--changed]=\"hasValueChangedFromPrevious(field.path, objIndex) && isChangesMode()\">\n @if (obj.context[field.path] !== undefined) {\n <div class=\"__object-content\">\n <axp-widgets-container [context]=\"obj.context\">\n <ng-container axp-widget-renderer [node]=\"field.widget\" [mode]=\"'view'\"></ng-container>\n </axp-widgets-container>\n </div>\n } @else {\n <div class=\"__object-placeholder\">---</div>\n }\n @if (hasValueChangingToNext(field.path, objIndex) && isChangesMode()) {\n <div class=\"__change-indicator\">\n <i class=\"fa-light fa-arrow-right\"></i>\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n<!--\n #endregion\n-->", styles: [".axp-compare-view{display:flex;height:100%;width:100%;flex-direction:column;border-radius:.375rem;border-width:1px;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:relative}.axp-compare-view .__filter-controls{flex-shrink:0;border-bottom-width:1px;padding:1rem;background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}.axp-compare-view .__filter-controls .__show-changes-toggle{font-size:.875rem;line-height:1.25rem}.axp-compare-view .__table-container{flex:1 1 0%;overflow:auto;position:relative}.axp-compare-view .__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.axp-compare-view .__table .__thead{position:-webkit-sticky;position:sticky;top:0;z-index:20}.axp-compare-view .__table .__thead .__header-row .__field-header{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;text-align:left;font-weight:700;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));position:-webkit-sticky;position:sticky;left:0;z-index:25}.axp-compare-view .__table .__thead .__header-row .__object-header{position:relative;border-bottom-width:1px;padding:.75rem 1rem;text-align:center;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));min-width:250px;width:250px}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-description{margin-top:.25rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button{display:flex;width:1.5rem;height:1.5rem;cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));font-size:.875rem;line-height:1.25rem;position:absolute;top:50%;inset-inline-end:0px;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button:hover{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-100),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-danger-600),var(--tw-text-opacity, 1))}.axp-compare-view .__table .__tbody .__row{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-compare-view .__table .__tbody .__row.__row--odd{background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-compare-view .__table .__tbody .__row.__row--has-differences{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{background-color:rgba(var(--ax-sys-color-warning-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{background-color:rgba(var(--ax-sys-color-success-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row .__field-cell{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;vertical-align:top;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:-webkit-sticky;position:sticky;left:0;z-index:15}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content{display:flex;flex-direction:column;gap:.25rem}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-title{font-weight:500}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-description{font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__tbody .__row .__object-cell{border-bottom-width:1px;padding:.75rem 1rem;text-align:center;vertical-align:middle;position:relative}.axp-compare-view .__table .__tbody .__row .__object-cell.__cell--changed .__object-content{border-width:1px;border-style:dashed;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-warning-200),var(--tw-border-opacity, 1));padding:.5rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-content{position:relative;display:flex;align-items:center;justify-content:center}.axp-compare-view .__table .__tbody .__row .__object-cell .__change-indicator{position:absolute;inset-inline-end:-.25rem;top:50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));line-height:1rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-warning-500),var(--tw-text-opacity, 1));font-size:.875rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-placeholder{opacity:.75}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-900),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-900),var(--tw-bg-opacity, 1))}\n"] }]
812
+ }] });
813
+
762
814
  class AXPComponentSlot {
763
815
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPComponentSlot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
764
816
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: AXPComponentSlot, isStandalone: true, ngImport: i0 }); }
@@ -945,287 +997,493 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
945
997
  args: ['AXPComponentSlotModuleFactory']
946
998
  }] }] });
947
999
 
948
- //#region ---- Component Definition ----
949
- class AXPActivityLogComponent {
950
- //#endregion
951
- //#region ---- Constructor & Lifecycle ----
1000
+ class AXPLayoutFiltersComponent {
952
1001
  constructor() {
953
- //#endregion
954
- //#region ---- Services & Dependencies ----
955
- this.translateService = inject(AXTranslationService);
956
- this.workflowService = inject(AXPWorkflowService);
957
- //#endregion
958
- //#region ---- Input Properties ----
959
- /**
960
- * Array of activity logs to display
961
- */
962
- this.activities = input([]);
963
- /**
964
- * Whether the component is in loading state
965
- */
966
- this.loading = input(false);
967
- //#endregion
968
- //#region ---- Component Properties ----
969
- this.i18nScope = 'activity-log';
970
- this.Object = Object;
971
- /**
972
- * Set of expanded activity IDs
973
- */
974
- this.expandedItems = signal(new Set());
975
- /**
976
- * Flag to track if component has been initialized
977
- */
978
- this.isInitialized = signal(false);
979
- /**
980
- * Set of items that have been manually toggled (for animation control)
981
- */
982
- this.manuallyToggledItems = signal(new Set());
983
- // Auto-expand top 5 items when activities change
984
- effect(() => {
985
- const activities = this.activities();
986
- const currentExpanded = this.expandedItems();
987
- const initialized = this.isInitialized();
988
- // Only auto-expand if not initialized and activities exist
989
- if (!initialized && activities.length > 0 && currentExpanded.size === 0) {
990
- const top5Ids = activities.slice(0, 5).map((activity) => activity.id);
991
- this.expandedItems.set(new Set(top5Ids));
992
- this.isInitialized.set(true);
1002
+ this.translate = inject(AXTranslationService);
1003
+ this.calendarService = inject(AXCalendarService);
1004
+ this.filterOperatorMiddleware = inject(AXPFilterOperatorMiddlewareService);
1005
+ this.filtersDefinitions = input([]);
1006
+ this.initialFilters = input([]);
1007
+ this.onFiltersChanged = output();
1008
+ this.tagBox = viewChild('tagBox');
1009
+ this.selectedField = signal(null);
1010
+ this.selectedFilters = linkedSignal(() => this.convertQueriesToDefinitions(this.initialFilters()).map((i) => ({ ...i, readOnly: true })));
1011
+ this.context = linkedSignal(() => this.convertQueriesToContext(this.initialFilters()));
1012
+ this.activeFilter = signal(null);
1013
+ this.asyncTags = signal([]);
1014
+ this.popover = viewChild('popover');
1015
+ this.inputValue = signal('');
1016
+ this.inlineFilters = () => {
1017
+ return this.filtersDefinitions().filter((f) => f.filterType.inline &&
1018
+ !this.filterOperatorMiddleware
1019
+ .transformFilters(this.selectedFilters())
1020
+ .some((sf) => sf.field === f.field &&
1021
+ sf.operator?.type === (this.context()[sf.field]?.operation?.type || f.operator?.type)));
1022
+ };
1023
+ this.getDisplayValue = async (filter, val) => {
1024
+ if (filter.widget.type === 'select-editor' || filter.widget.type === 'select-filter') {
1025
+ const dataSource = filter.widget.options?.['dataSource'];
1026
+ const textField = filter.widget.options?.['textField'];
1027
+ const valueField = filter.widget.options?.['valueField'];
1028
+ if (dataSource?.config?.byKey) {
1029
+ if (Array.isArray(val)) {
1030
+ const results = await Promise.all(val.map((v) => dataSource.config.byKey(v)));
1031
+ return results.map((data) => data[textField]).join(', ');
1032
+ }
1033
+ else {
1034
+ const data = (await dataSource.config.byKey(val));
1035
+ return data?.[textField] || val;
1036
+ }
1037
+ }
1038
+ else if (Array.isArray(dataSource)) {
1039
+ if (Array.isArray(val)) {
1040
+ return dataSource.map((data) => data[textField]).join(', ');
1041
+ }
1042
+ else {
1043
+ const record = dataSource.find((d) => d[valueField] === val);
1044
+ return record ? record[textField] : '';
1045
+ }
1046
+ }
1047
+ }
1048
+ return typeof val === 'object' && !Array.isArray(val)
1049
+ ? `${this.convertIfISOStringDate(val.from)} and ${this.convertIfISOStringDate(val.to)}`
1050
+ : this.convertIfISOStringDate(val);
1051
+ };
1052
+ this.convertIfISOStringDate = (val) => {
1053
+ const isISOStringDate = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(val);
1054
+ if (isISOStringDate) {
1055
+ return this.calendarService.convert(val).date.toLocaleDateString();
993
1056
  }
1057
+ return val;
1058
+ };
1059
+ this.filterFields = () => {
1060
+ return this.filtersDefinitions().filter((f) => {
1061
+ return (f.filterType.advance &&
1062
+ !this.selectedFilters().some((sf) => {
1063
+ return sf.field === f.field;
1064
+ }));
1065
+ });
1066
+ };
1067
+ this.#effect = effect(() => {
1068
+ const context = untracked(() => this.context());
1069
+ const selectedFilters = this.selectedFilters();
1070
+ untracked(() => {
1071
+ const convertedFilters = selectedFilters.map((f) => ({
1072
+ field: f.field,
1073
+ operator: context[f.field]?.operation,
1074
+ value: context[f.field]?.value,
1075
+ }));
1076
+ const newContext = {};
1077
+ convertedFilters.forEach((cf) => {
1078
+ newContext[cf.field] = {
1079
+ value: cf.value,
1080
+ operation: typeof cf.operator === 'string' ? { type: cf.operator } : cf.operator,
1081
+ };
1082
+ });
1083
+ this.context.set(newContext);
1084
+ this.deactivateAllListItems();
1085
+ this.onFiltersChanged.emit(convertedFilters);
1086
+ });
1087
+ });
1088
+ this.#effect2 = effect(() => {
1089
+ const filters = this.selectedFilters();
1090
+ const context = this.context();
1091
+ Promise.all(filters.map(async (filter) => {
1092
+ const val = context[filter.field]?.value;
1093
+ const displayValue = await this.getDisplayValue(filter, val);
1094
+ return {
1095
+ ...filter,
1096
+ query: `${this.translate.translateSync(filter.title)} ${this.getActiveOperator(filter)} '${displayValue}'`,
1097
+ };
1098
+ })).then((results) => {
1099
+ this.asyncTags.set(results);
1100
+ });
994
1101
  });
995
1102
  }
996
- //#endregion
997
- //#region ---- Utility Methods ----
998
- /**
999
- * Gets the appropriate CSS class for the change type
1000
- */
1001
- getChangeClasses(changeType) {
1002
- const action = getSystemActions(changeType);
1003
- return {
1004
- surface: action?.color ? `ax-${action.color}-surface` : 'ax-muted-surface',
1005
- text: action?.color ? `ax-text-${action.color}` : 'ax-text-muted',
1006
- icon: action?.icon ? `${action.icon}` : 'fa-light fa-pen'
1007
- };
1103
+ convertQueriesToDefinitions(queries) {
1104
+ const definitions = this.filtersDefinitions();
1105
+ return queries.map((q) => {
1106
+ const definition = definitions.find((p) => p.field === q.field);
1107
+ return {
1108
+ field: q.field,
1109
+ operator: q.operator,
1110
+ value: q.value,
1111
+ title: definition?.title || '',
1112
+ widget: definition?.widget,
1113
+ filterType: definition?.filterType,
1114
+ };
1115
+ });
1008
1116
  }
1009
- /**
1010
- * Checks if an activity item is expanded
1011
- */
1012
- isExpanded(activityId) {
1013
- return this.expandedItems().has(activityId);
1117
+ convertQueriesToContext(queries) {
1118
+ return queries.reduce((acc, q) => {
1119
+ acc[q.field] = { value: q.value, operation: q.operator };
1120
+ return acc;
1121
+ }, {});
1014
1122
  }
1015
- /**
1016
- * Toggles the expanded state of an activity item
1017
- */
1018
- toggleExpanded(activityId) {
1019
- const currentExpanded = new Set(this.expandedItems());
1020
- const currentManuallyToggled = new Set(this.manuallyToggledItems());
1021
- // Mark this item as manually toggled for animation purposes
1022
- currentManuallyToggled.add(activityId);
1023
- this.manuallyToggledItems.set(currentManuallyToggled);
1024
- if (currentExpanded.has(activityId)) {
1025
- currentExpanded.delete(activityId);
1123
+ ngOnInit() {
1124
+ this.tagBoxInput = this.tagBox()?.getHostElement().querySelector('input');
1125
+ }
1126
+ handleSelectField(field) {
1127
+ this.activeFilter.set(field);
1128
+ // this.inputValue.set('');
1129
+ this.tagBox()?.inputValue.set('');
1130
+ }
1131
+ handleFieldKeyDown(e, field) {
1132
+ if (e.key === 'Enter') {
1133
+ this.handleSelectField(field);
1134
+ }
1135
+ }
1136
+ onContextChanged(e) {
1137
+ this.context.set(e.data);
1138
+ }
1139
+ handleApplyFilter() {
1140
+ if (this.activeFilter()) {
1141
+ this.selectedFilters.update((prev) => [...prev, this.activeFilter()]);
1142
+ this.activeFilter.set(null);
1143
+ this.popover()?.close();
1144
+ }
1145
+ }
1146
+ handleButtonKeyDown(e) {
1147
+ if (this.popover()?.isOpen && !this.activeFilter()) {
1148
+ // Find first list item and focus it
1149
+ const firstItem = document.querySelector('[axListNavigationItem]');
1150
+ if (firstItem) {
1151
+ firstItem.focus();
1152
+ e?.preventDefault();
1153
+ }
1154
+ }
1155
+ }
1156
+ handleKeyDown(e) {
1157
+ if (e.nativeEvent?.key === 'ArrowDown') {
1158
+ if (this.popover()?.isOpen && !this.activeFilter()) {
1159
+ // Find first list item and focus it
1160
+ const firstItem = document.querySelector('[axListNavigationItem]');
1161
+ if (firstItem) {
1162
+ firstItem.focus();
1163
+ e.nativeEvent?.preventDefault();
1164
+ }
1165
+ }
1026
1166
  }
1027
1167
  else {
1028
- currentExpanded.add(activityId);
1168
+ this.popover()?.open();
1029
1169
  }
1030
- this.expandedItems.set(currentExpanded);
1031
1170
  }
1032
- /**
1033
- * Checks if an item should have expand/collapse animation
1034
- */
1035
- shouldAnimate(activityId) {
1036
- return this.manuallyToggledItems().has(activityId);
1171
+ #effect;
1172
+ handleSelectFilters(e) {
1173
+ if (e.value?.length < this.selectedFilters().length) {
1174
+ this.selectedFilters.update((prev) => {
1175
+ return e.value;
1176
+ });
1177
+ }
1037
1178
  }
1038
- /**
1039
- * Checks if an activity has expandable content (changes)
1040
- */
1041
- hasExpandableContent(activity) {
1042
- return activity.changes && activity.changes.length > 0;
1179
+ getActiveOperator(filter) {
1180
+ if (!filter) {
1181
+ return undefined;
1182
+ }
1183
+ const contextOperation = this.context()?.[filter.field]?.operation?.type;
1184
+ const operatorType = contextOperation || filter.operator?.type;
1185
+ return ALL_DEFAULT_OPERATORS.find((o) => o.name === operatorType)?.title;
1043
1186
  }
1044
- //#endregion
1045
- //#region ---- Compare Methods ----
1046
- /**
1047
- * Handles the compare action for an activity
1048
- */
1049
- async handleCompare(activity, event) {
1050
- event.stopPropagation(); // Prevent expanding/collapsing when clicking compare
1051
- // Get the previous activity for comparison
1052
- const currentIndex = this.activities().findIndex(a => a.id === activity.id);
1053
- if (currentIndex <= 0)
1054
- return; // No previous activity to compare with
1055
- const previousActivity = this.activities()[currentIndex - 1];
1056
- const ids = [
1057
- previousActivity.id,
1058
- activity.id
1059
- ];
1060
- // Execute the compare workflow
1061
- await this.workflowService.execute('show-entity-record-versions-compare', {
1062
- entity: activity.reference.type,
1063
- data: {
1064
- refId: activity.reference.id,
1065
- refType: activity.reference.type,
1066
- ids: ids
1067
- }
1068
- });
1187
+ handleSelectInlineFilter(filter) {
1188
+ this.context.update((prev) => ({
1189
+ ...prev,
1190
+ [filter.field]: {
1191
+ value: this.tagBox()?.inputValue(),
1192
+ operation: { type: 'contains' },
1193
+ },
1194
+ }));
1195
+ this.tagBox()?.inputValue.set('');
1196
+ this.selectedFilters.update((prev) => [...prev, filter]);
1197
+ this.popover()?.close();
1069
1198
  }
1070
- /**
1071
- * Checks if an activity can be compared (has a previous version)
1072
- */
1073
- canCompare(activity) {
1074
- const currentIndex = this.activities().findIndex(a => a.id === activity.id);
1075
- return currentIndex > 0; // Can compare if not the first activity
1199
+ handleInlineFilterKeyDown(e, filter) {
1200
+ if (e.key === 'Enter') {
1201
+ this.handleSelectInlineFilter(filter);
1202
+ }
1076
1203
  }
1077
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPActivityLogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1078
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPActivityLogComponent, isStandalone: true, selector: "axp-activity-log", inputs: { activities: { classPropertyName: "activities", publicName: "activities", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"axp-activity-log ax-accent2\" *translate=\"let t\">\n\n <!-- Activity Log Content -->\n <div class=\"__content\">\n\n <!-- Loading State -->\n @if (loading()) {\n <div class=\"__loading\">\n @for (item of [1,2,3,4]; track $index) {\n <div class=\"__item\">\n <ax-skeleton [animated]=\"true\" class=\"__avatar\"></ax-skeleton>\n <div class=\"__content\">\n <ax-skeleton [animated]=\"true\" class=\"__title\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__subtitle\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__description\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__time\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Activity Feed -->\n @if (!loading() && activities().length > 0) {\n <div class=\"__feed\">\n @for (activity of activities(); track activity.id) {\n @let changeClasses = getChangeClasses(activity.changeType);\n @let isItemExpanded = isExpanded(activity.id);\n @let hasExpandableContentItem = hasExpandableContent(activity);\n <div class=\"__item\" [class.__collapsed]=\"!isItemExpanded\" [class.__expandable]=\"hasExpandableContentItem\">\n\n <div\n class=\"ax-size-10 ax-rounded-full ax-border ax-flex ax-items-center ax-justify-center ax-lightest-surface \">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}} fa-solid\"></i>\n </div>\n\n <!-- Activity Content -->\n <div class=\"__content\">\n <!-- Main Activity Info -->\n <div class=\"__main-info\">\n\n <!-- User and Action with Toggle Button -->\n <div class=\"__action-line __header-line\" (click)=\"toggleExpanded(activity.id)\">\n <span class=\"__user-name\">{{ activity.user.title }}</span>\n <span class=\"__action-type\">\n {{ t(`actions.${activity.changeType}.title`, {\n scope: 'general' }) | async }}\n </span>\n <span class=\"__action-text\">\n {{ activity.title | translate | async }}\n </span>\n\n <!-- Compare Button -->\n @if (canCompare(activity)) {\n <button type=\"button\" class=\"__compare-button\" (click)=\"handleCompare(activity, $event)\"\n [attr.aria-label]=\"t('compare.title', { scope: i18nScope }) | async\">\n <i class=\"fa-solid fa-code-compare\"></i>\n </button>\n }\n\n <!-- Toggle Button (only show if there's expandable content) -->\n @if (hasExpandableContentItem) {\n <button type=\"button\" class=\"__toggle-button\" [attr.aria-expanded]=\"isItemExpanded\"\n [attr.aria-label]=\"isItemExpanded ? 'Collapse details' : 'Expand details'\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!isItemExpanded\"\n [class.fa-chevron-up]=\"isItemExpanded\"></i>\n </button>\n }\n </div>\n\n <!-- Expandable Description/Changes -->\n @if (hasExpandableContentItem && isItemExpanded && activity.changes.length > 0) {\n <div class=\"__action-lines __expandable-content\"\n [class.__animated]=\"shouldAnimate(activity.id)\">\n @for (change of activity.changes; track $index) {\n @let changeClasses = getChangeClasses(change.type);\n <div class=\"__action-line\">\n <div class=\"ax-rounded-full ax-size-7 ax-grid ax-place-items-center\">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}}\"></i>\n </div>\n <span class=\"__action-text\">{{\n change.description | translate | async }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Time -->\n <div class=\"__time\">\n {{ activity.date | format: 'datetime' : 'short' | async }}\n </div>\n\n </div>\n\n </div>\n }\n </div>\n }\n\n <!-- Empty State -->\n @if (!loading() && activities().length === 0) {\n <div class=\"__empty\">\n <div class=\"__icon\">\n <ax-icon icon=\"fa-light fa-history\" class=\"__svg\"></ax-icon>\n </div>\n <div class=\"__content\">\n <h4 class=\"__title\">{{ t('no-history.title', { scope: i18nScope }) | async }}</h4>\n <p class=\"__message\">{{ t('no-history.message', { scope: i18nScope }) | async }}\n </p>\n </div>\n </div>\n }\n\n </div>\n</div>\n\n<!-- \n\nax-success-surface\nax-primary-surface\nax-danger-surface\nax-warning-surface\nax-info-surface\nax-muted-surface\nax-text-success\n\n -->", styles: [".axp-activity-log{height:100%;width:100%}.axp-activity-log .__content .__loading>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item{display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__loading .__item .__avatar{height:3rem;width:3rem;flex-shrink:0;border-radius:9999px}.axp-activity-log .__content .__loading .__item .__content{flex:1 1 0%}.axp-activity-log .__content .__loading .__item .__content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item .__content .__title{height:1rem;width:75%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__subtitle{height:.75rem;width:50%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__description{height:.75rem;width:83.333333%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__time{height:.75rem;width:25%;border-radius:.25rem}.axp-activity-log .__content .__feed{position:relative}.axp-activity-log .__content .__feed>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__feed:before{content:\"\";position:absolute;inset-inline-start:1.25rem;top:.5rem;bottom:.5rem;width:0px;border-left:1px solid rgba(var(--ax-sys-color-border-surface));z-index:0}.axp-activity-log .__content .__feed .__item{position:relative;display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__feed .__item axp-user-avatar{position:relative;z-index:10}.axp-activity-log .__content .__feed .__item .__content{min-width:0px;flex:1 1 0%}.axp-activity-log .__content .__feed .__item .__content .__main-info{margin-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{margin-top:.25rem;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;line-height:1.5}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__user-name{font-weight:600}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-type,.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line{align-items:center;border-radius:.375rem;padding:.25rem .5rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button{margin-left:.5rem;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:hover{background-color:rgb(var(--ax-sys-color-primary-surface));color:rgb(var(--ax-sys-color-on-primary-surface));border-color:rgb(var(--ax-sys-color-border-primary-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button i{font-size:.75rem;line-height:1rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button{margin-left:auto;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button i{font-size:.75rem;line-height:1rem;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines{margin-top:.5rem;margin-bottom:.5rem;display:flex;flex-direction:column;font-size:.875rem;line-height:1.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content{overflow:hidden}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content.__animated{transition-property:all;transition-duration:.3s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(.4,0,.2,1);animation:slideDown .3s ease-out}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line{display:flex;align-items:center;gap:.5rem;padding-top:.25rem;padding-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__time{padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-activity-log .__content .__feed .__item.__collapsed .__expandable-content{display:none}.axp-activity-log .__content .__feed .__item.__expandable .__header-line{cursor:pointer}.axp-activity-log .__content .__empty{display:flex;height:12rem;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-activity-log .__content .__empty .__icon{margin-bottom:1rem}.axp-activity-log .__content .__empty .__icon .__svg{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__message{max-width:20rem;line-height:1.625;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.axp-activity-log .__content .__feed .__item{gap:.625rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{flex-wrap:nowrap}}@keyframes slideDown{0%{opacity:0;max-height:0;transform:translateY(-10px)}to{opacity:1;max-height:200px;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXCommonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }, { kind: "directive", type: i3$1.AXTranslatorDirective, selector: "[translate]" }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i4.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXFormatModule }, { kind: "pipe", type: i5.AXFormatPipe, name: "format" }, { kind: "ngmodule", type: AXTagModule }, { kind: "ngmodule", type: AXAccordionCdkModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1204
+ handlePopoverClosed(e) {
1205
+ this.activeFilter.set(null);
1206
+ }
1207
+ onPopoverOpened(e) {
1208
+ if (this.filtersDefinitions().length === 0) {
1209
+ this.popover()?.close();
1210
+ }
1211
+ }
1212
+ deactivateAllListItems() {
1213
+ if (this.listItems) {
1214
+ this.listItems.forEach((item) => {
1215
+ if (item.isActive()) {
1216
+ item.isActive.set(false);
1217
+ }
1218
+ });
1219
+ }
1220
+ }
1221
+ #effect2;
1222
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPLayoutFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1223
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPLayoutFiltersComponent, isStandalone: true, selector: "axp-layout-filters", inputs: { filtersDefinitions: { classPropertyName: "filtersDefinitions", publicName: "filtersDefinitions", isSignal: true, isRequired: false, transformFunction: null }, initialFilters: { classPropertyName: "initialFilters", publicName: "initialFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onFiltersChanged: "onFiltersChanged" }, viewQueries: [{ propertyName: "tagBox", first: true, predicate: ["tagBox"], descendants: true, isSignal: true }, { propertyName: "popover", first: true, predicate: ["popover"], descendants: true, isSignal: true }, { propertyName: "listItems", predicate: ["caseItem"], descendants: true }], ngImport: i0, template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"(filtersDefinitions().length === 0 ? 'filter.noRecords' : 'filter.title') | translate | async\"\n #tagBox\n ></ax-tag-box>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div class=\"md:ax-min-w-72 ax-border ax-surface ax-w-full ax-rounded-md md:ax-max-h-96 md:ax-overflow-auto\">\n <axp-widgets-container [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"ax-flex ax-flex-col ax-lightest-surface ax-shadow-md\">\n <ax-header class=\"ax-border-b ax-border-light ax-px-4 ax-py-2\">{{\n activeFilter()?.title! | translate | async\n }}</ax-header>\n <ax-content class=\"ax-p-4\">\n <div class=\"ax-mb-2\">\n <ax-badge [text]=\"getActiveOperator(activeFilter())!\"></ax-badge>\n </div>\n <ng-container\n axp-widget-renderer\n [node]=\"{\n type: activeFilter()?.widget?.type || 'text-editor',\n path: activeFilter()?.field,\n options: activeFilter()?.widget?.options,\n }\"\n [mode]=\"'edit'\"\n >\n </ng-container>\n </ax-content>\n <ax-footer class=\"ax-border-t ax-flex ax-justify-end ax-border-light ax-w-full ax-px-4 ax-py-2\">\n <ax-button class=\"ax-xs\" [text]=\"'apply' | translate | async\" (onClick)=\"handleApplyFilter()\"></ax-button>\n </ax-footer>\n </div>\n } @else {\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items\">\n @if (tagBox.inputValue()) {\n @for (inlineFilter of inlineFilters(); track inlineFilter.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n tabindex=\"0\"\n (click)=\"handleSelectInlineFilter(inlineFilter)\"\n (keydown)=\"handleInlineFilterKeyDown($event, inlineFilter)\"\n >\n {{ inlineFilter.title | translate | async }} {{ getActiveOperator(inlineFilter) }} '{{\n tagBox.inputValue()\n }}'\n </div>\n }\n <span class=\"ax-w-full ax-border-t ax-border-light ax-my-1\"></span>\n }\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n tabindex=\"0\"\n >\n <div class=\"ax-flex ax-items-end ax-gap-2\">\n <ax-icon class=\"ax-w-5\" [class]=\"'fa-light ' + field.icon\"> </ax-icon>\n {{ field.title | translate | async }}\n </div>\n </div>\n }\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["axp-layout-filters{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i3$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i4.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type: AXPopoverModule }, { kind: "component", type: i6.AXPopoverComponent, selector: "ax-popover", inputs: ["offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "backdropClass", "panelClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXSelectionListModule }, { kind: "ngmodule", type: AXTagBoxModule }, { kind: "component", type: i7.AXTagBoxComponent, selector: "ax-tag-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "allowNull", "type", "look", "addOnComma", "addOnEnter", "valueField", "textField", "readonlyField", "allowDuplicateValues"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXPLayoutBuilderModule }, { kind: "component", type: i5$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i5$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXListNavigationModule }, { kind: "directive", type: i9.AXListNavigationDirective, selector: "[axListNavigation]", inputs: ["orientation"], outputs: ["onNavigationChanged", "onPressEnterOrSpace"], exportAs: ["axListNavigation"] }, { kind: "directive", type: i9.AXListNavigationItemDirective, selector: "[axListNavigationItem]", exportAs: ["axListNavigationItem"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i10.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "text", "look"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1079
1224
  }
1080
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPActivityLogComponent, decorators: [{
1225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPLayoutFiltersComponent, decorators: [{
1081
1226
  type: Component,
1082
- args: [{ selector: 'axp-activity-log', standalone: true, imports: [
1227
+ args: [{ selector: 'axp-layout-filters', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
1083
1228
  CommonModule,
1229
+ FormsModule,
1084
1230
  AXButtonModule,
1085
- AXCommonModule,
1086
1231
  AXDecoratorModule,
1087
1232
  AXTranslationModule,
1088
- AXSkeletonModule,
1089
- AXFormatModule,
1090
- AXTagModule,
1091
- AXAccordionCdkModule,
1092
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"axp-activity-log ax-accent2\" *translate=\"let t\">\n\n <!-- Activity Log Content -->\n <div class=\"__content\">\n\n <!-- Loading State -->\n @if (loading()) {\n <div class=\"__loading\">\n @for (item of [1,2,3,4]; track $index) {\n <div class=\"__item\">\n <ax-skeleton [animated]=\"true\" class=\"__avatar\"></ax-skeleton>\n <div class=\"__content\">\n <ax-skeleton [animated]=\"true\" class=\"__title\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__subtitle\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__description\"></ax-skeleton>\n <ax-skeleton [animated]=\"true\" class=\"__time\"></ax-skeleton>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Activity Feed -->\n @if (!loading() && activities().length > 0) {\n <div class=\"__feed\">\n @for (activity of activities(); track activity.id) {\n @let changeClasses = getChangeClasses(activity.changeType);\n @let isItemExpanded = isExpanded(activity.id);\n @let hasExpandableContentItem = hasExpandableContent(activity);\n <div class=\"__item\" [class.__collapsed]=\"!isItemExpanded\" [class.__expandable]=\"hasExpandableContentItem\">\n\n <div\n class=\"ax-size-10 ax-rounded-full ax-border ax-flex ax-items-center ax-justify-center ax-lightest-surface \">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}} fa-solid\"></i>\n </div>\n\n <!-- Activity Content -->\n <div class=\"__content\">\n <!-- Main Activity Info -->\n <div class=\"__main-info\">\n\n <!-- User and Action with Toggle Button -->\n <div class=\"__action-line __header-line\" (click)=\"toggleExpanded(activity.id)\">\n <span class=\"__user-name\">{{ activity.user.title }}</span>\n <span class=\"__action-type\">\n {{ t(`actions.${activity.changeType}.title`, {\n scope: 'general' }) | async }}\n </span>\n <span class=\"__action-text\">\n {{ activity.title | translate | async }}\n </span>\n\n <!-- Compare Button -->\n @if (canCompare(activity)) {\n <button type=\"button\" class=\"__compare-button\" (click)=\"handleCompare(activity, $event)\"\n [attr.aria-label]=\"t('compare.title', { scope: i18nScope }) | async\">\n <i class=\"fa-solid fa-code-compare\"></i>\n </button>\n }\n\n <!-- Toggle Button (only show if there's expandable content) -->\n @if (hasExpandableContentItem) {\n <button type=\"button\" class=\"__toggle-button\" [attr.aria-expanded]=\"isItemExpanded\"\n [attr.aria-label]=\"isItemExpanded ? 'Collapse details' : 'Expand details'\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!isItemExpanded\"\n [class.fa-chevron-up]=\"isItemExpanded\"></i>\n </button>\n }\n </div>\n\n <!-- Expandable Description/Changes -->\n @if (hasExpandableContentItem && isItemExpanded && activity.changes.length > 0) {\n <div class=\"__action-lines __expandable-content\"\n [class.__animated]=\"shouldAnimate(activity.id)\">\n @for (change of activity.changes; track $index) {\n @let changeClasses = getChangeClasses(change.type);\n <div class=\"__action-line\">\n <div class=\"ax-rounded-full ax-size-7 ax-grid ax-place-items-center\">\n <i class=\"{{changeClasses.icon}} {{changeClasses.text}}\"></i>\n </div>\n <span class=\"__action-text\">{{\n change.description | translate | async }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Time -->\n <div class=\"__time\">\n {{ activity.date | format: 'datetime' : 'short' | async }}\n </div>\n\n </div>\n\n </div>\n }\n </div>\n }\n\n <!-- Empty State -->\n @if (!loading() && activities().length === 0) {\n <div class=\"__empty\">\n <div class=\"__icon\">\n <ax-icon icon=\"fa-light fa-history\" class=\"__svg\"></ax-icon>\n </div>\n <div class=\"__content\">\n <h4 class=\"__title\">{{ t('no-history.title', { scope: i18nScope }) | async }}</h4>\n <p class=\"__message\">{{ t('no-history.message', { scope: i18nScope }) | async }}\n </p>\n </div>\n </div>\n }\n\n </div>\n</div>\n\n<!-- \n\nax-success-surface\nax-primary-surface\nax-danger-surface\nax-warning-surface\nax-info-surface\nax-muted-surface\nax-text-success\n\n -->", styles: [".axp-activity-log{height:100%;width:100%}.axp-activity-log .__content .__loading>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item{display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__loading .__item .__avatar{height:3rem;width:3rem;flex-shrink:0;border-radius:9999px}.axp-activity-log .__content .__loading .__item .__content{flex:1 1 0%}.axp-activity-log .__content .__loading .__item .__content>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__loading .__item .__content .__title{height:1rem;width:75%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__subtitle{height:.75rem;width:50%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__description{height:.75rem;width:83.333333%;border-radius:.25rem}.axp-activity-log .__content .__loading .__item .__content .__time{height:.75rem;width:25%;border-radius:.25rem}.axp-activity-log .__content .__feed{position:relative}.axp-activity-log .__content .__feed>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.axp-activity-log .__content .__feed:before{content:\"\";position:absolute;inset-inline-start:1.25rem;top:.5rem;bottom:.5rem;width:0px;border-left:1px solid rgba(var(--ax-sys-color-border-surface));z-index:0}.axp-activity-log .__content .__feed .__item{position:relative;display:flex;align-items:flex-start;gap:1rem}.axp-activity-log .__content .__feed .__item axp-user-avatar{position:relative;z-index:10}.axp-activity-log .__content .__feed .__item .__content{min-width:0px;flex:1 1 0%}.axp-activity-log .__content .__feed .__item .__content .__main-info{margin-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{margin-top:.25rem;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;line-height:1.5}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__user-name{font-weight:600}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-type,.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line{align-items:center;border-radius:.375rem;padding:.25rem .5rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button{margin-left:.5rem;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-500),var(--tw-text-opacity, 1))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:hover{background-color:rgb(var(--ax-sys-color-primary-surface));color:rgb(var(--ax-sys-color-on-primary-surface));border-color:rgb(var(--ax-sys-color-border-primary-surface))}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__compare-button i{font-size:.75rem;line-height:1rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button{margin-left:auto;border-radius:9999px;padding:.25rem;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s;display:flex;width:1.5rem;height:1.5rem;align-items:center;justify-content:center}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgba(var(--ax-sys-color-primary-500), var(--tw-ring-opacity, 1));--tw-ring-offset-width: 1px}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line.__header-line .__toggle-button i{font-size:.75rem;line-height:1rem;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines{margin-top:.5rem;margin-bottom:.5rem;display:flex;flex-direction:column;font-size:.875rem;line-height:1.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content{overflow:hidden}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines.__expandable-content.__animated{transition-property:all;transition-duration:.3s;transition-timing-function:cubic-bezier(.4,0,.2,1);animation-duration:.3s;animation-timing-function:cubic-bezier(.4,0,.2,1);animation:slideDown .3s ease-out}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line{display:flex;align-items:center;gap:.5rem;padding-top:.25rem;padding-bottom:.25rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-lines .__action-line .__action-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;opacity:.85}.axp-activity-log .__content .__feed .__item .__content .__time{padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-activity-log .__content .__feed .__item.__collapsed .__expandable-content{display:none}.axp-activity-log .__content .__feed .__item.__expandable .__header-line{cursor:pointer}.axp-activity-log .__content .__empty{display:flex;height:12rem;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center}.axp-activity-log .__content .__empty .__icon{margin-bottom:1rem}.axp-activity-log .__content .__empty .__icon .__svg{font-size:2.25rem;line-height:2.5rem;--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__title{margin-bottom:.5rem;font-size:1.125rem;line-height:1.75rem;font-weight:600;--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.axp-activity-log .__content .__empty .__content .__message{max-width:20rem;line-height:1.625;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}@media (min-width: 640px){.axp-activity-log .__content .__feed .__item{gap:.625rem}.axp-activity-log .__content .__feed .__item .__content .__main-info .__action-line{flex-wrap:nowrap}}@keyframes slideDown{0%{opacity:0;max-height:0;transform:translateY(-10px)}to{opacity:1;max-height:200px;transform:translateY(0)}}\n"] }]
1093
- }], ctorParameters: () => [] });
1233
+ AXPopoverModule,
1234
+ AXSelectionListModule,
1235
+ AXTagBoxModule,
1236
+ AXPLayoutBuilderModule,
1237
+ AXListNavigationModule,
1238
+ AXBadgeModule,
1239
+ ], template: "<div class=\"ax-flex ax-items-center ax-gap-2 ax-p-2\">\n <ax-button (keydown)=\"handleButtonKeyDown($event)\" (onClick)=\"popover.open()\" #filterButton [look]=\"'blank'\">\n <ax-icon class=\"far fa-bars-filter ax-cursor-pointer\"> </ax-icon>\n </ax-button>\n <ax-tag-box\n [ngModel]=\"asyncTags()\"\n (onValueChanged)=\"handleSelectFilters($event)\"\n [textField]=\"'query'\"\n [valueField]=\"'id'\"\n [readonly]=\"filtersDefinitions().length === 0\"\n [look]=\"'none'\"\n [readonlyField]=\"'readOnly'\"\n (onKeyDown)=\"handleKeyDown($event)\"\n [addOnEnter]=\"false\"\n [placeholder]=\"(filtersDefinitions().length === 0 ? 'filter.noRecords' : 'filter.title') | translate | async\"\n #tagBox\n ></ax-tag-box>\n</div>\n\n<ax-popover\n [offsetY]=\"activeFilter() ? -30 : 0\"\n [target]=\"tagBoxInput\"\n [openOn]=\"'toggle'\"\n (onOpened)=\"onPopoverOpened($event)\"\n [closeOn]=\"'clickOut'\"\n (onClosed)=\"handlePopoverClosed($event)\"\n [adaptivityEnabled]=\"true\"\n #popover\n>\n <div class=\"md:ax-min-w-72 ax-border ax-surface ax-w-full ax-rounded-md md:ax-max-h-96 md:ax-overflow-auto\">\n <axp-widgets-container [context]=\"context()\" (onContextChanged)=\"onContextChanged($event)\">\n @if (activeFilter()) {\n <div class=\"ax-flex ax-flex-col ax-lightest-surface ax-shadow-md\">\n <ax-header class=\"ax-border-b ax-border-light ax-px-4 ax-py-2\">{{\n activeFilter()?.title! | translate | async\n }}</ax-header>\n <ax-content class=\"ax-p-4\">\n <div class=\"ax-mb-2\">\n <ax-badge [text]=\"getActiveOperator(activeFilter())!\"></ax-badge>\n </div>\n <ng-container\n axp-widget-renderer\n [node]=\"{\n type: activeFilter()?.widget?.type || 'text-editor',\n path: activeFilter()?.field,\n options: activeFilter()?.widget?.options,\n }\"\n [mode]=\"'edit'\"\n >\n </ng-container>\n </ax-content>\n <ax-footer class=\"ax-border-t ax-flex ax-justify-end ax-border-light ax-w-full ax-px-4 ax-py-2\">\n <ax-button class=\"ax-xs\" [text]=\"'apply' | translate | async\" (onClick)=\"handleApplyFilter()\"></ax-button>\n </ax-footer>\n </div>\n } @else {\n <div axListNavigation #list=\"axListNavigation\" class=\"axp-list-items\">\n @if (tagBox.inputValue()) {\n @for (inlineFilter of inlineFilters(); track inlineFilter.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n tabindex=\"0\"\n (click)=\"handleSelectInlineFilter(inlineFilter)\"\n (keydown)=\"handleInlineFilterKeyDown($event, inlineFilter)\"\n >\n {{ inlineFilter.title | translate | async }} {{ getActiveOperator(inlineFilter) }} '{{\n tagBox.inputValue()\n }}'\n </div>\n }\n <span class=\"ax-w-full ax-border-t ax-border-light ax-my-1\"></span>\n }\n @for (field of filterFields(); track field.field) {\n <div\n axListNavigationItem\n #caseItem=\"axListNavigationItem\"\n [class.axp-state-focused]=\"caseItem.isActive()\"\n (click)=\"handleSelectField(field)\"\n (keydown)=\"handleFieldKeyDown($event, field)\"\n tabindex=\"0\"\n >\n <div class=\"ax-flex ax-items-end ax-gap-2\">\n <ax-icon class=\"ax-w-5\" [class]=\"'fa-light ' + field.icon\"> </ax-icon>\n {{ field.title | translate | async }}\n </div>\n </div>\n }\n </div>\n }\n </axp-widgets-container>\n </div>\n</ax-popover>\n", styles: ["axp-layout-filters{width:100%}\n"] }]
1240
+ }], propDecorators: { listItems: [{
1241
+ type: ViewChildren,
1242
+ args: ['caseItem']
1243
+ }] } });
1094
1244
 
1095
- class AXPCompareViewComponent {
1096
- constructor() {
1097
- //#region ---- Component Properties ----
1098
- this.inputs = input();
1099
- this.showOnlyChanges = signal(false);
1100
- this.mode = input('compare');
1101
- this.removedObjects = signal([]);
1102
- this.isChangesMode = computed(() => this.mode() === 'changes');
1103
- //#endregion
1104
- //#region ---- Computed Properties ----
1105
- /**
1106
- * Filtered fields based on showOnlyChanges toggle
1107
- */
1108
- this.filteredFields = computed(() => {
1109
- const fields = this.inputs()?.fields ?? [];
1110
- if (!this.showOnlyChanges()) {
1111
- return fields;
1112
- }
1113
- // Filter to show only fields where values differ across objects
1114
- return fields.filter(field => this.hasUnequalValues(field.path));
1115
- });
1116
- this.remainingObjects = computed(() => {
1117
- const objects = this.inputs()?.objects ?? [];
1118
- return objects.filter(obj => !this.removedObjects().includes(obj.id));
1245
+ const AXP_USER_AVATAR_PROVIDER = new InjectionToken('AXP_USER_AVATAR_PROVIDER', {
1246
+ providedIn: 'root',
1247
+ factory: () => {
1248
+ return new AXPUserAvatarProviderDefault();
1249
+ }
1250
+ });
1251
+ class AXPUserAvatarProviderDefault {
1252
+ provide(userId) {
1253
+ return Promise.resolve({
1254
+ id: userId,
1255
+ username: 'johndoe',
1256
+ firstName: 'John',
1257
+ lastName: 'Doe',
1258
+ status: 'online',
1259
+ avatarUrl: 'https://via.placeholder.com/150',
1119
1260
  });
1120
1261
  }
1121
- //#endregion
1122
- //#region ---- Utility Methods ----
1262
+ }
1263
+
1264
+ class AXPUserAvatarService {
1265
+ constructor() {
1266
+ this.provider = inject(AXP_USER_AVATAR_PROVIDER);
1267
+ // Cache configuration
1268
+ this.cacheExpiryTime = 5 * 60 * 1000; // 5 minutes in milliseconds
1269
+ this.refreshInterval = 3 * 60 * 1000; // 3 minutes in milliseconds
1270
+ // Cache storage
1271
+ this.cache = new Map();
1272
+ }
1123
1273
  /**
1124
- * Check if a field value will change in the next object (to show arrow in current cell)
1274
+ * Gets user information with caching and auto-refresh
1275
+ * @param userId The username to fetch information for
1276
+ * @returns Observable that emits user avatar data
1125
1277
  */
1126
- hasValueChangingToNext(fieldPath, currentObjectIndex) {
1127
- const objects = this.remainingObjects();
1128
- if (currentObjectIndex >= objects.length - 1)
1129
- return false;
1130
- const currentValue = objects[currentObjectIndex]?.context[fieldPath];
1131
- const nextValue = objects[currentObjectIndex + 1]?.context[fieldPath];
1132
- return !this.areValuesEqual(currentValue, nextValue);
1278
+ getUserInfo$(userId) {
1279
+ // Check if we have a cached entry
1280
+ if (!this.cache.has(userId) || this.isExpired(userId)) {
1281
+ // Create a new cache entry with default values
1282
+ const defaultData = {
1283
+ id: userId,
1284
+ status: 'offline',
1285
+ username: '',
1286
+ firstName: '',
1287
+ lastName: ''
1288
+ };
1289
+ const subject = new BehaviorSubject(defaultData);
1290
+ this.cache.set(userId, {
1291
+ data: defaultData,
1292
+ timestamp: Date.now(),
1293
+ subject
1294
+ });
1295
+ // Fetch fresh data immediately
1296
+ this.fetchAndUpdateCache(userId);
1297
+ // Set up auto refresh
1298
+ timer(this.refreshInterval, this.refreshInterval)
1299
+ .pipe(tap(() => this.fetchAndUpdateCache(userId)))
1300
+ .subscribe();
1301
+ }
1302
+ return this.cache.get(userId).subject.asObservable();
1133
1303
  }
1134
1304
  /**
1135
- * Check if a field value has changed compared to the previous object
1305
+ * Gets user information (Promise-based for backward compatibility)
1306
+ * @param userId The username to fetch information for
1307
+ * @returns Promise that resolves to user avatar data
1136
1308
  */
1137
- hasValueChangedFromPrevious(fieldPath, currentObjectIndex) {
1138
- const objects = this.remainingObjects();
1139
- if (currentObjectIndex === 0 || objects.length <= 1)
1140
- return false;
1141
- const currentValue = objects[currentObjectIndex]?.context[fieldPath];
1142
- const previousValue = objects[currentObjectIndex - 1]?.context[fieldPath];
1143
- return !this.areValuesEqual(currentValue, previousValue);
1309
+ async getUserInfo(userId) {
1310
+ // Check if we have an unexpired cached entry
1311
+ if (this.cache.has(userId) && !this.isExpired(userId)) {
1312
+ return this.cache.get(userId).data;
1313
+ }
1314
+ // Fetch fresh data and cache it
1315
+ return this.fetchAndUpdateCache(userId);
1144
1316
  }
1145
1317
  /**
1146
- * Check if a field has unequal values across objects
1318
+ * Clears the entire cache or a specific user's cache
1319
+ * @param userId Optional username to clear specific cache
1147
1320
  */
1148
- hasUnequalValues(fieldPath) {
1149
- const objects = this.remainingObjects();
1150
- if (objects.length <= 1)
1151
- return false;
1152
- const values = objects.map(obj => obj.context[fieldPath]);
1153
- const firstValue = values[0];
1154
- return values.some(value => !this.areValuesEqual(value, firstValue));
1321
+ clearCache(userId) {
1322
+ if (userId) {
1323
+ this.cache.delete(userId);
1324
+ }
1325
+ else {
1326
+ this.cache.clear();
1327
+ }
1155
1328
  }
1156
1329
  /**
1157
- * Check if a field has equal values across objects
1330
+ * Force refresh data for a specific username
1331
+ * @param userId The username to refresh
1332
+ * @returns Promise that resolves to the refreshed data
1158
1333
  */
1159
- hasEqualValues(fieldPath) {
1160
- const objects = this.remainingObjects();
1161
- if (objects.length <= 1)
1162
- return false;
1163
- const values = objects.map(obj => obj.context[fieldPath]);
1164
- const firstValue = values[0];
1165
- return values.every(value => this.areValuesEqual(value, firstValue));
1334
+ async refreshUserInfo(userId) {
1335
+ return this.fetchAndUpdateCache(userId);
1166
1336
  }
1167
1337
  /**
1168
- * Compare two values for equality (deep comparison for objects/arrays)
1338
+ * Checks if a cache entry is expired
1169
1339
  */
1170
- areValuesEqual(value1, value2) {
1171
- if (value1 === value2)
1340
+ isExpired(userId) {
1341
+ const entry = this.cache.get(userId);
1342
+ if (!entry)
1172
1343
  return true;
1173
- if (value1 == null || value2 == null)
1174
- return value1 === value2;
1175
- if (typeof value1 !== typeof value2)
1176
- return false;
1177
- if (typeof value1 === 'object') {
1178
- return JSON.stringify(value1) === JSON.stringify(value2);
1344
+ return (Date.now() - entry.timestamp) > this.cacheExpiryTime;
1345
+ }
1346
+ /**
1347
+ * Fetches data from provider and updates the cache
1348
+ */
1349
+ async fetchAndUpdateCache(userId) {
1350
+ try {
1351
+ const data = await this.provider.provide(userId);
1352
+ if (!data) {
1353
+ throw new Error(`User info not found for ${userId}`);
1354
+ }
1355
+ const entry = this.cache.get(userId);
1356
+ // Update the cache entry
1357
+ if (entry) {
1358
+ entry.data = data;
1359
+ entry.timestamp = Date.now();
1360
+ entry.subject.next(data);
1361
+ }
1362
+ else {
1363
+ // Create a new cache entry if needed
1364
+ const subject = new BehaviorSubject(data);
1365
+ this.cache.set(userId, {
1366
+ data,
1367
+ timestamp: Date.now(),
1368
+ subject
1369
+ });
1370
+ }
1371
+ return data;
1372
+ }
1373
+ catch (error) {
1374
+ console.error(`Error fetching user info for ${userId}:`, error);
1375
+ throw error;
1179
1376
  }
1180
- return false;
1377
+ }
1378
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1379
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, providedIn: 'root' }); }
1380
+ }
1381
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarService, decorators: [{
1382
+ type: Injectable,
1383
+ args: [{
1384
+ providedIn: 'root',
1385
+ }]
1386
+ }] });
1387
+
1388
+ class AXPUserAvatarComponent {
1389
+ constructor() {
1390
+ this.userAvatarService = inject(AXPUserAvatarService);
1391
+ this.destroy$ = new Subject();
1392
+ this.userInfo = signal(null);
1393
+ this.size = input(40);
1394
+ this.userId = input('');
1395
+ this.src = signal('');
1396
+ this.userName = computed(() => this.userInfo()?.username || '');
1397
+ this.firstName = computed(() => this.userInfo()?.firstName || 'Root');
1398
+ this.lastName = computed(() => this.userInfo()?.lastName || 'User');
1399
+ this.title = computed(() => `${this.firstName()} ${this.lastName()}`);
1400
+ this.isOnline = computed(() => this.userInfo()?.status === 'online');
1401
+ this.avatarText = computed(() => this.getInitials());
1402
+ this.avatarColor = computed(() => this.pickColor(this.avatarText()));
1403
+ this.hasPicture = signal(false);
1404
+ }
1405
+ onImageError(event) {
1406
+ this.hasPicture.set(false);
1407
+ }
1408
+ onImageLoad(event) {
1409
+ this.hasPicture.set(true);
1410
+ }
1411
+ ngOnInit() {
1412
+ this.loadUserData();
1413
+ }
1414
+ ngOnDestroy() {
1415
+ this.destroy$.next();
1416
+ this.destroy$.complete();
1417
+ }
1418
+ loadUserData() {
1419
+ // Skip if no username provided
1420
+ if (!this.userId()) {
1421
+ return;
1422
+ }
1423
+ // Subscribe to the user info observable to get real-time updates
1424
+ this.userAvatarService
1425
+ .getUserInfo$(this.userId())
1426
+ .pipe(takeUntil(this.destroy$))
1427
+ .subscribe((userData) => {
1428
+ this.userInfo.set(userData);
1429
+ // This is a placeholder - replace with your actual avatar URL logic
1430
+ this.generateAvatarSrc();
1431
+ });
1181
1432
  }
1182
1433
  /**
1183
- * Toggle the show only changes filter
1434
+ * Generate avatar image source
1435
+ * This is a placeholder - implement based on your actual requirements
1184
1436
  */
1185
- toggleShowOnlyChanges() {
1186
- this.showOnlyChanges.update(value => !value);
1437
+ generateAvatarSrc() {
1438
+ // Example: Check if the user has a custom avatar URL
1439
+ // If not, generate a placeholder using initials
1440
+ if (this.userInfo()?.avatarUrl) {
1441
+ this.src.set(this.userInfo()?.avatarUrl);
1442
+ }
1443
+ else {
1444
+ // Generate a placeholder - you could use an external service like UI Avatars
1445
+ // or implement your own logic
1446
+ const initials = this.getInitials();
1447
+ this.src.set(`https://avatar.iran.liara.run/username?username=${encodeURIComponent(initials)}`);
1448
+ }
1187
1449
  }
1188
1450
  /**
1189
- * Remove an object from the comparison
1451
+ * Get initials from first and last name
1190
1452
  */
1191
- removeObject(objectId) {
1192
- this.removedObjects.update(objects => [...objects, objectId]);
1453
+ getInitials() {
1454
+ const firstInitial = this.firstName().charAt(0).toUpperCase();
1455
+ const lastInitial = this.lastName().charAt(0).toUpperCase();
1456
+ return firstInitial + lastInitial;
1193
1457
  }
1194
- //#endregion
1195
- //#region ---- Lifecycle Methods ----
1196
- ngOnInit() {
1458
+ hashString(str) {
1459
+ let hash = 0;
1460
+ for (let i = 0; i < str.length; i++) {
1461
+ hash = (hash << 5) - hash + str.charCodeAt(i);
1462
+ hash |= 0;
1463
+ }
1464
+ return Math.abs(hash);
1197
1465
  }
1198
- ngOnDestroy() {
1466
+ pickColor(initials) {
1467
+ const colors = ['primary', 'secondary', 'danger', 'warning', 'success', 'accent1', 'accent2', 'accent3'];
1468
+ const idx = this.hashString(initials) % colors.length;
1469
+ return colors[idx];
1199
1470
  }
1200
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPCompareViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1201
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPCompareViewComponent, isStandalone: true, selector: "axp-compare-view", inputs: { inputs: { classPropertyName: "inputs", publicName: "inputs", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, providers: [], ngImport: i0, template: "<!--\n #region ---- Compare View Table Layout ----\n-->\n<div class=\"axp-compare-view\">\n <div class=\"__table-container\">\n <table class=\"__table\">\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <th class=\"__field-header\">\n <ax-check-box [value]=\"showOnlyChanges()\" (valueChange)=\"toggleShowOnlyChanges()\"\n class=\"__show-changes-toggle\">\n <ax-label>\n {{ 'compare-view.show-only-differences' | translate: { scope: 'common' } | async }}\n </ax-label>\n </ax-check-box>\n </th>\n @for (obj of remainingObjects(); track obj.id) {\n <th class=\"__object-header\" [attr.data-id]=\"obj.id\">\n <div class=\"__object-title\" [title]=\"obj.description\">\n <span>{{ obj.title | translate | async }}</span>\n @if (remainingObjects().length > 2) {\n <span class=\"__remove-object-button\" (click)=\"removeObject(obj.id)\">\n <i class=\"fa-light fa-times\"></i>\n </span>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"__tbody\">\n @for (field of filteredFields(); track field.path; let i = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"i % 2 === 1\" [class.__row--has-differences]=\"hasUnequalValues(field.path)\"\n [class.__row--has-equal-values]=\"hasEqualValues(field.path)\">\n <td class=\"__field-cell\">\n <div class=\"__field-content\">\n <div class=\"__field-title\">\n {{ field.title | translate | async }}\n </div>\n @if (field.description) {\n <div class=\"__field-description\">{{ field.description }}</div>\n }\n </div>\n </td>\n @for (obj of remainingObjects(); track obj.id; let objIndex = $index) {\n <td class=\"__object-cell\" [attr.data-id]=\"obj.id\"\n [class.__cell--changed]=\"hasValueChangedFromPrevious(field.path, objIndex) && isChangesMode()\">\n @if (obj.context[field.path] !== undefined) {\n <div class=\"__object-content\">\n <axp-widgets-container [context]=\"obj.context\">\n <ng-container axp-widget-renderer [node]=\"field.widget\" [mode]=\"'view'\"></ng-container>\n </axp-widgets-container>\n </div>\n } @else {\n <div class=\"__object-placeholder\">---</div>\n }\n @if (hasValueChangingToNext(field.path, objIndex) && isChangesMode()) {\n <div class=\"__change-indicator\">\n <i class=\"fa-light fa-arrow-right\"></i>\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n<!--\n #endregion\n-->", styles: [".axp-compare-view{display:flex;height:100%;width:100%;flex-direction:column;border-radius:.375rem;border-width:1px;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:relative}.axp-compare-view .__filter-controls{flex-shrink:0;border-bottom-width:1px;padding:1rem;background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}.axp-compare-view .__filter-controls .__show-changes-toggle{font-size:.875rem;line-height:1.25rem}.axp-compare-view .__table-container{flex:1 1 0%;overflow:auto;position:relative}.axp-compare-view .__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.axp-compare-view .__table .__thead{position:-webkit-sticky;position:sticky;top:0;z-index:20}.axp-compare-view .__table .__thead .__header-row .__field-header{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;text-align:left;font-weight:700;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));position:-webkit-sticky;position:sticky;left:0;z-index:25}.axp-compare-view .__table .__thead .__header-row .__object-header{position:relative;border-bottom-width:1px;padding:.75rem 1rem;text-align:center;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));min-width:250px;width:250px}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-description{margin-top:.25rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button{display:flex;width:1.5rem;height:1.5rem;cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));font-size:.875rem;line-height:1.25rem;position:absolute;top:50%;inset-inline-end:0px;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button:hover{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-100),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-danger-600),var(--tw-text-opacity, 1))}.axp-compare-view .__table .__tbody .__row{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-compare-view .__table .__tbody .__row.__row--odd{background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-compare-view .__table .__tbody .__row.__row--has-differences{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{background-color:rgba(var(--ax-sys-color-warning-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{background-color:rgba(var(--ax-sys-color-success-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row .__field-cell{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;vertical-align:top;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:-webkit-sticky;position:sticky;left:0;z-index:15}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content{display:flex;flex-direction:column;gap:.25rem}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-title{font-weight:500}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-description{font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__tbody .__row .__object-cell{border-bottom-width:1px;padding:.75rem 1rem;text-align:center;vertical-align:middle;position:relative}.axp-compare-view .__table .__tbody .__row .__object-cell.__cell--changed .__object-content{border-width:1px;border-style:dashed;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-warning-200),var(--tw-border-opacity, 1));padding:.5rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-content{position:relative;display:flex;align-items:center;justify-content:center}.axp-compare-view .__table .__tbody .__row .__object-cell .__change-indicator{position:absolute;inset-inline-end:-.25rem;top:50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));line-height:1rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-warning-500),var(--tw-text-opacity, 1));font-size:.875rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-placeholder{opacity:.75}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-900),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-900),var(--tw-bg-opacity, 1))}\n"], dependencies: [{ kind: "ngmodule", type:
1202
- // Angular
1203
- CommonModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "ngmodule", type:
1204
- // ACoreX
1205
- AXFormModule }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXLabelModule }, { kind: "component", type: i2$1.AXLabelComponent, selector: "ax-label", inputs: ["required", "for"], outputs: ["requiredChange"] }, { kind: "ngmodule", type: AXCheckBoxModule }, { kind: "component", type: i3$2.AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "checked", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }, { kind: "ngmodule", type:
1206
- // Platform
1207
- AXPLayoutBuilderModule }, { kind: "component", type: i5$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i5$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }], encapsulation: i0.ViewEncapsulation.None }); }
1471
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1472
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: AXPUserAvatarComponent, isStandalone: true, selector: "axp-user-avatar", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userId: { classPropertyName: "userId", publicName: "userId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [], ngImport: i0, template: "<ax-avatar #avatar [size]=\"size()\" class=\"ax-cursor-pointer\">\n @if(hasPicture()){\n <ax-image (onError)=\"onImageError($event)\" (onLoad)=\"onImageLoad($event)\" [src]=\"src()\"></ax-image>\n }@else{\n <ax-text class=\"ax-{{ avatarColor() }}-lightest \">\n <small class=\"ax-text-xs ax-font-semibold\">{{ avatarText() }}</small>\n </ax-text>\n }\n</ax-avatar>\n\n<!--\n\nax-primary-lightest\nax-warning-lightest\nax-success-lightest\nax-danger-lightest\nax-secondary-lightest\nax-accent1-lightest\nax-accent2-lightest\nax-accent3-lightest\n\n-->\n", styles: [""], dependencies: [{ kind: "ngmodule", type: AXAvatarModule }, { kind: "component", type: i1$1.AXAvatarComponent, selector: "ax-avatar", inputs: ["color", "size", "shape", "look"], outputs: ["sizeChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXImageModule }, { kind: "component", type: i3$3.AXImageComponent, selector: "ax-image", inputs: ["width", "height", "overlayMode", "src", "alt", "priority", "lazy"], outputs: ["onLoad", "onError"] }, { kind: "ngmodule", type: AXBadgeModule }], encapsulation: i0.ViewEncapsulation.None }); }
1208
1473
  }
1209
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPCompareViewComponent, decorators: [{
1474
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXPUserAvatarComponent, decorators: [{
1210
1475
  type: Component,
1211
- args: [{ selector: 'axp-compare-view', imports: [
1212
- // Angular
1213
- CommonModule,
1214
- // ACoreX
1215
- AXFormModule,
1216
- AXTextBoxModule,
1217
- AXButtonModule,
1218
- AXLabelModule,
1219
- AXCheckBoxModule,
1220
- AXTranslationModule,
1221
- // Platform
1222
- AXPLayoutBuilderModule
1223
- ], encapsulation: ViewEncapsulation.None, providers: [], template: "<!--\n #region ---- Compare View Table Layout ----\n-->\n<div class=\"axp-compare-view\">\n <div class=\"__table-container\">\n <table class=\"__table\">\n <thead class=\"__thead\">\n <tr class=\"__header-row\">\n <th class=\"__field-header\">\n <ax-check-box [value]=\"showOnlyChanges()\" (valueChange)=\"toggleShowOnlyChanges()\"\n class=\"__show-changes-toggle\">\n <ax-label>\n {{ 'compare-view.show-only-differences' | translate: { scope: 'common' } | async }}\n </ax-label>\n </ax-check-box>\n </th>\n @for (obj of remainingObjects(); track obj.id) {\n <th class=\"__object-header\" [attr.data-id]=\"obj.id\">\n <div class=\"__object-title\" [title]=\"obj.description\">\n <span>{{ obj.title | translate | async }}</span>\n @if (remainingObjects().length > 2) {\n <span class=\"__remove-object-button\" (click)=\"removeObject(obj.id)\">\n <i class=\"fa-light fa-times\"></i>\n </span>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody class=\"__tbody\">\n @for (field of filteredFields(); track field.path; let i = $index) {\n <tr class=\"__row\" [class.__row--odd]=\"i % 2 === 1\" [class.__row--has-differences]=\"hasUnequalValues(field.path)\"\n [class.__row--has-equal-values]=\"hasEqualValues(field.path)\">\n <td class=\"__field-cell\">\n <div class=\"__field-content\">\n <div class=\"__field-title\">\n {{ field.title | translate | async }}\n </div>\n @if (field.description) {\n <div class=\"__field-description\">{{ field.description }}</div>\n }\n </div>\n </td>\n @for (obj of remainingObjects(); track obj.id; let objIndex = $index) {\n <td class=\"__object-cell\" [attr.data-id]=\"obj.id\"\n [class.__cell--changed]=\"hasValueChangedFromPrevious(field.path, objIndex) && isChangesMode()\">\n @if (obj.context[field.path] !== undefined) {\n <div class=\"__object-content\">\n <axp-widgets-container [context]=\"obj.context\">\n <ng-container axp-widget-renderer [node]=\"field.widget\" [mode]=\"'view'\"></ng-container>\n </axp-widgets-container>\n </div>\n } @else {\n <div class=\"__object-placeholder\">---</div>\n }\n @if (hasValueChangingToNext(field.path, objIndex) && isChangesMode()) {\n <div class=\"__change-indicator\">\n <i class=\"fa-light fa-arrow-right\"></i>\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n</div>\n<!--\n #endregion\n-->", styles: [".axp-compare-view{display:flex;height:100%;width:100%;flex-direction:column;border-radius:.375rem;border-width:1px;--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:relative}.axp-compare-view .__filter-controls{flex-shrink:0;border-bottom-width:1px;padding:1rem;background-color:rgb(var(--ax-sys-color-light-surface));color:rgb(var(--ax-sys-color-on-light-surface));border-color:rgb(var(--ax-sys-color-border-light-surface))}.axp-compare-view .__filter-controls .__show-changes-toggle{font-size:.875rem;line-height:1.25rem}.axp-compare-view .__table-container{flex:1 1 0%;overflow:auto;position:relative}.axp-compare-view .__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.axp-compare-view .__table .__thead{position:-webkit-sticky;position:sticky;top:0;z-index:20}.axp-compare-view .__table .__thead .__header-row .__field-header{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;text-align:left;font-weight:700;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));position:-webkit-sticky;position:sticky;left:0;z-index:25}.axp-compare-view .__table .__thead .__header-row .__object-header{position:relative;border-bottom-width:1px;padding:.75rem 1rem;text-align:center;background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface));min-width:250px;width:250px}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.875rem;line-height:1.25rem;font-weight:600}.axp-compare-view .__table .__thead .__header-row .__object-header .__object-description{margin-top:.25rem;font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button{display:flex;width:1.5rem;height:1.5rem;cursor:pointer;align-items:center;justify-content:center;border-radius:9999px;--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-light-surface),var(--tw-bg-opacity, 1));font-size:.875rem;line-height:1.25rem;position:absolute;top:50%;inset-inline-end:0px;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.axp-compare-view .__table .__thead .__header-row .__object-header .__remove-object-button:hover{--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-100),var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-danger-600),var(--tw-text-opacity, 1))}.axp-compare-view .__table .__tbody .__row{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.axp-compare-view .__table .__tbody .__row.__row--odd{background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.axp-compare-view .__table .__tbody .__row.__row--has-differences{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{background-color:rgba(var(--ax-sys-color-warning-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values{border-left-width:4px;--tw-border-opacity: 1;border-left-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{background-color:rgba(var(--ax-sys-color-success-500),var(--tw-bg-opacity, 1));--tw-bg-opacity: .05}.axp-compare-view .__table .__tbody .__row .__field-cell{width:14rem;border-bottom-width:1px;border-right-width:1px;padding:.75rem 1rem;vertical-align:top;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));position:-webkit-sticky;position:sticky;left:0;z-index:15}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content{display:flex;flex-direction:column;gap:.25rem}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-title{font-weight:500}.axp-compare-view .__table .__tbody .__row .__field-cell .__field-content .__field-description{font-size:.75rem;line-height:1rem;opacity:.75}.axp-compare-view .__table .__tbody .__row .__object-cell{border-bottom-width:1px;padding:.75rem 1rem;text-align:center;vertical-align:middle;position:relative}.axp-compare-view .__table .__tbody .__row .__object-cell.__cell--changed .__object-content{border-width:1px;border-style:dashed;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-warning-200),var(--tw-border-opacity, 1));padding:.5rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-content{position:relative;display:flex;align-items:center;justify-content:center}.axp-compare-view .__table .__tbody .__row .__object-cell .__change-indicator{position:absolute;inset-inline-end:-.25rem;top:50%;--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));line-height:1rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-warning-500),var(--tw-text-opacity, 1));font-size:.875rem}.axp-compare-view .__table .__tbody .__row .__object-cell .__object-placeholder{opacity:.75}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-warning-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-differences .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-warning-900),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell{border-inline-start-width:4px;--tw-border-opacity: 1;border-inline-start-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-50),var(--tw-bg-opacity, 1))}.axp-compare-view .__table .__tbody .__row.__row--has-equal-values .__field-cell:is(.ax-dark *){--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-success-900),var(--tw-bg-opacity, 1))}\n"] }]
1476
+ args: [{ selector: 'axp-user-avatar', imports: [
1477
+ AXAvatarModule,
1478
+ AXDecoratorModule,
1479
+ AXImageModule,
1480
+ AXBadgeModule
1481
+ ], encapsulation: ViewEncapsulation.None, providers: [], template: "<ax-avatar #avatar [size]=\"size()\" class=\"ax-cursor-pointer\">\n @if(hasPicture()){\n <ax-image (onError)=\"onImageError($event)\" (onLoad)=\"onImageLoad($event)\" [src]=\"src()\"></ax-image>\n }@else{\n <ax-text class=\"ax-{{ avatarColor() }}-lightest \">\n <small class=\"ax-text-xs ax-font-semibold\">{{ avatarText() }}</small>\n </ax-text>\n }\n</ax-avatar>\n\n<!--\n\nax-primary-lightest\nax-warning-lightest\nax-success-lightest\nax-danger-lightest\nax-secondary-lightest\nax-accent1-lightest\nax-accent2-lightest\nax-accent3-lightest\n\n-->\n" }]
1224
1482
  }] });
1225
1483
 
1226
1484
  /**
1227
1485
  * Generated bundle index. Do not edit.
1228
1486
  */
1229
1487
 
1230
- export { AXPActivityLogComponent, AXPCompareViewComponent, AXPComponentSlot, AXPComponentSlotDirective, AXPComponentSlotModule, AXPComponentSlotRegistryService, AXPMenuBadgeHelper, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER };
1488
+ export { AXPActivityLogComponent, AXPCompareViewComponent, AXPComponentSlot, AXPComponentSlotDirective, AXPComponentSlotModule, AXPComponentSlotRegistryService, AXPLayoutFiltersComponent, AXPMenuBadgeHelper, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER };
1231
1489
  //# sourceMappingURL=acorex-platform-layout-components.mjs.map