@smartbit4all/ng-client 7.0.10 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, reflectComponentType, Injectable, inject, DOCUMENT, PLATFORM_ID, Optional, Inject, RendererStyleFlags2, input, computed, Component, HostListener, HostBinding, Directive, ViewContainerRef, ElementRef, Renderer2, ChangeDetectorRef, Input, output, signal, Injector, ViewChild, ViewChildren, effect, afterNextRender, NgZone, forwardRef, Pipe, ChangeDetectionStrategy, ViewEncapsulation, EnvironmentInjector, EventEmitter, Output, ApplicationRef, viewChild, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
2
+ import { InjectionToken, reflectComponentType, Injectable, inject, DOCUMENT, PLATFORM_ID, Optional, Inject, RendererStyleFlags2, input, computed, Component, HostListener, HostBinding, Directive, ViewContainerRef, ElementRef, Renderer2, ChangeDetectorRef, Input, output, signal, Injector, ViewChild, ViewChildren, effect, afterNextRender, NgZone, forwardRef, Pipe, ChangeDetectionStrategy, ViewEncapsulation, SkipSelf, NgModule, EnvironmentInjector, EventEmitter, Output, ApplicationRef, viewChild, makeEnvironmentProviders, importProvidersFrom } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpHeaders, HttpContext, HttpErrorResponse, HttpParams, provideHttpClient, withInterceptors, withInterceptorsFromDi } from '@angular/common/http';
5
5
  import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
@@ -10,6 +10,7 @@ import { enUS, hu } from 'date-fns/locale';
10
10
  import { isPlatformBrowser, NgClass, NgTemplateOutlet, NgStyle, AsyncPipe, KeyValuePipe, DatePipe, Location, NgIf, NgForOf } from '@angular/common';
11
11
  import { Subject, lastValueFrom, tap, takeUntil, throwError, from, interval, startWith, map, distinctUntilChanged, catchError as catchError$1 } from 'rxjs';
12
12
  import { catchError, switchMap, takeUntil as takeUntil$1 } from 'rxjs/operators';
13
+ import { deepEqual } from 'fast-equals';
13
14
  import { MatButton, MatIconButton, MatMiniFabButton } from '@angular/material/button';
14
15
  import { MatTooltip } from '@angular/material/tooltip';
15
16
  import { MatIconRegistry, MatIcon } from '@angular/material/icon';
@@ -22,7 +23,6 @@ import { Validators, UntypedFormGroup, UntypedFormControl, NG_VALUE_ACCESSOR, Fo
22
23
  import { ENTER, COMMA } from '@angular/cdk/keycodes';
23
24
  import { MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
24
25
  import { MatChipGrid, MatChipRow, MatChipRemove, MatChipInput, MatChip } from '@angular/material/chips';
25
- import { deepEqual } from 'fast-equals';
26
26
  import { set } from 'date-fns';
27
27
  import { Overlay, OverlayPositionBuilder, ScrollDispatcher } from '@angular/cdk/overlay';
28
28
  import { TemplatePortal } from '@angular/cdk/portal';
@@ -2724,6 +2724,18 @@ var MessageType;
2724
2724
  * Do not edit the class manually.
2725
2725
  */
2726
2726
 
2727
+ /**
2728
+ * View API
2729
+ * View API
2730
+ *
2731
+ * The version of the OpenAPI document: 1.0.0
2732
+ * Contact: info@it4all.hu
2733
+ *
2734
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
2735
+ * https://openapi-generator.tech
2736
+ * Do not edit the class manually.
2737
+ */
2738
+
2727
2739
  /**
2728
2740
  * View API
2729
2741
  * View API
@@ -2915,18 +2927,6 @@ var UiActionInputType;
2915
2927
  * Do not edit the class manually.
2916
2928
  */
2917
2929
 
2918
- /**
2919
- * View API
2920
- * View API
2921
- *
2922
- * The version of the OpenAPI document: 1.0.0
2923
- * Contact: info@it4all.hu
2924
- *
2925
- * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
2926
- * https://openapi-generator.tech
2927
- * Do not edit the class manually.
2928
- */
2929
-
2930
2930
  /**
2931
2931
  * View API
2932
2932
  * View API
@@ -3934,6 +3934,15 @@ class SmartViewContextService {
3934
3934
  this.openSmartLink = new Subject();
3935
3935
  this.isOpeningSmartLink = false;
3936
3936
  this.dialogRefs = [];
3937
+ this.modelSyncParticipants = new Map();
3938
+ /**
3939
+ * Each view's data as last synced with the backend, a copy. A view whose data is deep-equal
3940
+ * to its copy is left out of the next call; a view without a copy is always sent.
3941
+ */
3942
+ this.syncedModels = new Map();
3943
+ /** The seq of the envelope (or push) each copy came from, so a late completion cannot roll it back. */
3944
+ this.syncedSeq = new Map();
3945
+ this.modelSyncSeq = 0;
3937
3946
  this.embeddedContainers = new Map();
3938
3947
  this.embeddedViewRefs = [];
3939
3948
  this.pendingEmbeddedViews = [];
@@ -4034,33 +4043,138 @@ class SmartViewContextService {
4034
4043
  }
4035
4044
  this.embeddedViewRefs = this.embeddedViewRefs.filter((ref) => !orphaned.includes(ref));
4036
4045
  }
4037
- getCompositeModel(containerUuid) {
4038
- const result = {};
4039
- const children = this.embeddedViewRefs.filter((ref) => ref.containerUuid === containerUuid);
4040
- for (const child of children) {
4041
- result[child.uuid] = child.componentRef.instance.getModel();
4042
- Object.assign(result, this.getCompositeModel(child.uuid));
4043
- }
4044
- return result;
4045
- }
4046
- submitEmbeddedForms(containerUuid, validate) {
4046
+ /**
4047
+ * Validates the forms of the views embedded under the container, transitively, and collects
4048
+ * their invalid fields into one list for the container's snackbar.
4049
+ */
4050
+ validateEmbeddedForms(containerUuid) {
4047
4051
  const allInvalidKeys = [];
4048
4052
  const allInvalidNames = [];
4049
4053
  const children = this.embeddedViewRefs.filter((ref) => ref.containerUuid === containerUuid);
4050
4054
  for (const child of children) {
4051
4055
  const instance = child.componentRef.instance;
4052
- instance.submitForm(validate);
4053
- if (validate) {
4054
- const invalid = instance.getInvalidFields();
4055
- allInvalidKeys.push(...invalid.invalidFieldKeys);
4056
- allInvalidNames.push(...invalid.invalidFieldNames);
4057
- }
4058
- const nested = this.submitEmbeddedForms(child.uuid, validate);
4056
+ instance.submitForm(true);
4057
+ const invalid = instance.getInvalidFields();
4058
+ allInvalidKeys.push(...invalid.invalidFieldKeys);
4059
+ allInvalidNames.push(...invalid.invalidFieldNames);
4060
+ const nested = this.validateEmbeddedForms(child.uuid);
4059
4061
  allInvalidKeys.push(...nested.invalidFieldKeys);
4060
4062
  allInvalidNames.push(...nested.invalidFieldNames);
4061
4063
  }
4062
4064
  return { invalidFieldKeys: allInvalidKeys, invalidFieldNames: allInvalidNames };
4063
4065
  }
4066
+ // #region model sync
4067
+ joinModelSync(uuid, participant) {
4068
+ this.modelSyncParticipants.set(uuid, participant);
4069
+ }
4070
+ /**
4071
+ * Only the participant that is registered under the uuid leaves: a component destroyed after
4072
+ * its successor joined under the same uuid must not take the successor with it.
4073
+ */
4074
+ leaveModelSync(uuid, participant) {
4075
+ if (this.modelSyncParticipants.get(uuid) !== participant) {
4076
+ return;
4077
+ }
4078
+ this.modelSyncParticipants.delete(uuid);
4079
+ this.syncedModels.delete(uuid);
4080
+ this.syncedSeq.delete(uuid);
4081
+ }
4082
+ /**
4083
+ * Records what the backend's model just told the view as in sync. Without keys the view's
4084
+ * whole data is the backend's (initial load, a whole-model push) and becomes the copy. With
4085
+ * keys only those paths of the data were pushed: they are written into the copy, and whatever
4086
+ * else the view holds keeps its standing — an edit written into the data outside the form
4087
+ * while a call was in flight stays unsynced. A view without a copy has nothing to update.
4088
+ */
4089
+ markModelSynced(uuid, keys) {
4090
+ const participant = this.modelSyncParticipants.get(uuid);
4091
+ if (!participant) {
4092
+ return;
4093
+ }
4094
+ if (!keys) {
4095
+ this.syncedModels.set(uuid, this.cloneModel(uuid, participant.getModel()));
4096
+ }
4097
+ else {
4098
+ const copy = this.syncedModels.get(uuid);
4099
+ const model = participant.getModel();
4100
+ if (copy === undefined || copy === null || model === undefined || model === null) {
4101
+ return;
4102
+ }
4103
+ for (const key of keys) {
4104
+ setDeep(copy, key, this.cloneModel(uuid, getDeep(model, key)));
4105
+ }
4106
+ }
4107
+ this.syncedSeq.set(uuid, this.modelSyncSeq);
4108
+ }
4109
+ cloneModel(uuid, model) {
4110
+ try {
4111
+ return structuredClone(model);
4112
+ }
4113
+ catch (err) {
4114
+ const path = uncloneablePath(model);
4115
+ throw new Error(`Model sync: the data of view ${uuid} cannot be cloned` +
4116
+ (path ? ` (at ${path})` : '') +
4117
+ `: ${err.message}`);
4118
+ }
4119
+ }
4120
+ /**
4121
+ * The envelope of the next backend call: the data of every open view that differs from its
4122
+ * last synced copy. Forms are flushed into their data first, so an unsaved field value is
4123
+ * part of what is compared and sent. The envelope is always present, that is what tells the
4124
+ * backend it talks to a client that syncs; a view absent from it means "unchanged".
4125
+ *
4126
+ * The copies taken here become the synced copies when the call succeeds
4127
+ * ({@link completeModelSync}), not the data at response time: what the user types while the
4128
+ * call is in flight must count as unsynced.
4129
+ */
4130
+ beginModelSync() {
4131
+ const models = {};
4132
+ const snapshots = new Map();
4133
+ for (const [uuid, participant] of this.modelSyncParticipants) {
4134
+ participant.submitForm(false);
4135
+ const model = participant.getModel();
4136
+ if (model === undefined || model === null) {
4137
+ continue;
4138
+ }
4139
+ if (this.syncedModels.has(uuid) && deepEqual(model, this.syncedModels.get(uuid))) {
4140
+ continue;
4141
+ }
4142
+ const snapshot = this.cloneModel(uuid, model);
4143
+ models[uuid] = snapshot;
4144
+ snapshots.set(uuid, snapshot);
4145
+ }
4146
+ return { modelSync: { models }, snapshots, seq: ++this.modelSyncSeq };
4147
+ }
4148
+ /**
4149
+ * Calls run concurrently, so an envelope built earlier may complete later: its copies are
4150
+ * older than what a later envelope or push already settled, and are not written back.
4151
+ */
4152
+ completeModelSync(pending) {
4153
+ for (const [uuid, snapshot] of pending.snapshots) {
4154
+ if (!this.modelSyncParticipants.has(uuid)) {
4155
+ continue;
4156
+ }
4157
+ if ((this.syncedSeq.get(uuid) ?? -1) > pending.seq) {
4158
+ continue;
4159
+ }
4160
+ this.syncedModels.set(uuid, snapshot);
4161
+ this.syncedSeq.set(uuid, pending.seq);
4162
+ }
4163
+ }
4164
+ /**
4165
+ * Runs a backend call on a model sync carrier: a request that can bring the models (a
4166
+ * `UiActionRequest`, a `GridSelectionChange`). The envelope goes onto the carrier, the call
4167
+ * runs with it, and a successful call settles the copies the envelope was built from. What
4168
+ * happens to the response is the caller's business.
4169
+ */
4170
+ async withModelSync(carrier, call) {
4171
+ const pending = this.beginModelSync();
4172
+ carrier.modelSync = pending.modelSync;
4173
+ const viewContextChange = await call(carrier);
4174
+ this.completeModelSync(pending);
4175
+ return viewContextChange;
4176
+ }
4177
+ // #endregion
4064
4178
  unregisterEmbeddedSlot(containerUuid, containerId) {
4065
4179
  const innerMap = this.embeddedContainers.get(containerUuid);
4066
4180
  if (innerMap) {
@@ -4354,7 +4468,11 @@ class SmartViewContextService {
4354
4468
  .afterClosed()
4355
4469
  .pipe(takeUntil(this._destroy$))
4356
4470
  .subscribe(() => {
4357
- this.performAction(view.uuid, { code: DefaultUiActionCode_CLOSE, params: {} });
4471
+ // A close the backend ordered (closeView) has already left dialogRefs; only the
4472
+ // user's own close is an action the backend has yet to hear about.
4473
+ if (this.dialogRefs.some((ref) => ref.uuid === view.uuid)) {
4474
+ this.performAction(view.uuid, { code: DefaultUiActionCode_CLOSE, params: {} });
4475
+ }
4358
4476
  });
4359
4477
  }
4360
4478
  }
@@ -4423,9 +4541,9 @@ class SmartViewContextService {
4423
4541
  if (view.type === ViewType.DIALOG) {
4424
4542
  let dialogRef = this.dialogRefs.find((dialogRef) => dialogRef.uuid === view.uuid);
4425
4543
  if (dialogRef) {
4426
- dialogRef.dialogRef.close();
4427
4544
  let index = this.dialogRefs.indexOf(dialogRef);
4428
4545
  this.dialogRefs.splice(index, 1);
4546
+ dialogRef.dialogRef.close();
4429
4547
  }
4430
4548
  else {
4431
4549
  // console.log('DialogRef is not found by uuid.');
@@ -4800,47 +4918,28 @@ class SmartViewContextService {
4800
4918
  content,
4801
4919
  });
4802
4920
  }
4803
- async dataChanged(uuid, dataChange) {
4804
- return await this._dataChanged({ uuid, dataChange });
4805
- // const isCompleted = new Subject<void>();
4806
- // this.apiQueueService.addToQueue(
4807
- // {
4808
- // callback: this._dataChanged.bind(this),
4809
- // config: {
4810
- // uuid,
4811
- // dataChange,
4812
- // },
4813
- // isCompleted,
4814
- // },
4815
- // true
4816
- // );
4817
- // return await isCompleted.toPromise();
4818
- }
4819
4921
  async _performAction(config) {
4820
- return await this.handlePerformActionResponse(await this.view.performAction(config.uuid, config.uiActionRequest).toPromise());
4922
+ return await this.handlePerformActionResponse(await this.withModelSync(config.uiActionRequest, () => this.view.performAction(config.uuid, config.uiActionRequest).toPromise()));
4821
4923
  }
4822
4924
  async _performWidgetAction(config) {
4823
- return await this.handlePerformActionResponse(await this.view
4925
+ return await this.handlePerformActionResponse(await this.withModelSync(config.uiActionRequest, () => this.view
4824
4926
  .performWidgetAction(config.uuid, config.widgetId, config.nodeId, config.uiActionRequest)
4825
- .toPromise());
4927
+ .toPromise()));
4826
4928
  }
4827
4929
  async _performWidgetMainAction(config) {
4828
- return await this.handlePerformActionResponse(await this.view
4930
+ return await this.handlePerformActionResponse(await this.withModelSync(config.uiActionRequest, () => this.view
4829
4931
  .performWidgetMainAction(config.uuid, config.widgetId, config.uiActionRequest)
4830
- .toPromise());
4932
+ .toPromise()));
4831
4933
  }
4832
4934
  async _performUploadAction(config) {
4833
- return await this.handlePerformActionResponse(await this.view
4935
+ return await this.handlePerformActionResponse(await this.withModelSync(config.uiActionRequest, () => this.view
4834
4936
  .uploadAction(config.uuid, JSON.stringify(config.uiActionRequest), config.param, config.content)
4835
- .toPromise());
4937
+ .toPromise()));
4836
4938
  }
4837
4939
  async _performUploadMultipleAction(config) {
4838
- return await this.handlePerformActionResponse(await this.view
4940
+ return await this.handlePerformActionResponse(await this.withModelSync(config.uiActionRequest, () => this.view
4839
4941
  .uploadMultipleAction(config.uuid, JSON.stringify(config.uiActionRequest), config.param, config.content)
4840
- .toPromise());
4841
- }
4842
- async _dataChanged(config) {
4843
- return await this.handlePerformActionResponse(await this.view.dataChanged(config.uuid, config.dataChange).toPromise());
4942
+ .toPromise()));
4844
4943
  }
4845
4944
  async handlePerformActionResponse(viewContextChange) {
4846
4945
  this.viewContext = viewContextChange?.viewContext;
@@ -4880,6 +4979,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
4880
4979
  providedIn: 'root',
4881
4980
  }]
4882
4981
  }], ctorParameters: () => [] });
4982
+ /** Reads the value at a dotted path; a missing segment yields undefined. */
4983
+ function getDeep(model, key) {
4984
+ let value = model;
4985
+ for (const segment of key.split('.')) {
4986
+ if (value === undefined || value === null) {
4987
+ return undefined;
4988
+ }
4989
+ value = value[segment];
4990
+ }
4991
+ return value;
4992
+ }
4993
+ /** Writes the value at a dotted path, creating the objects on the way. */
4994
+ function setDeep(model, key, value) {
4995
+ const segments = key.split('.');
4996
+ let target = model;
4997
+ for (const segment of segments.slice(0, -1)) {
4998
+ if (target[segment] === undefined || target[segment] === null) {
4999
+ target[segment] = {};
5000
+ }
5001
+ target = target[segment];
5002
+ }
5003
+ target[segments[segments.length - 1]] = value;
5004
+ }
5005
+ /** The first path in the value that structuredClone refuses (a function, a DOM node), if any. */
5006
+ function uncloneablePath(value, path = '') {
5007
+ if (typeof value === 'function' || typeof value === 'symbol') {
5008
+ return path || '<root>';
5009
+ }
5010
+ if (typeof Node !== 'undefined' && value instanceof Node) {
5011
+ return path || '<root>';
5012
+ }
5013
+ if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
5014
+ for (const [k, v] of Object.entries(value)) {
5015
+ const found = uncloneablePath(v, path ? `${path}.${k}` : k);
5016
+ if (found) {
5017
+ return found;
5018
+ }
5019
+ }
5020
+ }
5021
+ return undefined;
5022
+ }
4883
5023
  const IS_ASYNC_PARAM_NAME = 'isAsync';
4884
5024
  class ApiQueueService {
4885
5025
  constructor() {
@@ -5132,6 +5272,10 @@ const UI_ACTION_CONFIRM_DIALOG_SERVICE = new InjectionToken('UI_ACTION_CONFIRM_D
5132
5272
  const UI_ACTION_INPUT_DIALOG_SERVICE = new InjectionToken('UI_ACTION_INPUT_DIALOG_SERVICE');
5133
5273
  const UI_ACTION_FILE_UPLOAD_DIALOG_SERVICE = new InjectionToken('UI_ACTION_FILE_UPLOAD_DIALOG_SERVICE');
5134
5274
 
5275
+ /** A view's own client, as opposed to an executor standing in for another API. */
5276
+ function isViewClient(executor) {
5277
+ return typeof executor.uuid === 'string';
5278
+ }
5135
5279
  class UiActionService {
5136
5280
  constructor() {
5137
5281
  this.confirmDialogService = inject(UI_ACTION_CONFIRM_DIALOG_SERVICE);
@@ -5167,14 +5311,14 @@ class UiActionService {
5167
5311
  identifier: uiAction.identifier,
5168
5312
  params: uiAction.params ?? {},
5169
5313
  };
5170
- if (uiAction.submit || uiAction.model) {
5171
- // submit: with validation, model: without validation. both can be undefined
5172
- const validate = uiAction.submit || !uiAction.model;
5173
- executor.submitForm(validate);
5314
+ // submit: validate before sending, the embedded views' forms included. The model itself
5315
+ // travels by model sync whatever the flags say; the deprecated `model` flag only keeps
5316
+ // flushing the form of an executor that is not a view.
5317
+ if (uiAction.submit) {
5318
+ executor.submitForm(true);
5174
5319
  let invalidFields = executor.getInvalidFields();
5175
- const containerUuid = executor.uuid;
5176
- if (uiAction.composite && containerUuid) {
5177
- const embeddedInvalid = this.viewContext.submitEmbeddedForms(containerUuid, validate);
5320
+ if (isViewClient(executor)) {
5321
+ const embeddedInvalid = this.viewContext.validateEmbeddedForms(executor.uuid);
5178
5322
  invalidFields = {
5179
5323
  invalidFieldKeys: [...invalidFields.invalidFieldKeys, ...embeddedInvalid.invalidFieldKeys],
5180
5324
  invalidFieldNames: [
@@ -5183,11 +5327,14 @@ class UiActionService {
5183
5327
  ],
5184
5328
  };
5185
5329
  }
5186
- if (validate && invalidFields.invalidFieldKeys.length) {
5330
+ if (invalidFields.invalidFieldKeys.length) {
5187
5331
  this.showInvalidFieldsSnackbar(invalidFields);
5188
5332
  return;
5189
5333
  }
5190
5334
  }
5335
+ else if (uiAction.model && !isViewClient(executor)) {
5336
+ executor.submitForm(false);
5337
+ }
5191
5338
  if (uiAction.confirm) {
5192
5339
  this.confirmDialogService.action = uiAction;
5193
5340
  this.confirmDialogService.openDialog();
@@ -5292,26 +5439,10 @@ class UiActionService {
5292
5439
  return uiActionRequest;
5293
5440
  }
5294
5441
  async performAction(uiAction, uiActionRequest, uiActionModel, executor, options) {
5295
- if (!uiActionRequest.params ||
5296
- (uiActionRequest.params && !Object.keys(uiActionRequest.params).length)) {
5297
- uiActionRequest.params = {
5298
- model: executor.getModel(),
5299
- };
5300
- }
5301
- else if (uiAction.submit || uiAction.model) {
5302
- if (options?.widgetId && options?.nodeId) {
5303
- uiActionRequest.params['clientPageModel'] = { data: executor.getModel() };
5304
- }
5305
- else {
5306
- uiActionRequest.params['model'] = executor.getModel();
5307
- }
5308
- }
5309
- if (uiAction.composite) {
5310
- const containerUuid = executor.uuid;
5311
- if (containerUuid) {
5312
- uiActionRequest.params['compositeModel'] =
5313
- this.viewContext.getCompositeModel(containerUuid);
5314
- }
5442
+ // A view's model goes by model sync (SmartViewContextService). An executor that is not a
5443
+ // view (tree, filter editor) has no view to sync, so its model still rides on the request.
5444
+ if (!isViewClient(executor) && (uiAction.submit || uiAction.model)) {
5445
+ uiActionRequest.params['model'] = executor.getModel();
5315
5446
  }
5316
5447
  try {
5317
5448
  await executor.performUiActionRequest(uiActionRequest, options?.widgetId, options?.nodeId);
@@ -6417,6 +6548,14 @@ class SmartFormService {
6417
6548
  this.revision = this.revisionState.asReadonly();
6418
6549
  this.emptyKey = 'e#m%p@t*y';
6419
6550
  this.group = {};
6551
+ /**
6552
+ * The model value each control last agreed with, by control key: what the control was built
6553
+ * or refreshed from, or what it last wrote into the data. A control whose value still equals
6554
+ * it holds no edit of the user's, and a data value that no longer equals it was changed by
6555
+ * the backend. The form's own dirty flag is not this: it lives until the form is rebuilt and
6556
+ * says nothing about what the data holds.
6557
+ */
6558
+ this.exchanged = new Map();
6420
6559
  this.regexRegexChars = new RegExp(/[\.\-\[\]\/\{\}\(\)\+\^\$\\\|]/g);
6421
6560
  this.regexAsteriskInTheMiddle = new RegExp(/([^\*])\*([^\*])/g);
6422
6561
  this.regexAsteriskInTheEnd = new RegExp(/([^\*])\*$/g);
@@ -6431,6 +6570,10 @@ class SmartFormService {
6431
6570
  widgetsChanged() {
6432
6571
  this.revisionState.update((revision) => revision + 1);
6433
6572
  }
6573
+ /** Forgets the agreed values; the form is being rebuilt from the model. */
6574
+ resetExchangedValues() {
6575
+ this.exchanged.clear();
6576
+ }
6434
6577
  getSmartFormWidgetByKey(key) {
6435
6578
  return this.findSmartFormWidgetByKey(this.smartForm?.widgets, key);
6436
6579
  }
@@ -6555,6 +6698,12 @@ class SmartFormService {
6555
6698
  widget = this.findSmartFormWidgetByKey(widgets, key);
6556
6699
  if (widget) {
6557
6700
  let value = this.getValueDeeply(data, key);
6701
+ // A data value the control already agreed with was not pushed: the control keeps
6702
+ // what it shows, which may be the user's edit.
6703
+ if (this.exchanged.has(key) && deepEqual(value, this.exchanged.get(key))) {
6704
+ continue;
6705
+ }
6706
+ this.exchanged.set(key, structuredClone(value));
6558
6707
  if (widget.type === SmartFormWidgetType.CHECK_BOX && typeof value !== 'boolean') {
6559
6708
  value = value === 'true';
6560
6709
  }
@@ -6574,6 +6723,8 @@ class SmartFormService {
6574
6723
  if (widget.showLabel === undefined && smartForm.showLabel) {
6575
6724
  widget.showLabel = true;
6576
6725
  }
6726
+ // The backend changed this field: its value reaches the control even over an edit.
6727
+ this.group[key]?.setValue(value ?? '', { emitEvent: false });
6577
6728
  }
6578
6729
  this.copyFromValueSetToValuesList(widget, smartForm.componentModel.valueSets);
6579
6730
  }
@@ -6733,7 +6884,7 @@ class SmartFormService {
6733
6884
  formControl = new UntypedFormControl();
6734
6885
  this.group[key] = formControl;
6735
6886
  }
6736
- formControl.setValue(value || '', { emitEvent: false });
6887
+ formControl.setValue(value ?? '', { emitEvent: false });
6737
6888
  formControl.clearValidators();
6738
6889
  validators?.map((validator) => {
6739
6890
  formControl.addValidators(validator.validator);
@@ -6799,15 +6950,29 @@ class SmartFormService {
6799
6950
  }
6800
6951
  });
6801
6952
  }
6953
+ /**
6954
+ * Copies the user's edits from the controls into the data: only a control whose value differs
6955
+ * from what it last agreed with writes, typed as the data holds the field. Nothing is
6956
+ * submitted; a control the user never touched leaves its field as the backend sent it.
6957
+ */
6802
6958
  toSmartForm(group) {
6803
6959
  if (this.smartForm) {
6804
6960
  this.copyValueFromFormToWidgetBeans(this.smartForm.widgets, group);
6805
6961
  const data = this.smartForm.componentModel?.data;
6806
6962
  if (data) {
6807
6963
  for (const key of this.getPropertyNamesDeeply(data)) {
6808
- if (group.controls[key]) {
6809
- this.setValueDeeply(data, key, group.controls[key].value);
6964
+ if (!group.controls[key]) {
6965
+ continue;
6966
+ }
6967
+ const agreed = this.exchanged.has(key)
6968
+ ? this.exchanged.get(key)
6969
+ : this.getValueDeeply(data, key);
6970
+ const value = coerceToTypeOf(agreed, group.controls[key].value);
6971
+ if (this.exchanged.has(key) && deepEqual(value, agreed)) {
6972
+ continue;
6810
6973
  }
6974
+ this.setValueDeeply(data, key, value);
6975
+ this.exchanged.set(key, structuredClone(this.getValueDeeply(data, key)));
6811
6976
  }
6812
6977
  }
6813
6978
  }
@@ -6819,12 +6984,14 @@ class SmartFormService {
6819
6984
  }
6820
6985
  let originalModel = this.smartForm.componentModel.data;
6821
6986
  let copyOfModel = { ...originalModel };
6987
+ const exchangedBefore = new Map(this.exchanged);
6822
6988
  // copyOfModel should be the current model
6823
6989
  this.smartForm.componentModel.data = copyOfModel;
6824
6990
  // copy value from FormGroup into model
6825
6991
  this.toSmartForm(group);
6826
6992
  let newModel = this.smartForm.componentModel.data;
6827
6993
  this.smartForm.componentModel.data = originalModel;
6994
+ this.exchanged = exchangedBefore;
6828
6995
  return newModel;
6829
6996
  }
6830
6997
  applyComponentConstraints(widgets, constraints) {
@@ -7001,6 +7168,32 @@ function extractTime(widgetInstance) {
7001
7168
  }
7002
7169
  return time;
7003
7170
  }
7171
+ /**
7172
+ * A control's value in the type its field has in the data. The controls of a boolean or a
7173
+ * number shown as text hold strings; the data keeps the field's type across a round trip.
7174
+ */
7175
+ function coerceToTypeOf(reference, value) {
7176
+ if (typeof reference === 'boolean') {
7177
+ if (value === 'true') {
7178
+ return true;
7179
+ }
7180
+ if (value === 'false') {
7181
+ return false;
7182
+ }
7183
+ if (value === '') {
7184
+ return null;
7185
+ }
7186
+ }
7187
+ else if (typeof reference === 'number') {
7188
+ if (value === '') {
7189
+ return null;
7190
+ }
7191
+ if (typeof value === 'string' && value.trim() !== '' && !isNaN(Number(value))) {
7192
+ return Number(value);
7193
+ }
7194
+ }
7195
+ return value;
7196
+ }
7004
7197
 
7005
7198
  /*
7006
7199
  * Public API Surface of component-factory-service
@@ -10760,6 +10953,7 @@ class SmartformComponent {
10760
10953
  if (!this.originalWidgets || this.originalWidgets.length === 0) {
10761
10954
  this.originalWidgets = this.smartForm.widgets;
10762
10955
  }
10956
+ this.service.resetExchangedValues();
10763
10957
  this.service.setValuesFromModel(this.originalWidgets);
10764
10958
  this.service.applyConstraints(this.originalWidgets);
10765
10959
  this.smartForm.widgets = this.service.filterWidgetsByVisibility(this.originalWidgets);
@@ -11262,7 +11456,18 @@ class Table {
11262
11456
  this.ACTION_SEPERATOR = '_actionSeparator_';
11263
11457
  // ---- Toolbar ----
11264
11458
  this.defaultActionToolbarId = SmartGridToolbarActionsUtil.defaultActionToolbarId;
11459
+ /**
11460
+ * The row menu model by row id, so that the toolbar binding sees the same array on every
11461
+ * change detection pass and does not rebuild an open menu. Cleared whenever the rows are
11462
+ * rendered anew: a row keeps its id across reloads, but not necessarily its actions.
11463
+ */
11265
11464
  this.rowMenuActionModelArrayCache = new Map();
11465
+ // ------------- TREE_GRID -------------
11466
+ this.expandedRowIds = new Set();
11467
+ this.visibleRows = [];
11468
+ this.rowsById = new Map();
11469
+ this.isTreeGrid = false;
11470
+ this.treeInitialized = false;
11266
11471
  }
11267
11472
  /** The address of the toolbar in this grid's header; `undefined` while it has no id. */
11268
11473
  get headerToolbarId() {
@@ -11295,6 +11500,7 @@ class Table {
11295
11500
  if (this.smartTable.sortable)
11296
11501
  this.sortEvent = new Subject();
11297
11502
  this.createCellToActionMap();
11503
+ this.calcTree();
11298
11504
  }
11299
11505
  ngOnDestroy() {
11300
11506
  this._destroy$.next();
@@ -11324,11 +11530,13 @@ class Table {
11324
11530
  this.smartTable = smartTable;
11325
11531
  // Pushed in by the grid rather than read from it, so nothing else marks this view. The
11326
11532
  // pull the rest of the library moved to (ADR-0005) is the 7.1 grid/table merge.
11533
+ this.calcTree();
11327
11534
  this.changeDetector.markForCheck();
11328
11535
  this.renderRows();
11329
11536
  }
11330
11537
  renderRows() {
11331
11538
  this.createCellToActionMap();
11539
+ this.rowMenuActionModelArrayCache.clear();
11332
11540
  this.myTableChild.renderRows();
11333
11541
  }
11334
11542
  createCellToActionMap() {
@@ -11814,6 +12022,143 @@ class Table {
11814
12022
  shouldShowMenuButton(row) {
11815
12023
  return SmartGridToolbarActionsUtil.showMenu(row, this.smartTable.tableHeaders);
11816
12024
  }
12025
+ initializeExpandedRows(rows) {
12026
+ if (this.treeInitialized) {
12027
+ return;
12028
+ }
12029
+ rows.forEach(row => {
12030
+ if (row.id && row.children?.length) {
12031
+ this.expandedRowIds.add(row.id);
12032
+ }
12033
+ });
12034
+ this.treeInitialized = true;
12035
+ }
12036
+ calcTree() {
12037
+ const rows = this.smartTable.tableRows ?? [];
12038
+ this.isTreeGrid = rows.some(row => !!row?.children?.length || !!row?.parent);
12039
+ if (!this.isTreeGrid) {
12040
+ this.visibleRows = rows;
12041
+ return;
12042
+ }
12043
+ // Open all rows on first tree initialization.
12044
+ this.initializeExpandedRows(rows);
12045
+ this.rowsById.clear();
12046
+ rows.forEach(row => {
12047
+ if (row.id) {
12048
+ this.rowsById.set(row.id, row);
12049
+ }
12050
+ });
12051
+ const roots = rows.filter(row => !row.parent);
12052
+ const result = [];
12053
+ const walk = (row) => {
12054
+ result.push(row);
12055
+ if (row.id &&
12056
+ row.children?.length &&
12057
+ this.expandedRowIds.has(row.id)) {
12058
+ row.children
12059
+ .map(childId => this.rowsById.get(childId))
12060
+ .filter((child) => !!child)
12061
+ .forEach(child => walk(child));
12062
+ }
12063
+ };
12064
+ roots.forEach(root => walk(root));
12065
+ this.visibleRows = result;
12066
+ }
12067
+ hasChildren(row) {
12068
+ return !!row?.children?.length;
12069
+ }
12070
+ isRowExpanded(row) {
12071
+ return !!row?.id && this.expandedRowIds.has(row.id);
12072
+ }
12073
+ toggleRowExpansion(row, event) {
12074
+ event?.stopPropagation();
12075
+ if (!row?.id) {
12076
+ return;
12077
+ }
12078
+ if (this.expandedRowIds.has(row.id)) {
12079
+ this.expandedRowIds.delete(row.id);
12080
+ }
12081
+ else {
12082
+ this.expandedRowIds.add(row.id);
12083
+ }
12084
+ this.calcTree();
12085
+ }
12086
+ canExpand() {
12087
+ return this.visibleRows.some(row => this.hasChildren(row) && !this.isRowExpanded(row));
12088
+ }
12089
+ canCollapse() {
12090
+ return this.expandedRowIds.size > 0;
12091
+ }
12092
+ expandOneLevel() {
12093
+ let changed = false;
12094
+ for (const row of this.visibleRows) {
12095
+ if (row.id && this.hasChildren(row) && !this.expandedRowIds.has(row.id)) {
12096
+ this.expandedRowIds.add(row.id);
12097
+ changed = true;
12098
+ }
12099
+ }
12100
+ if (changed) {
12101
+ this.calcTree();
12102
+ }
12103
+ }
12104
+ collapseOneLevel() {
12105
+ let maxLevel = -1;
12106
+ for (const row of this.visibleRows) {
12107
+ if (row.id && this.expandedRowIds.has(row.id)) {
12108
+ maxLevel = Math.max(maxLevel, row.level ?? 0);
12109
+ }
12110
+ }
12111
+ if (maxLevel < 0) {
12112
+ return;
12113
+ }
12114
+ let changed = false;
12115
+ for (const row of this.visibleRows) {
12116
+ if (row.id && this.expandedRowIds.has(row.id) && (row.level ?? 0) === maxLevel) {
12117
+ this.expandedRowIds.delete(row.id);
12118
+ changed = true;
12119
+ }
12120
+ }
12121
+ if (changed) {
12122
+ this.calcTree();
12123
+ }
12124
+ }
12125
+ expandAll() {
12126
+ let changed = false;
12127
+ (this.smartTable.tableRows ?? []).forEach(row => {
12128
+ if (row.id && this.hasChildren(row) && !this.expandedRowIds.has(row.id)) {
12129
+ this.expandedRowIds.add(row.id);
12130
+ changed = true;
12131
+ }
12132
+ });
12133
+ if (changed) {
12134
+ this.calcTree();
12135
+ }
12136
+ }
12137
+ collapseAll() {
12138
+ if (this.expandedRowIds.size === 0) {
12139
+ return;
12140
+ }
12141
+ this.expandedRowIds.clear();
12142
+ this.calcTree();
12143
+ }
12144
+ get expandTreeGridLevel() {
12145
+ return {
12146
+ title: '',
12147
+ color: 'primary',
12148
+ type: UiActionButtonType.MINI_FAB,
12149
+ icon: 'add',
12150
+ iconPosition: IconPosition.PRE,
12151
+ };
12152
+ }
12153
+ get closeTreeGridLevel() {
12154
+ return {
12155
+ title: '',
12156
+ color: 'primary',
12157
+ type: UiActionButtonType.MINI_FAB,
12158
+ icon: 'remove',
12159
+ iconPosition: IconPosition.PRE,
12160
+ };
12161
+ }
11817
12162
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: Table, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11818
12163
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.8", type: Table, isStandalone: true, selector: "ng-component", inputs: { smartTable: "smartTable" }, viewQueries: [{ propertyName: "myTableChild", first: true, predicate: ["myTable"], descendants: true }, { propertyName: "vcRef", predicate: ["expandedArea"], descendants: true, read: ViewContainerRef }, { propertyName: "defaultActionMenuComponents", predicate: DefaultActionsPopupComponent, descendants: true }, { propertyName: "triggers", predicate: MatMenuTrigger, descendants: true }], ngImport: i0, template: '', isInline: true }); }
11819
12164
  }
@@ -11874,11 +12219,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
11874
12219
 
11875
12220
  class MaterialTableComponent extends Table {
11876
12221
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MaterialTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
11877
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: MaterialTableComponent, isStandalone: true, selector: "lib-material-table", usesInheritance: true, ngImport: i0, template: "<table\n #myTable\n mat-table\n [dataSource]=\"smartTable.tableRows\"\n class=\"full-width\"\n multiTemplateDataRows\n >\n <!-- Column Descriptor -->\n @if (smartTable.title) {\n <caption class=\"captionTitle\">\n {{ smartTable.title }}\n </caption>\n }\n @for (header of smartTable.tableHeaders; track header; let i = $index) {\n <ng-container\n matColumnDef=\"{{ header }}\"\n >\n <!-- my_menu is the implicit action column present on all tables: -->\n @if ('my_menu' === header) {\n <th\n mat-header-cell\n *matHeaderCellDef\n [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\"\n >\n <smart-ui-action-toolbar [id]=\"headerToolbarId\"></smart-ui-action-toolbar>\n </th>\n } @else {\n <th\n mat-header-cell\n *matHeaderCellDef\n [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\"\n >\n @if (\n header === 'icon' || header === 'img' || header === 'options' || header === 'button'\n ) {\n <div\n ></div>\n }\n @if (header === 'select') {\n <div>\n @if (smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"smartTable.selection!.hasValue() && isAllSelected()\"\n [indeterminate]=\"smartTable.selection!.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n >\n </mat-checkbox>\n }\n @if (!smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <div>\n {{ smartTable.customTableHeaders[i] }}\n </div>\n }\n </div>\n }\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'options' &&\n header !== 'button' &&\n header !== 'select' &&\n header !== 'expand' &&\n header !== 'actions'\n ) {\n <div\n >\n @if (smartTable.sortable) {\n @if (smartTable.sortable && isSortable(smartTable.customSmartTableHeaders![i])) {\n <button\n (click)=\"sortButtonClicked($event, smartTable.customSmartTableHeaders![i])\"\n mat-button\n class=\"sortableHeaderButton\"\n >\n {{ smartTable.customTableHeaders[i] }}\n @if (getSortIcon(header)) {\n <smart-icon\n class=\"sortableHeaderButtonIcon\"\n title=\"sort\"\n [icon]=\"getSortIcon(header)!\"\n ></smart-icon>\n }\n @if (hasSortNumIcon(header)) {\n <smart-icon\n class=\"sortableHeaderButtonIcon\"\n title=\"sort\"\n [icon]=\"getSortNumIcon(header)\"\n ></smart-icon>\n }\n </button>\n }\n } @else {\n {{ smartTable.customTableHeaders[i] }}\n }\n </div>\n }\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" [ngClass]=\"isDisabled(element) ? 'disabledRow' : ''\">\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'select' &&\n !isDisabled(element)\n ) {\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"\n $event\n ? setSelection(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n : null\n \"\n [disabled]=\"isDisabled(element)\"\n [checked]=\"\n smartTable.selection!.isSelected(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \"\n [aria-label]=\"\n checkboxLabel(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \"\n >\n </mat-checkbox>\n }\n @if (\n smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].properties\n ) {\n <div\n >\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATETIME) {\n <div>\n {{\n getValue(element, header)\n | smartDateTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATE) {\n <div>\n {{\n getValue(element, header)\n | smartDate: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().TIME) {\n <div>\n {{\n getValue(element, header)\n | smartTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().CHECKBOX) {\n <div>\n <mat-checkbox [disabled]=\"true\" [checked]=\"getValue(element, header)\"></mat-checkbox>\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders[i].properties?.type === type().ICON &&\n smartTable.customSmartTableHeaders[i].properties?.icons?.length\n ) {\n <div\n >\n <smart-icon\n [smartTooltip]=\"getToolTip(element, i)\"\n [icon]=\"getIcon(getValue(element, header), i)!\"\n [color]=\"getColor(getValue(element, header), i)\"\n >\n </smart-icon>\n </div>\n }\n </div>\n }\n <div class=\"smart-table-icon-container\">\n @for (ir of getImageResourceIcons(element, header); track ir) {\n <div>\n <smart-icon [imageResource]=\"ir\"> </smart-icon>\n </div>\n }\n </div>\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].buttons) {\n <div\n class=\"smart-table-buttons-col\"\n >\n @for (button of smartTable.customSmartTableHeaders[i].buttons; track button) {\n <div>\n @if (showButton(button, element)) {\n <div>\n @switch (button.type) {\n @case (smartTableButtonType.ICON) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-icon-button\n color=\"{{ button.color }}\"\n >\n <smart-icon title=\"{{ button.label }}\" [icon]=\"button.icon!\"></smart-icon>\n </button>\n }\n @case (smartTableButtonType.NORMAL) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-button\n color=\"{{ button.color }}\"\n >\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n @case (smartTableButtonType.RAISED) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-raised-button\n color=\"{{ button.color }}\"\n >\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n <!------ MENU ------>\n @case (smartTableButtonType.MENU) {\n <div class=\"menu-button\">\n <!------ DEFAULT_ACTION_COLUMN ID TOOLBAR ------>\n <smart-ui-action-toolbar\n [uiActionModels]=\"getRowColumnAction(element, defaultActionToolbarId)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n <!------ GENERIC HAMBURGER ------>\n <!------ TOOLBAR ------>\n @if (shouldShowMenuButton(element)) {\n <smart-ui-action-toolbar\n [uiActionModels]=\"getMenuActions(element)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n }\n </div>\n }\n <!------ MENU ------>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].icon) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].icon?.icon) {\n <smart-icon\n [ngClass]=\"smartTable.customSmartTableHeaders[i].icon?.cssClass ?? ''\"\n [color]=\"$safeNavigationMigration(smartTable.customSmartTableHeaders[i].icon?.color)\"\n [icon]=\"smartTable.customSmartTableHeaders[i].icon!.icon\"\n >\n </smart-icon>\n }\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].translator !== undefined\n ) {\n <div\n >\n {{ smartTable.customSmartTableHeaders[i].translator!(getValue(element, header)) }}\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'expand'\n ) {\n <button\n mat-icon-button\n aria-label=\"expand row\"\n (click)=\"onToggle(element, $event)\"\n >\n @if (expandedElement !== element) {\n <smart-icon [icon]=\"'keyboard_arrow_down'\"></smart-icon>\n }\n @if (expandedElement === element) {\n <smart-icon [icon]=\"'keyboard_arrow_up'\"></smart-icon>\n }\n </button>\n }\n @if (\n !smartTable.customSmartTableHeaders ||\n (smartTable.customSmartTableHeaders &&\n !smartTable.customSmartTableHeaders[i].properties &&\n !smartTable.customSmartTableHeaders[i].icon &&\n !smartTable.customSmartTableHeaders[i].buttons &&\n !smartTable.customSmartTableHeaders[i].translator &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'select') &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'expand'))\n ) {\n <div\n >\n @if (header === 'icon') {\n <smart-icon [icon]=\"getValue(element, header)!\"> </smart-icon>\n }\n @if (header === 'img') {\n <img\n [src]=\"getValue(element, header)\"\n alt=\"\"\n class=\"smarttableImg\"\n />\n }\n <!------ TOOLBAR ------>\n @if (showCellToolbar(element, header)) {\n <smart-ui-action-toolbar\n [uiActionModels]=\"getRowColumnAction(element, header)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n }\n <!------ TOOLBAR ------>\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'option' &&\n header !== 'button' &&\n !isImageResource(element, header)\n ) {\n <div\n [innerHtml]=\"getValue(element, header)\"\n ></div>\n }\n </div>\n }\n </td>\n </ng-container>\n }\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n @if (smartTable.expandable) {\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"smartTable.tableHeaders.length\">\n <div class=\"smart-table-detail\" animate.enter=\"smart-table-detail-enter\">\n <div class=\"smart-table-detail-content\">\n <ng-template #expandedArea></ng-template>\n </div>\n </div>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"smartTable.tableHeaders; sticky: true\"></tr>\n <ng-container *matRowDef=\"let element; columns: smartTable.tableHeaders\">\n <tr\n mat-row\n class=\"smart-table-row\"\n [class.smart-table-row-expanded]=\"expandedElement === element\"\n [ngClass]=\"getRowClasses(element)\"\n [ngStyle]=\"getRowStyles(element)\"\n (click)=\"handleOnRowClick(element)\"\n (dblclick)=\"handleOnRowDoubleClick($event, element)\"\n [attr.data-testid]=\"element?.id ?? null\"\n ></tr>\n @if (smartTable.defaultActionCodes && smartTable.defaultActionCodes.length > 0) {\n <lib-default-actions-popup\n #defaultActionMenu\n [buttons]=\"getDefaultActionsForRow(element)!\"\n [row]=\"element\"\n ></lib-default-actions-popup>\n }\n </ng-container>\n <!-- Only the expanded row has a detail row; no host style can give a collapsed one a height. -->\n @if (smartTable.expandable) {\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['expandedDetail']; when: isExpandedRow\"\n class=\"smart-table-detail-row\"\n (animate.leave)=\"onDetailRowLeave($event)\"\n ></tr>\n }\n</table>\n", styles: [".full-width{width:100%}.smarttableImg{width:25px}.smartTableRowHover:hover{cursor:pointer}tr.smart-table-row:not(.smart-table-row-expanded):hover{background:#f5f5f5}tr.smart-table-row:not(.smart-table-row-expanded):active{background:#efefef}tr.smart-table-row-expanded td{border-bottom-width:0}tr.smart-table-detail-row{height:0}.smart-table-detail{display:grid;grid-template-rows:1fr}.smart-table-detail-enter{animation:smart-table-detail-expand 225ms cubic-bezier(.4,0,.2,1)}.smart-table-detail-content{min-height:0;overflow:hidden}@keyframes smart-table-detail-expand{0%{grid-template-rows:0fr}to{grid-template-rows:1fr}}.disabledRow{color:var(--disabled)}.disabledRow:hover{cursor:default}.smart-table-buttons-col{display:flex;flex-direction:row;justify-content:flex-end}.sortableHeaderButton{margin:0!important;padding:0!important;text-align:left!important}.selected{background-color:var(--primary-light-color)}.smart-table-icon-container{display:flex;flex-direction:row;justify-content:space-between;white-space:initial}.reversed{flex-direction:row-reverse;gap:1rem}:host ::ng-deep .mat-mdc-menu-item{line-height:normal!important}.mat-mdc-menu-item[disabled]{cursor:default!important}.menu-button{display:flex;flex-direction:row;justify-content:flex-end;text-align:-webkit-right;align-items:center}.captionTitle{font-size:1.5rem;align-content:center;padding:.5rem .75rem;text-align:start;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);background:#f5f5f5}\n"], dependencies: [{ kind: "component", type: MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: DefaultActionsPopupComponent, selector: "lib-default-actions-popup", inputs: ["buttons", "row", "colIdx"] }, { kind: "pipe", type: SmartDateTimePipe, name: "smartDateTime" }, { kind: "pipe", type: SmartDatePipe, name: "smartDate" }, { kind: "pipe", type: SmartTimePipe, name: "smartTime" }] }); }
12222
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: MaterialTableComponent, isStandalone: true, selector: "lib-material-table", usesInheritance: true, ngImport: i0, template: "<table #myTable mat-table [dataSource]=\"isTreeGrid ? visibleRows : smartTable.tableRows\" class=\"full-width\"\n multiTemplateDataRows>\n <!-- Column Descriptor -->\n @if (smartTable.title) {\n <caption class=\"captionTitle\">\n {{ smartTable.title }}\n </caption>\n }\n\n @for (header of smartTable.tableHeaders; track header; let i = $index) {\n\n <ng-container matColumnDef=\"{{ header }}\">\n <!-- my_menu is the implicit action column present on all tables: -->\n @if ('my_menu' === header) {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\">\n\n <!-- ==================== TREE ACTIONS ==================== -->\n @if ( isTreeGrid) {\n <div class=\"tree-grid-actions\">\n\n <ui-action-button (actionClick)=\"expandOneLevel()\" [descriptor]=\"expandTreeGridLevel\">\n </ui-action-button>\n\n\n <ui-action-button (actionClick)=\"collapseOneLevel()\" [descriptor]=\"closeTreeGridLevel\">\n </ui-action-button>\n </div>\n }\n <!-- ==================== TREE ACTIONS ==================== -->\n\n <smart-ui-action-toolbar [id]=\"headerToolbarId\"></smart-ui-action-toolbar>\n </th>\n } @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\">\n @if (\n header === 'icon' || header === 'img' || header === 'options' || header === 'button'\n ) {\n <div></div>\n }\n @if (header === 'select') {\n <div>\n @if (smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <mat-checkbox (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"smartTable.selection!.hasValue() && isAllSelected()\"\n [indeterminate]=\"smartTable.selection!.hasValue() && !isAllSelected()\" [aria-label]=\"checkboxLabel()\">\n </mat-checkbox>\n }\n @if (!smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <div>\n {{ smartTable.customTableHeaders[i] }}\n </div>\n }\n </div>\n }\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'options' &&\n header !== 'button' &&\n header !== 'select' &&\n header !== 'expand' &&\n header !== 'actions'\n ) {\n <div>\n @if (smartTable.sortable) {\n @if (smartTable.sortable && isSortable(smartTable.customSmartTableHeaders![i])) {\n <button (click)=\"sortButtonClicked($event, smartTable.customSmartTableHeaders![i])\" mat-button\n class=\"sortableHeaderButton\">\n {{ smartTable.customTableHeaders[i] }}\n @if (getSortIcon(header)) {\n <smart-icon class=\"sortableHeaderButtonIcon\" title=\"sort\" [icon]=\"getSortIcon(header)!\"></smart-icon>\n }\n @if (hasSortNumIcon(header)) {\n <smart-icon class=\"sortableHeaderButtonIcon\" title=\"sort\" [icon]=\"getSortNumIcon(header)\"></smart-icon>\n }\n </button>\n }\n } @else {\n {{ smartTable.customTableHeaders[i] }}\n }\n </div>\n }\n </th>\n }\n\n <td mat-cell *matCellDef=\"let element\" [ngClass]=\"isDisabled(element) ? 'disabledRow' : ''\">\n <div class=\"mat-cell-content\">\n\n\n <!-- ==================== TREE TOGGLE ==================== -->\n @if (isTreeGrid && i === 0) {\n <div class=\"tree-grid-first-column\" [style.padding-left.px]=\"(element.level ?? 0) * 24\">\n @if (hasChildren(element)) {\n <button mat-icon-button type=\"button\" (click)=\"toggleRowExpansion(element, $event)\">\n <smart-icon [icon]=\"\n isRowExpanded(element)\n ? 'keyboard_arrow_down'\n : 'keyboard_arrow_right'\n \"></smart-icon>\n </button>\n } @else {\n <span class=\"tree-grid-spacer\"></span>\n }\n\n </div>\n }\n <!-- ==================== TREE TOGGLE ==================== -->\n\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'select' &&\n !isDisabled(element)\n ) {\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"\n $event\n ? setSelection(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n : null\n \" [disabled]=\"isDisabled(element)\" [checked]=\"\n smartTable.selection!.isSelected(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \" [aria-label]=\"\n checkboxLabel(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \">\n </mat-checkbox>\n }\n @if (\n smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].properties\n ) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATETIME) {\n <div>\n {{\n getValue(element, header)\n | smartDateTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATE) {\n <div>\n {{\n getValue(element, header)\n | smartDate: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().TIME) {\n <div>\n {{\n getValue(element, header)\n | smartTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().CHECKBOX) {\n <div>\n <mat-checkbox [disabled]=\"true\" [checked]=\"getValue(element, header)\"></mat-checkbox>\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders[i].properties?.type === type().ICON &&\n smartTable.customSmartTableHeaders[i].properties?.icons?.length\n ) {\n <div>\n <smart-icon [smartTooltip]=\"getToolTip(element, i)\" [icon]=\"getIcon(getValue(element, header), i)!\"\n [color]=\"getColor(getValue(element, header), i)\">\n </smart-icon>\n </div>\n }\n </div>\n }\n <div class=\"smart-table-icon-container\">\n @for (ir of getImageResourceIcons(element, header); track ir) {\n <div>\n <smart-icon [imageResource]=\"ir\"> </smart-icon>\n </div>\n }\n </div>\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].buttons) {\n <div class=\"smart-table-buttons-col\">\n @for (button of smartTable.customSmartTableHeaders[i].buttons; track button) {\n <div>\n @if (showButton(button, element)) {\n <div>\n @switch (button.type) {\n @case (smartTableButtonType.ICON) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-icon-button color=\"{{ button.color }}\">\n <smart-icon title=\"{{ button.label }}\" [icon]=\"button.icon!\"></smart-icon>\n </button>\n }\n @case (smartTableButtonType.NORMAL) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-button color=\"{{ button.color }}\">\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n @case (smartTableButtonType.RAISED) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-raised-button\n color=\"{{ button.color }}\">\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n <!------ MENU ------>\n @case (smartTableButtonType.MENU) {\n <div class=\"menu-button\">\n <!------ DEFAULT_ACTION_COLUMN ID TOOLBAR ------>\n <smart-ui-action-toolbar [uiActionModels]=\"getRowColumnAction(element, defaultActionToolbarId)\"\n [widgetId]=\"smartTable.getGridId()\" [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n <!------ GENERIC HAMBURGER ------>\n <!------ TOOLBAR ------>\n @if (shouldShowMenuButton(element)) {\n <smart-ui-action-toolbar [uiActionModels]=\"getMenuActions(element)\" [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\" [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n }\n </div>\n }\n <!------ MENU ------>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].icon) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].icon?.icon) {\n <smart-icon [ngClass]=\"smartTable.customSmartTableHeaders[i].icon?.cssClass ?? ''\"\n [color]=\"$safeNavigationMigration(smartTable.customSmartTableHeaders[i].icon?.color)\"\n [icon]=\"smartTable.customSmartTableHeaders[i].icon!.icon\">\n </smart-icon>\n }\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].translator !== undefined\n ) {\n <div>\n {{ smartTable.customSmartTableHeaders[i].translator!(getValue(element, header)) }}\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'expand'\n ) {\n <button mat-icon-button aria-label=\"expand row\" (click)=\"onToggle(element, $event)\">\n @if (expandedElement !== element) {\n <smart-icon [icon]=\"'keyboard_arrow_down'\"></smart-icon>\n }\n @if (expandedElement === element) {\n <smart-icon [icon]=\"'keyboard_arrow_up'\"></smart-icon>\n }\n </button>\n }\n @if (\n !smartTable.customSmartTableHeaders ||\n (smartTable.customSmartTableHeaders &&\n !smartTable.customSmartTableHeaders[i].properties &&\n !smartTable.customSmartTableHeaders[i].icon &&\n !smartTable.customSmartTableHeaders[i].buttons &&\n !smartTable.customSmartTableHeaders[i].translator &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'select') &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'expand'))\n ) {\n <div>\n @if (header === 'icon') {\n <smart-icon [icon]=\"getValue(element, header)!\"> </smart-icon>\n }\n @if (header === 'img') {\n <img [src]=\"getValue(element, header)\" alt=\"\" class=\"smarttableImg\" />\n }\n <!------ TOOLBAR ------>\n @if (showCellToolbar(element, header)) {\n <smart-ui-action-toolbar [uiActionModels]=\"getRowColumnAction(element, header)\"\n [widgetId]=\"smartTable.getGridId()\" [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n }\n <!------ TOOLBAR ------>\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'option' &&\n header !== 'button' &&\n !isImageResource(element, header)\n ) {\n <div [innerHtml]=\"getValue(element, header)\"></div>\n }\n </div>\n }\n\n </div>\n </td>\n </ng-container>\n }\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n @if (smartTable.expandable) {\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"smartTable.tableHeaders.length\">\n <div class=\"smart-table-detail\" animate.enter=\"smart-table-detail-enter\">\n <div class=\"smart-table-detail-content\">\n <ng-template #expandedArea></ng-template>\n </div>\n </div>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"smartTable.tableHeaders; sticky: true\"></tr>\n <ng-container *matRowDef=\"let element; columns: smartTable.tableHeaders\">\n <tr mat-row class=\"smart-table-row\" [class.smart-table-row-expanded]=\"expandedElement === element\"\n [ngClass]=\"getRowClasses(element)\" [ngStyle]=\"getRowStyles(element)\" (click)=\"handleOnRowClick(element)\"\n (dblclick)=\"handleOnRowDoubleClick($event, element)\" [attr.data-testid]=\"element?.id ?? null\"></tr>\n\n @if (smartTable.defaultActionCodes && smartTable.defaultActionCodes.length > 0) {\n <lib-default-actions-popup #defaultActionMenu [buttons]=\"getDefaultActionsForRow(element)!\"\n [row]=\"element\"></lib-default-actions-popup>\n }\n </ng-container>\n <!-- Only the expanded row has a detail row; no host style can give a collapsed one a height. -->\n @if (smartTable.expandable) {\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']; when: isExpandedRow\" class=\"smart-table-detail-row\"\n (animate.leave)=\"onDetailRowLeave($event)\"></tr>\n }\n</table>", styles: [".full-width{width:100%}.smarttableImg{width:25px}.smartTableRowHover:hover{cursor:pointer}tr.smart-table-row:not(.smart-table-row-expanded):hover{background:#f5f5f5}tr.smart-table-row:not(.smart-table-row-expanded):active{background:#efefef}tr.smart-table-row-expanded td{border-bottom-width:0}tr.smart-table-detail-row{height:0}.smart-table-detail{display:grid;grid-template-rows:1fr}.smart-table-detail-enter{animation:smart-table-detail-expand 225ms cubic-bezier(.4,0,.2,1)}.smart-table-detail-content{min-height:0;overflow:hidden}@keyframes smart-table-detail-expand{0%{grid-template-rows:0fr}to{grid-template-rows:1fr}}.disabledRow{color:var(--disabled)}.disabledRow:hover{cursor:default}.smart-table-buttons-col{display:flex;flex-direction:row;justify-content:flex-end}.sortableHeaderButton{margin:0!important;padding:0!important;text-align:left!important}.selected{background-color:var(--primary-light-color)}.smart-table-icon-container{display:flex;flex-direction:row;justify-content:space-between;white-space:initial}.reversed{flex-direction:row-reverse;gap:1rem}:host ::ng-deep .mat-mdc-menu-item{line-height:normal!important}.mat-mdc-menu-item[disabled]{cursor:default!important}.menu-button{display:flex;flex-direction:row;justify-content:flex-end;text-align:-webkit-right;align-items:center}.captionTitle{font-size:1.5rem;align-content:center;padding:.5rem .75rem;text-align:start;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);background:#f5f5f5}.tree-grid-actions,.mat-cell-content{display:flex;flex-direction:row;align-items:center}.mat-column-my_menu,.tree-grid-column{width:0}.tree-grid-cell{display:flex;align-items:center;min-height:48px}.tree-grid-expand-button{flex:0 0 auto}.tree-grid-spacer{display:inline-block;width:40px;flex:0 0 40px}.tree-grid-label{min-width:0}\n"], dependencies: [{ kind: "component", type: MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "addedCssClass", "addBasicClasses", "iconPlaceholder"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: SmartIconComponent, selector: "smart-icon", inputs: ["icon", "color", "imageResource"] }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: SmartTooltipDirective, selector: "[smartTooltip]", inputs: ["smartTooltip"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: DefaultActionsPopupComponent, selector: "lib-default-actions-popup", inputs: ["buttons", "row", "colIdx"] }, { kind: "pipe", type: SmartDateTimePipe, name: "smartDateTime" }, { kind: "pipe", type: SmartDatePipe, name: "smartDate" }, { kind: "pipe", type: SmartTimePipe, name: "smartTime" }] }); }
11878
12223
  }
11879
12224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MaterialTableComponent, decorators: [{
11880
12225
  type: Component,
11881
- args: [{ selector: 'lib-material-table', imports: [MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, NgClass, NgStyle, UiActionToolbarComponent, MatCheckbox, MatButton, SmartIconComponent, MatCellDef, MatCell, SmartTooltipDirective, MatIconButton, MatMenuTrigger, MatMenu, MatMenuItem, MatDivider, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, DefaultActionsPopupComponent, SmartDateTimePipe, SmartDatePipe, SmartTimePipe], template: "<table\n #myTable\n mat-table\n [dataSource]=\"smartTable.tableRows\"\n class=\"full-width\"\n multiTemplateDataRows\n >\n <!-- Column Descriptor -->\n @if (smartTable.title) {\n <caption class=\"captionTitle\">\n {{ smartTable.title }}\n </caption>\n }\n @for (header of smartTable.tableHeaders; track header; let i = $index) {\n <ng-container\n matColumnDef=\"{{ header }}\"\n >\n <!-- my_menu is the implicit action column present on all tables: -->\n @if ('my_menu' === header) {\n <th\n mat-header-cell\n *matHeaderCellDef\n [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\"\n >\n <smart-ui-action-toolbar [id]=\"headerToolbarId\"></smart-ui-action-toolbar>\n </th>\n } @else {\n <th\n mat-header-cell\n *matHeaderCellDef\n [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\"\n >\n @if (\n header === 'icon' || header === 'img' || header === 'options' || header === 'button'\n ) {\n <div\n ></div>\n }\n @if (header === 'select') {\n <div>\n @if (smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"smartTable.selection!.hasValue() && isAllSelected()\"\n [indeterminate]=\"smartTable.selection!.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n >\n </mat-checkbox>\n }\n @if (!smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <div>\n {{ smartTable.customTableHeaders[i] }}\n </div>\n }\n </div>\n }\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'options' &&\n header !== 'button' &&\n header !== 'select' &&\n header !== 'expand' &&\n header !== 'actions'\n ) {\n <div\n >\n @if (smartTable.sortable) {\n @if (smartTable.sortable && isSortable(smartTable.customSmartTableHeaders![i])) {\n <button\n (click)=\"sortButtonClicked($event, smartTable.customSmartTableHeaders![i])\"\n mat-button\n class=\"sortableHeaderButton\"\n >\n {{ smartTable.customTableHeaders[i] }}\n @if (getSortIcon(header)) {\n <smart-icon\n class=\"sortableHeaderButtonIcon\"\n title=\"sort\"\n [icon]=\"getSortIcon(header)!\"\n ></smart-icon>\n }\n @if (hasSortNumIcon(header)) {\n <smart-icon\n class=\"sortableHeaderButtonIcon\"\n title=\"sort\"\n [icon]=\"getSortNumIcon(header)\"\n ></smart-icon>\n }\n </button>\n }\n } @else {\n {{ smartTable.customTableHeaders[i] }}\n }\n </div>\n }\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" [ngClass]=\"isDisabled(element) ? 'disabledRow' : ''\">\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'select' &&\n !isDisabled(element)\n ) {\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"\n $event\n ? setSelection(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n : null\n \"\n [disabled]=\"isDisabled(element)\"\n [checked]=\"\n smartTable.selection!.isSelected(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \"\n [aria-label]=\"\n checkboxLabel(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \"\n >\n </mat-checkbox>\n }\n @if (\n smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].properties\n ) {\n <div\n >\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATETIME) {\n <div>\n {{\n getValue(element, header)\n | smartDateTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATE) {\n <div>\n {{\n getValue(element, header)\n | smartDate: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().TIME) {\n <div>\n {{\n getValue(element, header)\n | smartTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().CHECKBOX) {\n <div>\n <mat-checkbox [disabled]=\"true\" [checked]=\"getValue(element, header)\"></mat-checkbox>\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders[i].properties?.type === type().ICON &&\n smartTable.customSmartTableHeaders[i].properties?.icons?.length\n ) {\n <div\n >\n <smart-icon\n [smartTooltip]=\"getToolTip(element, i)\"\n [icon]=\"getIcon(getValue(element, header), i)!\"\n [color]=\"getColor(getValue(element, header), i)\"\n >\n </smart-icon>\n </div>\n }\n </div>\n }\n <div class=\"smart-table-icon-container\">\n @for (ir of getImageResourceIcons(element, header); track ir) {\n <div>\n <smart-icon [imageResource]=\"ir\"> </smart-icon>\n </div>\n }\n </div>\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].buttons) {\n <div\n class=\"smart-table-buttons-col\"\n >\n @for (button of smartTable.customSmartTableHeaders[i].buttons; track button) {\n <div>\n @if (showButton(button, element)) {\n <div>\n @switch (button.type) {\n @case (smartTableButtonType.ICON) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-icon-button\n color=\"{{ button.color }}\"\n >\n <smart-icon title=\"{{ button.label }}\" [icon]=\"button.icon!\"></smart-icon>\n </button>\n }\n @case (smartTableButtonType.NORMAL) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-button\n color=\"{{ button.color }}\"\n >\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n @case (smartTableButtonType.RAISED) {\n <button\n (click)=\"customButtonClicked($event, button, element)\"\n mat-raised-button\n color=\"{{ button.color }}\"\n >\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n <!------ MENU ------>\n @case (smartTableButtonType.MENU) {\n <div class=\"menu-button\">\n <!------ DEFAULT_ACTION_COLUMN ID TOOLBAR ------>\n <smart-ui-action-toolbar\n [uiActionModels]=\"getRowColumnAction(element, defaultActionToolbarId)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n <!------ GENERIC HAMBURGER ------>\n <!------ TOOLBAR ------>\n @if (shouldShowMenuButton(element)) {\n <smart-ui-action-toolbar\n [uiActionModels]=\"getMenuActions(element)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n }\n </div>\n }\n <!------ MENU ------>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].icon) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].icon?.icon) {\n <smart-icon\n [ngClass]=\"smartTable.customSmartTableHeaders[i].icon?.cssClass ?? ''\"\n [color]=\"$safeNavigationMigration(smartTable.customSmartTableHeaders[i].icon?.color)\"\n [icon]=\"smartTable.customSmartTableHeaders[i].icon!.icon\"\n >\n </smart-icon>\n }\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].translator !== undefined\n ) {\n <div\n >\n {{ smartTable.customSmartTableHeaders[i].translator!(getValue(element, header)) }}\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'expand'\n ) {\n <button\n mat-icon-button\n aria-label=\"expand row\"\n (click)=\"onToggle(element, $event)\"\n >\n @if (expandedElement !== element) {\n <smart-icon [icon]=\"'keyboard_arrow_down'\"></smart-icon>\n }\n @if (expandedElement === element) {\n <smart-icon [icon]=\"'keyboard_arrow_up'\"></smart-icon>\n }\n </button>\n }\n @if (\n !smartTable.customSmartTableHeaders ||\n (smartTable.customSmartTableHeaders &&\n !smartTable.customSmartTableHeaders[i].properties &&\n !smartTable.customSmartTableHeaders[i].icon &&\n !smartTable.customSmartTableHeaders[i].buttons &&\n !smartTable.customSmartTableHeaders[i].translator &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'select') &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'expand'))\n ) {\n <div\n >\n @if (header === 'icon') {\n <smart-icon [icon]=\"getValue(element, header)!\"> </smart-icon>\n }\n @if (header === 'img') {\n <img\n [src]=\"getValue(element, header)\"\n alt=\"\"\n class=\"smarttableImg\"\n />\n }\n <!------ TOOLBAR ------>\n @if (showCellToolbar(element, header)) {\n <smart-ui-action-toolbar\n [uiActionModels]=\"getRowColumnAction(element, header)\"\n [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"\n ></smart-ui-action-toolbar>\n }\n <!------ TOOLBAR ------>\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'option' &&\n header !== 'button' &&\n !isImageResource(element, header)\n ) {\n <div\n [innerHtml]=\"getValue(element, header)\"\n ></div>\n }\n </div>\n }\n </td>\n </ng-container>\n }\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n @if (smartTable.expandable) {\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"smartTable.tableHeaders.length\">\n <div class=\"smart-table-detail\" animate.enter=\"smart-table-detail-enter\">\n <div class=\"smart-table-detail-content\">\n <ng-template #expandedArea></ng-template>\n </div>\n </div>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"smartTable.tableHeaders; sticky: true\"></tr>\n <ng-container *matRowDef=\"let element; columns: smartTable.tableHeaders\">\n <tr\n mat-row\n class=\"smart-table-row\"\n [class.smart-table-row-expanded]=\"expandedElement === element\"\n [ngClass]=\"getRowClasses(element)\"\n [ngStyle]=\"getRowStyles(element)\"\n (click)=\"handleOnRowClick(element)\"\n (dblclick)=\"handleOnRowDoubleClick($event, element)\"\n [attr.data-testid]=\"element?.id ?? null\"\n ></tr>\n @if (smartTable.defaultActionCodes && smartTable.defaultActionCodes.length > 0) {\n <lib-default-actions-popup\n #defaultActionMenu\n [buttons]=\"getDefaultActionsForRow(element)!\"\n [row]=\"element\"\n ></lib-default-actions-popup>\n }\n </ng-container>\n <!-- Only the expanded row has a detail row; no host style can give a collapsed one a height. -->\n @if (smartTable.expandable) {\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['expandedDetail']; when: isExpandedRow\"\n class=\"smart-table-detail-row\"\n (animate.leave)=\"onDetailRowLeave($event)\"\n ></tr>\n }\n</table>\n", styles: [".full-width{width:100%}.smarttableImg{width:25px}.smartTableRowHover:hover{cursor:pointer}tr.smart-table-row:not(.smart-table-row-expanded):hover{background:#f5f5f5}tr.smart-table-row:not(.smart-table-row-expanded):active{background:#efefef}tr.smart-table-row-expanded td{border-bottom-width:0}tr.smart-table-detail-row{height:0}.smart-table-detail{display:grid;grid-template-rows:1fr}.smart-table-detail-enter{animation:smart-table-detail-expand 225ms cubic-bezier(.4,0,.2,1)}.smart-table-detail-content{min-height:0;overflow:hidden}@keyframes smart-table-detail-expand{0%{grid-template-rows:0fr}to{grid-template-rows:1fr}}.disabledRow{color:var(--disabled)}.disabledRow:hover{cursor:default}.smart-table-buttons-col{display:flex;flex-direction:row;justify-content:flex-end}.sortableHeaderButton{margin:0!important;padding:0!important;text-align:left!important}.selected{background-color:var(--primary-light-color)}.smart-table-icon-container{display:flex;flex-direction:row;justify-content:space-between;white-space:initial}.reversed{flex-direction:row-reverse;gap:1rem}:host ::ng-deep .mat-mdc-menu-item{line-height:normal!important}.mat-mdc-menu-item[disabled]{cursor:default!important}.menu-button{display:flex;flex-direction:row;justify-content:flex-end;text-align:-webkit-right;align-items:center}.captionTitle{font-size:1.5rem;align-content:center;padding:.5rem .75rem;text-align:start;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);background:#f5f5f5}\n"] }]
12226
+ args: [{ selector: 'lib-material-table', imports: [MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, NgClass, NgStyle, UiActionToolbarComponent, UiActionButtonComponent, MatCheckbox, MatButton, SmartIconComponent, MatCellDef, MatCell, SmartTooltipDirective, MatIconButton, MatMenuTrigger, MatMenu, MatMenuItem, MatDivider, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, DefaultActionsPopupComponent, SmartDateTimePipe, SmartDatePipe, SmartTimePipe], template: "<table #myTable mat-table [dataSource]=\"isTreeGrid ? visibleRows : smartTable.tableRows\" class=\"full-width\"\n multiTemplateDataRows>\n <!-- Column Descriptor -->\n @if (smartTable.title) {\n <caption class=\"captionTitle\">\n {{ smartTable.title }}\n </caption>\n }\n\n @for (header of smartTable.tableHeaders; track header; let i = $index) {\n\n <ng-container matColumnDef=\"{{ header }}\">\n <!-- my_menu is the implicit action column present on all tables: -->\n @if ('my_menu' === header) {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\">\n\n <!-- ==================== TREE ACTIONS ==================== -->\n @if ( isTreeGrid) {\n <div class=\"tree-grid-actions\">\n\n <ui-action-button (actionClick)=\"expandOneLevel()\" [descriptor]=\"expandTreeGridLevel\">\n </ui-action-button>\n\n\n <ui-action-button (actionClick)=\"collapseOneLevel()\" [descriptor]=\"closeTreeGridLevel\">\n </ui-action-button>\n </div>\n }\n <!-- ==================== TREE ACTIONS ==================== -->\n\n <smart-ui-action-toolbar [id]=\"headerToolbarId\"></smart-ui-action-toolbar>\n </th>\n } @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(smartTable.customSmartTableHeaders![i])\"\n [ngStyle]=\"getColumnStyles(smartTable.customSmartTableHeaders![i])\"\n [attr.data-testid]=\"smartTable.customSmartTableHeaders![i].propertyName\">\n @if (\n header === 'icon' || header === 'img' || header === 'options' || header === 'button'\n ) {\n <div></div>\n }\n @if (header === 'select') {\n <div>\n @if (smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <mat-checkbox (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"smartTable.selection!.hasValue() && isAllSelected()\"\n [indeterminate]=\"smartTable.selection!.hasValue() && !isAllSelected()\" [aria-label]=\"checkboxLabel()\">\n </mat-checkbox>\n }\n @if (!smartTable.customSmartTableHeaders![i].showCheckboxInHeader) {\n <div>\n {{ smartTable.customTableHeaders[i] }}\n </div>\n }\n </div>\n }\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'options' &&\n header !== 'button' &&\n header !== 'select' &&\n header !== 'expand' &&\n header !== 'actions'\n ) {\n <div>\n @if (smartTable.sortable) {\n @if (smartTable.sortable && isSortable(smartTable.customSmartTableHeaders![i])) {\n <button (click)=\"sortButtonClicked($event, smartTable.customSmartTableHeaders![i])\" mat-button\n class=\"sortableHeaderButton\">\n {{ smartTable.customTableHeaders[i] }}\n @if (getSortIcon(header)) {\n <smart-icon class=\"sortableHeaderButtonIcon\" title=\"sort\" [icon]=\"getSortIcon(header)!\"></smart-icon>\n }\n @if (hasSortNumIcon(header)) {\n <smart-icon class=\"sortableHeaderButtonIcon\" title=\"sort\" [icon]=\"getSortNumIcon(header)\"></smart-icon>\n }\n </button>\n }\n } @else {\n {{ smartTable.customTableHeaders[i] }}\n }\n </div>\n }\n </th>\n }\n\n <td mat-cell *matCellDef=\"let element\" [ngClass]=\"isDisabled(element) ? 'disabledRow' : ''\">\n <div class=\"mat-cell-content\">\n\n\n <!-- ==================== TREE TOGGLE ==================== -->\n @if (isTreeGrid && i === 0) {\n <div class=\"tree-grid-first-column\" [style.padding-left.px]=\"(element.level ?? 0) * 24\">\n @if (hasChildren(element)) {\n <button mat-icon-button type=\"button\" (click)=\"toggleRowExpansion(element, $event)\">\n <smart-icon [icon]=\"\n isRowExpanded(element)\n ? 'keyboard_arrow_down'\n : 'keyboard_arrow_right'\n \"></smart-icon>\n </button>\n } @else {\n <span class=\"tree-grid-spacer\"></span>\n }\n\n </div>\n }\n <!-- ==================== TREE TOGGLE ==================== -->\n\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'select' &&\n !isDisabled(element)\n ) {\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"\n $event\n ? setSelection(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n : null\n \" [disabled]=\"isDisabled(element)\" [checked]=\"\n smartTable.selection!.isSelected(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \" [aria-label]=\"\n checkboxLabel(\n smartTable.selectionProperty\n ? smartTable.getValueDeeply(element, smartTable.selectionProperty)\n : element\n )\n \">\n </mat-checkbox>\n }\n @if (\n smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].properties\n ) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATETIME) {\n <div>\n {{\n getValue(element, header)\n | smartDateTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().DATE) {\n <div>\n {{\n getValue(element, header)\n | smartDate: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().TIME) {\n <div>\n {{\n getValue(element, header)\n | smartTime: $safeNavigationMigration(smartTable.customSmartTableHeaders[i].properties?.dateFormat)\n }}\n </div>\n }\n @if (smartTable.customSmartTableHeaders[i].properties?.type === type().CHECKBOX) {\n <div>\n <mat-checkbox [disabled]=\"true\" [checked]=\"getValue(element, header)\"></mat-checkbox>\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders[i].properties?.type === type().ICON &&\n smartTable.customSmartTableHeaders[i].properties?.icons?.length\n ) {\n <div>\n <smart-icon [smartTooltip]=\"getToolTip(element, i)\" [icon]=\"getIcon(getValue(element, header), i)!\"\n [color]=\"getColor(getValue(element, header), i)\">\n </smart-icon>\n </div>\n }\n </div>\n }\n <div class=\"smart-table-icon-container\">\n @for (ir of getImageResourceIcons(element, header); track ir) {\n <div>\n <smart-icon [imageResource]=\"ir\"> </smart-icon>\n </div>\n }\n </div>\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].buttons) {\n <div class=\"smart-table-buttons-col\">\n @for (button of smartTable.customSmartTableHeaders[i].buttons; track button) {\n <div>\n @if (showButton(button, element)) {\n <div>\n @switch (button.type) {\n @case (smartTableButtonType.ICON) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-icon-button color=\"{{ button.color }}\">\n <smart-icon title=\"{{ button.label }}\" [icon]=\"button.icon!\"></smart-icon>\n </button>\n }\n @case (smartTableButtonType.NORMAL) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-button color=\"{{ button.color }}\">\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n @case (smartTableButtonType.RAISED) {\n <button (click)=\"customButtonClicked($event, button, element)\" mat-raised-button\n color=\"{{ button.color }}\">\n @if (button.icon) {\n <smart-icon [icon]=\"button.icon\"></smart-icon>\n }\n {{ button.label ?? (button.translator ? button.translator(element).title : '') }}\n </button>\n }\n <!------ MENU ------>\n @case (smartTableButtonType.MENU) {\n <div class=\"menu-button\">\n <!------ DEFAULT_ACTION_COLUMN ID TOOLBAR ------>\n <smart-ui-action-toolbar [uiActionModels]=\"getRowColumnAction(element, defaultActionToolbarId)\"\n [widgetId]=\"smartTable.getGridId()\" [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n <!------ GENERIC HAMBURGER ------>\n <!------ TOOLBAR ------>\n @if (shouldShowMenuButton(element)) {\n <smart-ui-action-toolbar [uiActionModels]=\"getMenuActions(element)\" [widgetId]=\"smartTable.getGridId()\"\n [nodeId]=\"element.id\" [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n }\n </div>\n }\n <!------ MENU ------>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n @if (smartTable.customSmartTableHeaders && smartTable.customSmartTableHeaders[i].icon) {\n <div>\n @if (smartTable.customSmartTableHeaders[i].icon?.icon) {\n <smart-icon [ngClass]=\"smartTable.customSmartTableHeaders[i].icon?.cssClass ?? ''\"\n [color]=\"$safeNavigationMigration(smartTable.customSmartTableHeaders[i].icon?.color)\"\n [icon]=\"smartTable.customSmartTableHeaders[i].icon!.icon\">\n </smart-icon>\n }\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].translator !== undefined\n ) {\n <div>\n {{ smartTable.customSmartTableHeaders[i].translator!(getValue(element, header)) }}\n </div>\n }\n @if (\n smartTable.customSmartTableHeaders &&\n smartTable.customSmartTableHeaders[i].propertyName === 'expand'\n ) {\n <button mat-icon-button aria-label=\"expand row\" (click)=\"onToggle(element, $event)\">\n @if (expandedElement !== element) {\n <smart-icon [icon]=\"'keyboard_arrow_down'\"></smart-icon>\n }\n @if (expandedElement === element) {\n <smart-icon [icon]=\"'keyboard_arrow_up'\"></smart-icon>\n }\n </button>\n }\n @if (\n !smartTable.customSmartTableHeaders ||\n (smartTable.customSmartTableHeaders &&\n !smartTable.customSmartTableHeaders[i].properties &&\n !smartTable.customSmartTableHeaders[i].icon &&\n !smartTable.customSmartTableHeaders[i].buttons &&\n !smartTable.customSmartTableHeaders[i].translator &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'select') &&\n !(smartTable.customSmartTableHeaders[i].propertyName === 'expand'))\n ) {\n <div>\n @if (header === 'icon') {\n <smart-icon [icon]=\"getValue(element, header)!\"> </smart-icon>\n }\n @if (header === 'img') {\n <img [src]=\"getValue(element, header)\" alt=\"\" class=\"smarttableImg\" />\n }\n <!------ TOOLBAR ------>\n @if (showCellToolbar(element, header)) {\n <smart-ui-action-toolbar [uiActionModels]=\"getRowColumnAction(element, header)\"\n [widgetId]=\"smartTable.getGridId()\" [nodeId]=\"element.id\"\n [actionParams]=\"{ model: element }\"></smart-ui-action-toolbar>\n }\n <!------ TOOLBAR ------>\n @if (\n header !== 'icon' &&\n header !== 'img' &&\n header !== 'option' &&\n header !== 'button' &&\n !isImageResource(element, header)\n ) {\n <div [innerHtml]=\"getValue(element, header)\"></div>\n }\n </div>\n }\n\n </div>\n </td>\n </ng-container>\n }\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n @if (smartTable.expandable) {\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"smartTable.tableHeaders.length\">\n <div class=\"smart-table-detail\" animate.enter=\"smart-table-detail-enter\">\n <div class=\"smart-table-detail-content\">\n <ng-template #expandedArea></ng-template>\n </div>\n </div>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"smartTable.tableHeaders; sticky: true\"></tr>\n <ng-container *matRowDef=\"let element; columns: smartTable.tableHeaders\">\n <tr mat-row class=\"smart-table-row\" [class.smart-table-row-expanded]=\"expandedElement === element\"\n [ngClass]=\"getRowClasses(element)\" [ngStyle]=\"getRowStyles(element)\" (click)=\"handleOnRowClick(element)\"\n (dblclick)=\"handleOnRowDoubleClick($event, element)\" [attr.data-testid]=\"element?.id ?? null\"></tr>\n\n @if (smartTable.defaultActionCodes && smartTable.defaultActionCodes.length > 0) {\n <lib-default-actions-popup #defaultActionMenu [buttons]=\"getDefaultActionsForRow(element)!\"\n [row]=\"element\"></lib-default-actions-popup>\n }\n </ng-container>\n <!-- Only the expanded row has a detail row; no host style can give a collapsed one a height. -->\n @if (smartTable.expandable) {\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']; when: isExpandedRow\" class=\"smart-table-detail-row\"\n (animate.leave)=\"onDetailRowLeave($event)\"></tr>\n }\n</table>", styles: [".full-width{width:100%}.smarttableImg{width:25px}.smartTableRowHover:hover{cursor:pointer}tr.smart-table-row:not(.smart-table-row-expanded):hover{background:#f5f5f5}tr.smart-table-row:not(.smart-table-row-expanded):active{background:#efefef}tr.smart-table-row-expanded td{border-bottom-width:0}tr.smart-table-detail-row{height:0}.smart-table-detail{display:grid;grid-template-rows:1fr}.smart-table-detail-enter{animation:smart-table-detail-expand 225ms cubic-bezier(.4,0,.2,1)}.smart-table-detail-content{min-height:0;overflow:hidden}@keyframes smart-table-detail-expand{0%{grid-template-rows:0fr}to{grid-template-rows:1fr}}.disabledRow{color:var(--disabled)}.disabledRow:hover{cursor:default}.smart-table-buttons-col{display:flex;flex-direction:row;justify-content:flex-end}.sortableHeaderButton{margin:0!important;padding:0!important;text-align:left!important}.selected{background-color:var(--primary-light-color)}.smart-table-icon-container{display:flex;flex-direction:row;justify-content:space-between;white-space:initial}.reversed{flex-direction:row-reverse;gap:1rem}:host ::ng-deep .mat-mdc-menu-item{line-height:normal!important}.mat-mdc-menu-item[disabled]{cursor:default!important}.menu-button{display:flex;flex-direction:row;justify-content:flex-end;text-align:-webkit-right;align-items:center}.captionTitle{font-size:1.5rem;align-content:center;padding:.5rem .75rem;text-align:start;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);background:#f5f5f5}.tree-grid-actions,.mat-cell-content{display:flex;flex-direction:row;align-items:center}.mat-column-my_menu,.tree-grid-column{width:0}.tree-grid-cell{display:flex;align-items:center;min-height:48px}.tree-grid-expand-button{flex:0 0 auto}.tree-grid-spacer{display:inline-block;width:40px;flex:0 0 40px}.tree-grid-label{min-width:0}\n"] }]
11882
12227
  }] });
11883
12228
 
11884
12229
  class MobileTableComponent extends Table {
@@ -15606,11 +15951,11 @@ class SmarttreeGenericService extends SmarttreeService {
15606
15951
  let nodeId = uiActionRequest.params['nodeUuid'];
15607
15952
  delete uiActionRequest.params['nodeUuid'];
15608
15953
  let viewUuid = this.viewContext.getUuidOfPage(this.pageName);
15609
- this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.service.performAction2(viewUuid, this.treeId, nodeId, uiActionRequest).toPromise());
15954
+ this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.viewContext.withModelSync(uiActionRequest, (request) => this.service.performAction2(viewUuid, this.treeId, nodeId, request).toPromise()));
15610
15955
  }
15611
15956
  async performMainUiActionRequest(uiActionRequest) {
15612
15957
  let viewUuid = this.viewContext.getUuidOfPage(this.pageName);
15613
- this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.service.performMainAction2(viewUuid, this.treeId, uiActionRequest).toPromise());
15958
+ this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.viewContext.withModelSync(uiActionRequest, (request) => this.service.performMainAction2(viewUuid, this.treeId, request).toPromise()));
15614
15959
  }
15615
15960
  handleSpecificDemandsAsynchronously(uiAction, uiActionRequest) {
15616
15961
  throw new Error('Method not implemented.');
@@ -15652,11 +15997,13 @@ class SmartComponentApiClient {
15652
15997
  }
15653
15998
  if (this.uuid) {
15654
15999
  this.viewContext.unfollow(this.uuid);
16000
+ this.viewContext.leaveModelSync(this.uuid, this);
15655
16001
  }
15656
16002
  this.uuidState.set(uuid);
15657
16003
  // Widgets read `widgetUuid` themselves; nothing is pushed into them from here. (ADR-0005)
15658
16004
  if (uuid) {
15659
16005
  this.viewContext.follow(this.uuid, this.detectChange);
16006
+ this.viewContext.joinModelSync(this.uuid, this);
15660
16007
  this.onUuidResolved(uuid);
15661
16008
  }
15662
16009
  }
@@ -15746,7 +16093,6 @@ class SmartComponentApiClient {
15746
16093
  */
15747
16094
  this.commands = new Subject();
15748
16095
  this.dataChanged = new Subject();
15749
- this.sendModelOnWidgetAction = false;
15750
16096
  this.inmediateDataChangeKeys = [];
15751
16097
  this.blurDataChangeKeys = [];
15752
16098
  // check and calculate pageName
@@ -15783,6 +16129,7 @@ class SmartComponentApiClient {
15783
16129
  }
15784
16130
  _ngOnDestroy() {
15785
16131
  this.viewContext.unfollow(this.uuid);
16132
+ this.viewContext.leaveModelSync(this.uuid, this);
15786
16133
  this._destroy$.next();
15787
16134
  this._destroy$.complete();
15788
16135
  }
@@ -15868,6 +16215,7 @@ class SmartComponentApiClient {
15868
16215
  // grids are already loaded in setUuid()
15869
16216
  this.handleChangeWidgets(this.model.widgets, true);
15870
16217
  }
16218
+ this.viewContext.markModelSynced(uuid);
15871
16219
  }
15872
16220
  async executeUiAction(uiAction, options) {
15873
16221
  const uiActionModel = {
@@ -15894,7 +16242,7 @@ class SmartComponentApiClient {
15894
16242
  }
15895
16243
  let blurIdx = this.blurDataChangeKeys.indexOf(key);
15896
16244
  if (blurIdx >= 0) {
15897
- this.inmediateDataChangeKeys.splice(blurIdx, 1);
16245
+ this.blurDataChangeKeys.splice(blurIdx, 1);
15898
16246
  }
15899
16247
  }
15900
16248
  /**
@@ -15906,7 +16254,6 @@ class SmartComponentApiClient {
15906
16254
  if (changeKeys.includes(event.key)) {
15907
16255
  this.executeUiAction({
15908
16256
  code: event.key,
15909
- model: true,
15910
16257
  params: {
15911
16258
  item: event.value,
15912
16259
  },
@@ -15952,7 +16299,6 @@ class SmartComponentApiClient {
15952
16299
  delete uiActionRequest.params['_files'];
15953
16300
  delete uiActionRequest.params['_uploadDescriptor'];
15954
16301
  delete uiActionRequest.params['isMultiple'];
15955
- // await this.sendModelToServer();
15956
16302
  if (!isMultiple) {
15957
16303
  await this.viewContext.performUploadAction(this.uuid, uiActionRequest, param, files[0]);
15958
16304
  }
@@ -15992,38 +16338,15 @@ class SmartComponentApiClient {
15992
16338
  }
15993
16339
  }
15994
16340
  else if (widgetId && nodeId) {
15995
- // await this.sendModelToServer();
15996
- this.addModelToWidgetAction(uiActionRequest);
15997
16341
  await this.viewContext.performWidgetAction(this.uuid, widgetId, nodeId, uiActionRequest);
15998
16342
  }
15999
16343
  else if (widgetId) {
16000
- // await this.sendModelToServer();
16001
- this.addModelToWidgetAction(uiActionRequest);
16002
16344
  await this.viewContext.performWidgetMainAction(this.uuid, widgetId, uiActionRequest);
16003
16345
  }
16004
16346
  else {
16005
16347
  await this.viewContext.performAction(this.uuid, uiActionRequest);
16006
16348
  }
16007
16349
  }
16008
- addModelToWidgetAction(uiActionRequest) {
16009
- this.addModelToWidgetParams(uiActionRequest.params);
16010
- }
16011
- addModelToWidgetParams(params) {
16012
- if (this.sendModelOnWidgetAction) {
16013
- this.submitForm(false);
16014
- // mimic ComponentModel
16015
- params['clientPageModel'] = { data: this.getModel() };
16016
- }
16017
- }
16018
- // private async sendModelToServer() {
16019
- // this.submitForms(false);
16020
- // let dataChange = {
16021
- // kind: DataChangeKind.Widget,
16022
- // source: '',
16023
- // values: [['', this.getModel()]],
16024
- // };
16025
- // await this.viewContext.dataChanged(this.uuid!, dataChange);
16026
- // }
16027
16350
  handleSpecificDemandsAsynchronously(uiAction, uiActionRequest) {
16028
16351
  throw new Error('handleSpecificDemandsAsynchronously method not implemented.');
16029
16352
  }
@@ -16073,27 +16396,10 @@ class SmartComponentApiClient {
16073
16396
  return matData?.uuid;
16074
16397
  }
16075
16398
  // #region handle changes
16076
- handleValueChanges(valueChange) {
16077
- let dataChange;
16078
- if (valueChange.key.includes('.')) {
16079
- const source = valueChange.key.split('.')[0];
16080
- const valueKey = valueChange.key.split('.')[1];
16081
- dataChange = {
16082
- kind: valueChange.kind === 'basic' ? DataChangeKind.WIDGET : DataChangeKind.SELECTION,
16083
- source,
16084
- values: [[valueKey, valueChange.value]],
16085
- };
16086
- }
16087
- else {
16088
- dataChange = {
16089
- kind: valueChange.kind === 'basic' ? DataChangeKind.WIDGET : DataChangeKind.SELECTION,
16090
- source: valueChange.key,
16091
- values: [[valueChange.key, valueChange.value]],
16092
- };
16093
- }
16094
- this.viewContext.dataChanged(this.uuid, dataChange);
16095
- }
16096
16399
  handleChanges(change) {
16400
+ // What of the data the push wrote: the paths under `data`, or everything on a whole-model
16401
+ // replacement. Tells the view context how much of the data to take as the backend's.
16402
+ let pushedKeys = [];
16097
16403
  try {
16098
16404
  if (!this.componentModelLoaded) {
16099
16405
  // initial load
@@ -16108,6 +16414,7 @@ class SmartComponentApiClient {
16108
16414
  Object.keys(changes).map((changeKey) => {
16109
16415
  if (changeKey.startsWith('data.')) {
16110
16416
  this.handleDataChange(changes, changeKey);
16417
+ pushedKeys?.push(changeKey.substring('data.'.length));
16111
16418
  }
16112
16419
  else if (changeKey.startsWith('layouts.') && this.model?.layouts) {
16113
16420
  this.handleLayoutChange(changes, changeKey);
@@ -16127,6 +16434,7 @@ class SmartComponentApiClient {
16127
16434
  else if (changeKey === '') {
16128
16435
  this.model = changes[''];
16129
16436
  dataChangeHasBeenNexted = true;
16437
+ pushedKeys = undefined;
16130
16438
  }
16131
16439
  });
16132
16440
  if (!dataChangeHasBeenNexted) {
@@ -16137,9 +16445,14 @@ class SmartComponentApiClient {
16137
16445
  catch (error) {
16138
16446
  console.error(error);
16139
16447
  this.model = change.value;
16448
+ pushedKeys = undefined;
16140
16449
  }
16141
16450
  if (!change.changedWidgets && !change.changes && change.value) {
16142
16451
  this.model = change.value;
16452
+ pushedKeys = undefined;
16453
+ }
16454
+ if (pushedKeys === undefined || pushedKeys.length) {
16455
+ this.viewContext.markModelSynced(this.uuid, pushedKeys);
16143
16456
  }
16144
16457
  }
16145
16458
  /**
@@ -16293,6 +16606,7 @@ var SmartLayoutDef;
16293
16606
  SmartLayoutDef["EXPANDABLE"] = "EXPANDABLE";
16294
16607
  SmartLayoutDef["CARD"] = "CARD";
16295
16608
  SmartLayoutDef["TREE"] = "TREE";
16609
+ SmartLayoutDef["TREE_GRID"] = "TREE_GRID";
16296
16610
  })(SmartLayoutDef || (SmartLayoutDef = {}));
16297
16611
  var SmartGridButtonType;
16298
16612
  (function (SmartGridButtonType) {
@@ -16996,18 +17310,6 @@ var GridDataAccessConfigKindEnum;
16996
17310
  })(GridDataAccessConfigKindEnum || (GridDataAccessConfigKindEnum = {}));
16997
17311
  ;
16998
17312
 
16999
- /**
17000
- * Grid api
17001
- * The grid api is resposible for the grid components that shows a list of item.
17002
- *
17003
- * The version of the OpenAPI document: 1.0.0
17004
- * Contact: info@it4all.hu
17005
- *
17006
- * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
17007
- * https://openapi-generator.tech
17008
- * Do not edit the class manually.
17009
- */
17010
-
17011
17313
  /**
17012
17314
  * Grid api
17013
17315
  * The grid api is resposible for the grid components that shows a list of item.
@@ -17048,9 +17350,46 @@ var GridViewDescriptorKindEnum;
17048
17350
  GridViewDescriptorKindEnum["TABLE"] = "TABLE";
17049
17351
  GridViewDescriptorKindEnum["CARDS"] = "CARDS";
17050
17352
  GridViewDescriptorKindEnum["TREE"] = "TREE";
17353
+ GridViewDescriptorKindEnum["TREE_GRID"] = "TREE_GRID";
17051
17354
  })(GridViewDescriptorKindEnum || (GridViewDescriptorKindEnum = {}));
17052
17355
  ;
17053
17356
 
17357
+ class ApiModule {
17358
+ static forRoot(configurationFactory) {
17359
+ return {
17360
+ ngModule: ApiModule,
17361
+ providers: [{ provide: Configuration$2, useFactory: configurationFactory }]
17362
+ };
17363
+ }
17364
+ constructor(parentModule, http) {
17365
+ if (parentModule) {
17366
+ throw new Error('ApiModule is already loaded. Import in your base AppModule only.');
17367
+ }
17368
+ if (!http) {
17369
+ throw new Error('You need to import the HttpClientModule in your AppModule! \n' +
17370
+ 'See also https://github.com/angular/angular/issues/20575');
17371
+ }
17372
+ }
17373
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ApiModule, deps: [{ token: ApiModule, optional: true, skipSelf: true }, { token: i1.HttpClient, optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
17374
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: ApiModule }); }
17375
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ApiModule }); }
17376
+ }
17377
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ApiModule, decorators: [{
17378
+ type: NgModule,
17379
+ args: [{
17380
+ imports: [],
17381
+ declarations: [],
17382
+ exports: [],
17383
+ providers: []
17384
+ }]
17385
+ }], ctorParameters: () => [{ type: ApiModule, decorators: [{
17386
+ type: Optional
17387
+ }, {
17388
+ type: SkipSelf
17389
+ }] }, { type: i1.HttpClient, decorators: [{
17390
+ type: Optional
17391
+ }] }] });
17392
+
17054
17393
  class TableLayoutDefinerComponent {
17055
17394
  constructor() {
17056
17395
  this.data = inject(MAT_DIALOG_DATA);
@@ -17236,6 +17575,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
17236
17575
  args: ['forms']
17237
17576
  }] } });
17238
17577
 
17578
+ /** The model sync carrier of a selection call; the view context puts the envelope on it. */
17579
+ function selection(selected, unselected) {
17580
+ return { selected, unselected, params: {} };
17581
+ }
17239
17582
  class SmartGridService {
17240
17583
  constructor() {
17241
17584
  this.api = inject(GridService);
@@ -17273,27 +17616,19 @@ class SmartGridService {
17273
17616
  }
17274
17617
  async select(smartGrid, gridRow) {
17275
17618
  gridRow.selected = !gridRow.selected;
17276
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, [], []);
17277
- return await this.api
17619
+ return await smartGrid.viewContextService.withModelSync(selection([], []), (gridSelectionChange) => this.api
17278
17620
  .select(smartGrid.gridModel.viewUuid, smartGrid.gridIdentifier, gridRow.id, gridRow.selected, gridSelectionChange)
17279
- .toPromise();
17621
+ .toPromise());
17280
17622
  }
17281
17623
  async selectRows(smartGrid, selected, unselected) {
17282
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, selected, unselected);
17283
- return await this.api
17624
+ return await smartGrid.viewContextService.withModelSync(selection(selected, unselected), (gridSelectionChange) => this.api
17284
17625
  .selectRows(smartGrid.gridModel.viewUuid, smartGrid.gridIdentifier, gridSelectionChange)
17285
- .toPromise();
17626
+ .toPromise());
17286
17627
  }
17287
17628
  async selectAll(smartGrid, selected) {
17288
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, [], []);
17289
- return await this.api
17629
+ return await smartGrid.viewContextService.withModelSync(selection([], []), (gridSelectionChange) => this.api
17290
17630
  .selectAll(smartGrid.gridModel.viewUuid, smartGrid.gridIdentifier, selected, gridSelectionChange)
17291
- .toPromise();
17292
- }
17293
- buildGridSelectionChange(smartGrid, selected, unselected) {
17294
- const gridSelectionChange = { selected, unselected, params: {} };
17295
- smartGrid.serviceToUse?.addModelToWidgetParams?.(gridSelectionChange.params);
17296
- return gridSelectionChange;
17631
+ .toPromise());
17297
17632
  }
17298
17633
  async update(uuid, identifier, updateData) {
17299
17634
  if (!updateData.pageSize) {
@@ -17838,6 +18173,9 @@ class SmartGridComponent {
17838
18173
  if (kind === GridViewDescriptorKindEnum.TABLE) {
17839
18174
  layoutDef = SmartLayoutDef.TABLE;
17840
18175
  }
18176
+ else if (kind === GridViewDescriptorKindEnum.TREE_GRID) {
18177
+ layoutDef = SmartLayoutDef.TREE_GRID;
18178
+ }
17841
18179
  else if (kind === GridViewDescriptorKindEnum.TREE) {
17842
18180
  layoutDef = SmartLayoutDef.TREE;
17843
18181
  }
@@ -17863,6 +18201,9 @@ class SmartGridComponent {
17863
18201
  if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE) {
17864
18202
  this.renderTable();
17865
18203
  }
18204
+ else if (this.smartGrid.layoutDef === SmartLayoutDef.TREE_GRID) {
18205
+ this.renderTable();
18206
+ }
17866
18207
  else if (this.smartGrid.layoutDef === SmartLayoutDef.EXPANDABLE) {
17867
18208
  this.renderExpandableSections();
17868
18209
  }
@@ -17900,7 +18241,7 @@ class SmartGridComponent {
17900
18241
  else {
17901
18242
  this.tableType = SmartTableType.INHERITED;
17902
18243
  }
17903
- if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE) {
18244
+ if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE || this.smartGrid.layoutDef === SmartLayoutDef.TREE_GRID) {
17904
18245
  let tableConfig = {
17905
18246
  ...this.smartGrid.tableConfig,
17906
18247
  title: this.smartGrid?.gridModel.title,
@@ -18430,12 +18771,21 @@ class SmartGridComponent {
18430
18771
  };
18431
18772
  this.dialog.open(TableLayoutDefinerComponent, { data: dialogData });
18432
18773
  }
18774
+ get showEditColumns() {
18775
+ return {
18776
+ title: '',
18777
+ color: 'primary',
18778
+ type: UiActionButtonType.MINI_FAB,
18779
+ icon: 'view_columns',
18780
+ iconPosition: IconPosition.PRE,
18781
+ };
18782
+ }
18433
18783
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18434
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartGridComponent, isStandalone: true, selector: "smart-grid", inputs: { smartGrid: { classPropertyName: "smartGrid", publicName: "smartGrid", isSignal: false, isRequired: false, transformFunction: null }, uuid: { classPropertyName: "uuid", publicName: "uuid", isSignal: false, isRequired: false, transformFunction: null }, parentLayoutComponent: { classPropertyName: "parentLayoutComponent", publicName: "parentLayoutComponent", isSignal: true, isRequired: false, transformFunction: null }, dev: { classPropertyName: "dev", publicName: "dev", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-testid": "this.testId" } }, providers: [SmartGridService], viewQueries: [{ propertyName: "vcRefTable", first: true, predicate: ["table"], descendants: true, read: ViewContainerRef }, { propertyName: "expandedRowsComps", predicate: ExpandedRowRendererComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (smartGrid) {\n <div class=\"smartGrid-container\">\n <div class=\"smart-grid-toolbar\">\n <smart-ui-action-toolbar [id]=\"toolbarId\"></smart-ui-action-toolbar>\n @if (smartGrid.showEditColumns) {\n <button\n (click)=\"editColumns()\"\n mat-mini-fab\n color=\"text-primary\"\n >\n <mat-icon aria-hidden=\"false\" aria-label=\"Columns\" class=\"smart-grid-edit-icon\"\n >view_columns</mat-icon\n >\n </button>\n }\n </div>\n <!-- <div [ngClass]=\"isBlocked ? 'blocked' : ''\"></div> -->\n <div class=\"smartGridContent\">\n <div>\n @if (smartGrid.showResultCount) {\n <div>\n <div class=\"smartGrid-data-number\">\n {{ smartGrid.gridModel.totalRowCount }}\n </div>\n </div>\n }\n </div>\n <div class=\"smart-grid-table-container\">\n <ng-template #table></ng-template>\n </div>\n @if (smartGrid.layoutDef === layoutDef().EXPANDABLE) {\n <div>\n @for (expandableSection of expandableSections; track expandableSection) {\n <smart-expandable-section\n #gridExpandableSection\n [data]=\"expandableSection\"\n ></smart-expandable-section>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().CARD && smartGrid.dataLayoutDef) {\n <div\n class=\"cards-container\"\n [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\"\n >\n @for (row of smartGrid.gridModel.page.rows; track row.id) {\n <app-smart-grid-card\n class=\"smartGrid-card-container\"\n [class.clickable-row]=\"row.layoutDescriptor\"\n (click)=\"row.layoutDescriptor && onClick(row)\"\n [item]=\"row\"\n [smartGrid]=\"smartGrid\"\n [parentLayoutComponent]=\"parentLayoutComponent()\"\n ></app-smart-grid-card>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().TREE && treeControl) {\n <div\n class=\"tree-container\"\n [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\"\n >\n <mat-tree [dataSource]=\"treeDataSource!\" [treeControl]=\"treeControl!\">\n <mat-tree-node\n *matTreeNodeDef=\"let node\"\n matTreeNodeToggle\n matTreeNodePadding\n matTreeNodePaddingIndent=\"24\"\n >\n <button mat-icon-button disabled class=\"tree-button\"></button>\n <mat-checkbox\n class=\"checklist-leaf-node\"\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n (change)=\"treeNodeSelectionToggle(node)\"\n >{{ getTreeItem(node) }}</mat-checkbox\n >\n </mat-tree-node>\n <mat-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n matTreeNodePadding\n matTreeNodePaddingIndent=\"24\"\n >\n <button\n mat-icon-button\n matTreeNodeToggle\n class=\"tree-button\"\n [attr.aria-label]=\"'Toggle ' + node.item\"\n >\n <mat-icon class=\"mat-icon-rtl-mirror\">\n {{ treeControl!.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <mat-checkbox\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n [indeterminate]=\"descendantsPartiallySelected(node)\"\n (change)=\"treeNodeSelectionToggle(node)\"\n >{{ getTreeItem(node) }}</mat-checkbox\n >\n </mat-tree-node>\n </mat-tree>\n </div>\n }\n </div>\n @if (smartGrid.paginator) {\n <div class=\"paginator-row-material\">\n @if (smartGrid.gridModel.refreshEnabled) {\n <button mat-icon-button type=\"button\" matTooltip=\"Friss\u00EDt\u00E9s\" (click)=\"refreshPartialResults()\">\n <mat-icon>refresh</mat-icon>\n </button>\n }\n @if (smartGrid.paginator && !treeControl) {\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onChangePage($event)\"\n ></mat-paginator>\n }\n </div>\n }\n </div>\n }\n", styles: [".smartGrid-container{position:relative;padding:1.5rem;display:flex;flex-direction:column;gap:1rem}.smartGrid-data-number{padding-bottom:1rem}.cards-container{display:grid;gap:1rem;padding:1rem}.smartGrid-container ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-underline{bottom:0}.smartGridContent{width:100%;flex:1;overflow:auto}.blocked{position:absolute;width:calc(100% - 3rem);height:calc(100% - 3rem);z-index:110;background-color:#0003}.smart-grid-table-container{display:flex;flex-direction:column;gap:1rem}.smart-grid-toolbar{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.smart-grid-toolbar smart-ui-action-toolbar{width:100%}.smart-grid-edit-icon{color:var(--light-gray)}.tree-button{width:24px!important;height:24px!important}.paginator-row-material{display:flex;align-items:center;align-self:flex-end;gap:.25rem}.clickable-row{cursor:pointer}\n"], dependencies: [{ kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"] }, { kind: "component", type: MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: ExpandableSectionComponent, selector: "smart-expandable-section", inputs: ["data", "index"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SmartGridCardComponent, selector: "app-smart-grid-card", inputs: ["item", "smartGrid", "parentLayoutComponent"] }, { kind: "component", type: MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "directive", type: MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "directive", type: MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }] }); }
18784
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: SmartGridComponent, isStandalone: true, selector: "smart-grid", inputs: { smartGrid: { classPropertyName: "smartGrid", publicName: "smartGrid", isSignal: false, isRequired: false, transformFunction: null }, uuid: { classPropertyName: "uuid", publicName: "uuid", isSignal: false, isRequired: false, transformFunction: null }, parentLayoutComponent: { classPropertyName: "parentLayoutComponent", publicName: "parentLayoutComponent", isSignal: true, isRequired: false, transformFunction: null }, dev: { classPropertyName: "dev", publicName: "dev", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-testid": "this.testId" } }, providers: [SmartGridService], viewQueries: [{ propertyName: "vcRefTable", first: true, predicate: ["table"], descendants: true, read: ViewContainerRef }, { propertyName: "expandedRowsComps", predicate: ExpandedRowRendererComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (smartGrid) {\n<div class=\"smartGrid-container\">\n <div class=\"smart-grid-toolbar\">\n <smart-ui-action-toolbar [id]=\"toolbarId\"></smart-ui-action-toolbar>\n @if (smartGrid.showEditColumns) {\n <ui-action-button (actionClick)=\"editColumns()\" [descriptor]=\"showEditColumns\">\n </ui-action-button>\n }\n </div>\n <!-- <div [ngClass]=\"isBlocked ? 'blocked' : ''\"></div> -->\n <div class=\"smartGridContent\">\n <div>\n @if (smartGrid.showResultCount) {\n <div>\n <div class=\"smartGrid-data-number\">\n {{ smartGrid.gridModel.totalRowCount }}\n </div>\n </div>\n }\n </div>\n <div class=\"smart-grid-table-container\">\n <ng-template #table></ng-template>\n </div>\n @if (smartGrid.layoutDef === layoutDef().EXPANDABLE) {\n <div>\n @for (expandableSection of expandableSections; track expandableSection) {\n <smart-expandable-section #gridExpandableSection [data]=\"expandableSection\"></smart-expandable-section>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().CARD && smartGrid.dataLayoutDef) {\n <div class=\"cards-container\" [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\">\n @for (row of smartGrid.gridModel.page.rows; track row.id) {\n <app-smart-grid-card class=\"smartGrid-card-container\" [class.clickable-row]=\"row.layoutDescriptor\"\n (click)=\"row.layoutDescriptor && onClick(row)\" [item]=\"row\" [smartGrid]=\"smartGrid\"\n [parentLayoutComponent]=\"parentLayoutComponent()\"></app-smart-grid-card>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().TREE && treeControl) {\n <div class=\"tree-container\" [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\">\n <mat-tree [dataSource]=\"treeDataSource!\" [treeControl]=\"treeControl!\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodeToggle matTreeNodePadding matTreeNodePaddingIndent=\"24\">\n <button mat-icon-button disabled class=\"tree-button\"></button>\n <mat-checkbox class=\"checklist-leaf-node\"\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n (change)=\"treeNodeSelectionToggle(node)\">{{ getTreeItem(node) }}</mat-checkbox>\n </mat-tree-node>\n <mat-tree-node *matTreeNodeDef=\"let node; when: hasChild\" matTreeNodePadding matTreeNodePaddingIndent=\"24\">\n <button mat-icon-button matTreeNodeToggle class=\"tree-button\" [attr.aria-label]=\"'Toggle ' + node.item\">\n <mat-icon class=\"mat-icon-rtl-mirror\">\n {{ treeControl!.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <mat-checkbox [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n [indeterminate]=\"descendantsPartiallySelected(node)\" (change)=\"treeNodeSelectionToggle(node)\">{{\n getTreeItem(node) }}</mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n }\n </div>\n @if (smartGrid.paginator) {\n <div class=\"paginator-row-material\">\n @if (smartGrid.gridModel.refreshEnabled) {\n <button mat-icon-button type=\"button\" matTooltip=\"Friss\u00EDt\u00E9s\" (click)=\"refreshPartialResults()\">\n <mat-icon>refresh</mat-icon>\n </button>\n }\n @if (smartGrid.paginator && !treeControl) {\n <mat-paginator #paginator [length]=\"length\" [pageIndex]=\"pageIndex\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" (page)=\"onChangePage($event)\"></mat-paginator>\n }\n </div>\n }\n</div>\n}", styles: [".smartGrid-container{position:relative;padding:1.5rem;display:flex;flex-direction:column;gap:1rem}.smartGrid-data-number{padding-bottom:1rem}.cards-container{display:grid;gap:1rem;padding:1rem}.smartGrid-container ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-underline{bottom:0}.smartGridContent{width:100%;flex:1;overflow:auto}.blocked{position:absolute;width:calc(100% - 3rem);height:calc(100% - 3rem);z-index:110;background-color:#0003}.smart-grid-table-container{display:flex;flex-direction:column;gap:1rem}.smart-grid-toolbar{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.smart-grid-toolbar smart-ui-action-toolbar{width:100%}.smart-grid-edit-icon{color:var(--light-gray)}.tree-button{width:24px!important;height:24px!important}.paginator-row-material{display:flex;align-items:center;align-self:flex-end;gap:.25rem}.clickable-row{cursor:pointer}\n"], dependencies: [{ kind: "component", type: UiActionToolbarComponent, selector: "smart-ui-action-toolbar", inputs: ["uiActionModels", "uiActionDescriptorService", "id", "executor", "widgetId", "nodeId", "actionParams", "scrollOnWrap", "toolbarPropertes"] }, { kind: "component", type: UiActionButtonComponent, selector: "ui-action-button", inputs: ["disabled", "descriptor", "code", "identifier", "viewActivated", "addedCssClass", "addBasicClasses", "iconPlaceholder"], outputs: ["actionClick", "actionDoubleClick"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: ExpandableSectionComponent, selector: "smart-expandable-section", inputs: ["data", "index"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SmartGridCardComponent, selector: "app-smart-grid-card", inputs: ["item", "smartGrid", "parentLayoutComponent"] }, { kind: "component", type: MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "directive", type: MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "directive", type: MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }] }); }
18435
18785
  }
18436
18786
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartGridComponent, decorators: [{
18437
18787
  type: Component,
18438
- args: [{ selector: 'smart-grid', providers: [SmartGridService], imports: [UiActionToolbarComponent, MatMiniFabButton, MatIcon, ExpandableSectionComponent, NgStyle, SmartGridCardComponent, MatTree, MatTreeNodeDef, MatTreeNode, MatTreeNodeToggle, MatTreeNodePadding, MatIconButton, MatCheckbox, MatTooltip, MatPaginator], template: "@if (smartGrid) {\n <div class=\"smartGrid-container\">\n <div class=\"smart-grid-toolbar\">\n <smart-ui-action-toolbar [id]=\"toolbarId\"></smart-ui-action-toolbar>\n @if (smartGrid.showEditColumns) {\n <button\n (click)=\"editColumns()\"\n mat-mini-fab\n color=\"text-primary\"\n >\n <mat-icon aria-hidden=\"false\" aria-label=\"Columns\" class=\"smart-grid-edit-icon\"\n >view_columns</mat-icon\n >\n </button>\n }\n </div>\n <!-- <div [ngClass]=\"isBlocked ? 'blocked' : ''\"></div> -->\n <div class=\"smartGridContent\">\n <div>\n @if (smartGrid.showResultCount) {\n <div>\n <div class=\"smartGrid-data-number\">\n {{ smartGrid.gridModel.totalRowCount }}\n </div>\n </div>\n }\n </div>\n <div class=\"smart-grid-table-container\">\n <ng-template #table></ng-template>\n </div>\n @if (smartGrid.layoutDef === layoutDef().EXPANDABLE) {\n <div>\n @for (expandableSection of expandableSections; track expandableSection) {\n <smart-expandable-section\n #gridExpandableSection\n [data]=\"expandableSection\"\n ></smart-expandable-section>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().CARD && smartGrid.dataLayoutDef) {\n <div\n class=\"cards-container\"\n [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\"\n >\n @for (row of smartGrid.gridModel.page.rows; track row.id) {\n <app-smart-grid-card\n class=\"smartGrid-card-container\"\n [class.clickable-row]=\"row.layoutDescriptor\"\n (click)=\"row.layoutDescriptor && onClick(row)\"\n [item]=\"row\"\n [smartGrid]=\"smartGrid\"\n [parentLayoutComponent]=\"parentLayoutComponent()\"\n ></app-smart-grid-card>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().TREE && treeControl) {\n <div\n class=\"tree-container\"\n [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\"\n >\n <mat-tree [dataSource]=\"treeDataSource!\" [treeControl]=\"treeControl!\">\n <mat-tree-node\n *matTreeNodeDef=\"let node\"\n matTreeNodeToggle\n matTreeNodePadding\n matTreeNodePaddingIndent=\"24\"\n >\n <button mat-icon-button disabled class=\"tree-button\"></button>\n <mat-checkbox\n class=\"checklist-leaf-node\"\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n (change)=\"treeNodeSelectionToggle(node)\"\n >{{ getTreeItem(node) }}</mat-checkbox\n >\n </mat-tree-node>\n <mat-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n matTreeNodePadding\n matTreeNodePaddingIndent=\"24\"\n >\n <button\n mat-icon-button\n matTreeNodeToggle\n class=\"tree-button\"\n [attr.aria-label]=\"'Toggle ' + node.item\"\n >\n <mat-icon class=\"mat-icon-rtl-mirror\">\n {{ treeControl!.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <mat-checkbox\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n [indeterminate]=\"descendantsPartiallySelected(node)\"\n (change)=\"treeNodeSelectionToggle(node)\"\n >{{ getTreeItem(node) }}</mat-checkbox\n >\n </mat-tree-node>\n </mat-tree>\n </div>\n }\n </div>\n @if (smartGrid.paginator) {\n <div class=\"paginator-row-material\">\n @if (smartGrid.gridModel.refreshEnabled) {\n <button mat-icon-button type=\"button\" matTooltip=\"Friss\u00EDt\u00E9s\" (click)=\"refreshPartialResults()\">\n <mat-icon>refresh</mat-icon>\n </button>\n }\n @if (smartGrid.paginator && !treeControl) {\n <mat-paginator\n #paginator\n [length]=\"length\"\n [pageIndex]=\"pageIndex\"\n [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\"\n (page)=\"onChangePage($event)\"\n ></mat-paginator>\n }\n </div>\n }\n </div>\n }\n", styles: [".smartGrid-container{position:relative;padding:1.5rem;display:flex;flex-direction:column;gap:1rem}.smartGrid-data-number{padding-bottom:1rem}.cards-container{display:grid;gap:1rem;padding:1rem}.smartGrid-container ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-underline{bottom:0}.smartGridContent{width:100%;flex:1;overflow:auto}.blocked{position:absolute;width:calc(100% - 3rem);height:calc(100% - 3rem);z-index:110;background-color:#0003}.smart-grid-table-container{display:flex;flex-direction:column;gap:1rem}.smart-grid-toolbar{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.smart-grid-toolbar smart-ui-action-toolbar{width:100%}.smart-grid-edit-icon{color:var(--light-gray)}.tree-button{width:24px!important;height:24px!important}.paginator-row-material{display:flex;align-items:center;align-self:flex-end;gap:.25rem}.clickable-row{cursor:pointer}\n"] }]
18788
+ args: [{ selector: 'smart-grid', providers: [SmartGridService], imports: [UiActionToolbarComponent, UiActionButtonComponent, MatMiniFabButton, MatIcon, ExpandableSectionComponent, NgStyle, SmartGridCardComponent, MatTree, MatTreeNodeDef, MatTreeNode, MatTreeNodeToggle, MatTreeNodePadding, MatIconButton, MatCheckbox, MatTooltip, MatPaginator], template: "@if (smartGrid) {\n<div class=\"smartGrid-container\">\n <div class=\"smart-grid-toolbar\">\n <smart-ui-action-toolbar [id]=\"toolbarId\"></smart-ui-action-toolbar>\n @if (smartGrid.showEditColumns) {\n <ui-action-button (actionClick)=\"editColumns()\" [descriptor]=\"showEditColumns\">\n </ui-action-button>\n }\n </div>\n <!-- <div [ngClass]=\"isBlocked ? 'blocked' : ''\"></div> -->\n <div class=\"smartGridContent\">\n <div>\n @if (smartGrid.showResultCount) {\n <div>\n <div class=\"smartGrid-data-number\">\n {{ smartGrid.gridModel.totalRowCount }}\n </div>\n </div>\n }\n </div>\n <div class=\"smart-grid-table-container\">\n <ng-template #table></ng-template>\n </div>\n @if (smartGrid.layoutDef === layoutDef().EXPANDABLE) {\n <div>\n @for (expandableSection of expandableSections; track expandableSection) {\n <smart-expandable-section #gridExpandableSection [data]=\"expandableSection\"></smart-expandable-section>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().CARD && smartGrid.dataLayoutDef) {\n <div class=\"cards-container\" [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\">\n @for (row of smartGrid.gridModel.page.rows; track row.id) {\n <app-smart-grid-card class=\"smartGrid-card-container\" [class.clickable-row]=\"row.layoutDescriptor\"\n (click)=\"row.layoutDescriptor && onClick(row)\" [item]=\"row\" [smartGrid]=\"smartGrid\"\n [parentLayoutComponent]=\"parentLayoutComponent()\"></app-smart-grid-card>\n }\n </div>\n }\n @if (smartGrid.layoutDef === layoutDef().TREE && treeControl) {\n <div class=\"tree-container\" [ngStyle]=\"{\n 'grid-template-columns':\n smartGrid.numberOfColumn !== undefined\n ? 'repeat(' + smartGrid.numberOfColumn + ', 1fr)'\n : '',\n }\">\n <mat-tree [dataSource]=\"treeDataSource!\" [treeControl]=\"treeControl!\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodeToggle matTreeNodePadding matTreeNodePaddingIndent=\"24\">\n <button mat-icon-button disabled class=\"tree-button\"></button>\n <mat-checkbox class=\"checklist-leaf-node\"\n [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n (change)=\"treeNodeSelectionToggle(node)\">{{ getTreeItem(node) }}</mat-checkbox>\n </mat-tree-node>\n <mat-tree-node *matTreeNodeDef=\"let node; when: hasChild\" matTreeNodePadding matTreeNodePaddingIndent=\"24\">\n <button mat-icon-button matTreeNodeToggle class=\"tree-button\" [attr.aria-label]=\"'Toggle ' + node.item\">\n <mat-icon class=\"mat-icon-rtl-mirror\">\n {{ treeControl!.isExpanded(node) ? 'expand_more' : 'chevron_right' }}\n </mat-icon>\n </button>\n <mat-checkbox [checked]=\"$safeNavigationMigration(treeChecklistSelection?.isSelected(node))\"\n [indeterminate]=\"descendantsPartiallySelected(node)\" (change)=\"treeNodeSelectionToggle(node)\">{{\n getTreeItem(node) }}</mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n }\n </div>\n @if (smartGrid.paginator) {\n <div class=\"paginator-row-material\">\n @if (smartGrid.gridModel.refreshEnabled) {\n <button mat-icon-button type=\"button\" matTooltip=\"Friss\u00EDt\u00E9s\" (click)=\"refreshPartialResults()\">\n <mat-icon>refresh</mat-icon>\n </button>\n }\n @if (smartGrid.paginator && !treeControl) {\n <mat-paginator #paginator [length]=\"length\" [pageIndex]=\"pageIndex\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" (page)=\"onChangePage($event)\"></mat-paginator>\n }\n </div>\n }\n</div>\n}", styles: [".smartGrid-container{position:relative;padding:1.5rem;display:flex;flex-direction:column;gap:1rem}.smartGrid-data-number{padding-bottom:1rem}.cards-container{display:grid;gap:1rem;padding:1rem}.smartGrid-container ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-underline{bottom:0}.smartGridContent{width:100%;flex:1;overflow:auto}.blocked{position:absolute;width:calc(100% - 3rem);height:calc(100% - 3rem);z-index:110;background-color:#0003}.smart-grid-table-container{display:flex;flex-direction:column;gap:1rem}.smart-grid-toolbar{display:flex;flex-direction:row;justify-content:flex-end;align-items:center}.smart-grid-toolbar smart-ui-action-toolbar{width:100%}.smart-grid-edit-icon{color:var(--light-gray)}.tree-button{width:24px!important;height:24px!important}.paginator-row-material{display:flex;align-items:center;align-self:flex-end;gap:.25rem}.clickable-row{cursor:pointer}\n"] }]
18439
18789
  }], ctorParameters: () => [], propDecorators: { smartGrid: [{
18440
18790
  type: Input
18441
18791
  }], uuid: [{
@@ -22391,7 +22741,6 @@ class GenericPageComponent extends SmartComponent {
22391
22741
  /** Written from `dataChanged`, so a signal — the page has no template event that would. */
22392
22742
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
22393
22743
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
22394
- this.sendModelOnWidgetAction = true;
22395
22744
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
22396
22745
  if (this.model?.componentLayouts) {
22397
22746
  this.setUpComponentLayout();
@@ -22453,7 +22802,6 @@ class SearchPageComponent extends SmartComponent {
22453
22802
  this.layoutComponent = viewChild(SmartComponentLayoutComponent, /* @ts-ignore */
22454
22803
  ...(ngDevMode ? [{ debugName: "layoutComponent" }] : /* istanbul ignore next */ []));
22455
22804
  this.setupGrid();
22456
- this.sendModelOnWidgetAction = true;
22457
22805
  // uuid is set in onUuidResolved — it is not known at construction for
22458
22806
  // dynamic default-component views. (#28870)
22459
22807
  this.filterService.config = {
@@ -23374,7 +23722,6 @@ class NoPermissionPageComponent extends SmartComponent {
23374
23722
  /** Written from `dataChanged`, so a signal. */
23375
23723
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
23376
23724
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
23377
- this.sendModelOnWidgetAction = true;
23378
23725
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
23379
23726
  if (this.model?.componentLayouts) {
23380
23727
  this.setUpComponentLayout();
@@ -23416,7 +23763,6 @@ class InvalidSmartlinkComponent extends SmartComponent {
23416
23763
  /** Written from `dataChanged`, so a signal. */
23417
23764
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
23418
23765
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
23419
- this.sendModelOnWidgetAction = true;
23420
23766
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
23421
23767
  if (this.model?.componentLayouts) {
23422
23768
  this.setUpComponentLayout();