@smartbit4all/ng-client 7.0.10 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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;
6810
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;
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);
@@ -11263,6 +11457,12 @@ class Table {
11263
11457
  // ---- Toolbar ----
11264
11458
  this.defaultActionToolbarId = SmartGridToolbarActionsUtil.defaultActionToolbarId;
11265
11459
  this.rowMenuActionModelArrayCache = new Map();
11460
+ // ------------- TREE_GRID -------------
11461
+ this.expandedRowIds = new Set();
11462
+ this.visibleRows = [];
11463
+ this.rowsById = new Map();
11464
+ this.isTreeGrid = false;
11465
+ this.treeInitialized = false;
11266
11466
  }
11267
11467
  /** The address of the toolbar in this grid's header; `undefined` while it has no id. */
11268
11468
  get headerToolbarId() {
@@ -11295,6 +11495,7 @@ class Table {
11295
11495
  if (this.smartTable.sortable)
11296
11496
  this.sortEvent = new Subject();
11297
11497
  this.createCellToActionMap();
11498
+ this.calcTree();
11298
11499
  }
11299
11500
  ngOnDestroy() {
11300
11501
  this._destroy$.next();
@@ -11324,6 +11525,7 @@ class Table {
11324
11525
  this.smartTable = smartTable;
11325
11526
  // Pushed in by the grid rather than read from it, so nothing else marks this view. The
11326
11527
  // pull the rest of the library moved to (ADR-0005) is the 7.1 grid/table merge.
11528
+ this.calcTree();
11327
11529
  this.changeDetector.markForCheck();
11328
11530
  this.renderRows();
11329
11531
  }
@@ -11814,6 +12016,143 @@ class Table {
11814
12016
  shouldShowMenuButton(row) {
11815
12017
  return SmartGridToolbarActionsUtil.showMenu(row, this.smartTable.tableHeaders);
11816
12018
  }
12019
+ initializeExpandedRows(rows) {
12020
+ if (this.treeInitialized) {
12021
+ return;
12022
+ }
12023
+ rows.forEach(row => {
12024
+ if (row.id && row.children?.length) {
12025
+ this.expandedRowIds.add(row.id);
12026
+ }
12027
+ });
12028
+ this.treeInitialized = true;
12029
+ }
12030
+ calcTree() {
12031
+ const rows = this.smartTable.tableRows ?? [];
12032
+ this.isTreeGrid = rows.some(row => !!row?.children?.length || !!row?.parent);
12033
+ if (!this.isTreeGrid) {
12034
+ this.visibleRows = rows;
12035
+ return;
12036
+ }
12037
+ // Open all rows on first tree initialization.
12038
+ this.initializeExpandedRows(rows);
12039
+ this.rowsById.clear();
12040
+ rows.forEach(row => {
12041
+ if (row.id) {
12042
+ this.rowsById.set(row.id, row);
12043
+ }
12044
+ });
12045
+ const roots = rows.filter(row => !row.parent);
12046
+ const result = [];
12047
+ const walk = (row) => {
12048
+ result.push(row);
12049
+ if (row.id &&
12050
+ row.children?.length &&
12051
+ this.expandedRowIds.has(row.id)) {
12052
+ row.children
12053
+ .map(childId => this.rowsById.get(childId))
12054
+ .filter((child) => !!child)
12055
+ .forEach(child => walk(child));
12056
+ }
12057
+ };
12058
+ roots.forEach(root => walk(root));
12059
+ this.visibleRows = result;
12060
+ }
12061
+ hasChildren(row) {
12062
+ return !!row?.children?.length;
12063
+ }
12064
+ isRowExpanded(row) {
12065
+ return !!row?.id && this.expandedRowIds.has(row.id);
12066
+ }
12067
+ toggleRowExpansion(row, event) {
12068
+ event?.stopPropagation();
12069
+ if (!row?.id) {
12070
+ return;
12071
+ }
12072
+ if (this.expandedRowIds.has(row.id)) {
12073
+ this.expandedRowIds.delete(row.id);
12074
+ }
12075
+ else {
12076
+ this.expandedRowIds.add(row.id);
12077
+ }
12078
+ this.calcTree();
12079
+ }
12080
+ canExpand() {
12081
+ return this.visibleRows.some(row => this.hasChildren(row) && !this.isRowExpanded(row));
12082
+ }
12083
+ canCollapse() {
12084
+ return this.expandedRowIds.size > 0;
12085
+ }
12086
+ expandOneLevel() {
12087
+ let changed = false;
12088
+ for (const row of this.visibleRows) {
12089
+ if (row.id && this.hasChildren(row) && !this.expandedRowIds.has(row.id)) {
12090
+ this.expandedRowIds.add(row.id);
12091
+ changed = true;
12092
+ }
12093
+ }
12094
+ if (changed) {
12095
+ this.calcTree();
12096
+ }
12097
+ }
12098
+ collapseOneLevel() {
12099
+ let maxLevel = -1;
12100
+ for (const row of this.visibleRows) {
12101
+ if (row.id && this.expandedRowIds.has(row.id)) {
12102
+ maxLevel = Math.max(maxLevel, row.level ?? 0);
12103
+ }
12104
+ }
12105
+ if (maxLevel < 0) {
12106
+ return;
12107
+ }
12108
+ let changed = false;
12109
+ for (const row of this.visibleRows) {
12110
+ if (row.id && this.expandedRowIds.has(row.id) && (row.level ?? 0) === maxLevel) {
12111
+ this.expandedRowIds.delete(row.id);
12112
+ changed = true;
12113
+ }
12114
+ }
12115
+ if (changed) {
12116
+ this.calcTree();
12117
+ }
12118
+ }
12119
+ expandAll() {
12120
+ let changed = false;
12121
+ (this.smartTable.tableRows ?? []).forEach(row => {
12122
+ if (row.id && this.hasChildren(row) && !this.expandedRowIds.has(row.id)) {
12123
+ this.expandedRowIds.add(row.id);
12124
+ changed = true;
12125
+ }
12126
+ });
12127
+ if (changed) {
12128
+ this.calcTree();
12129
+ }
12130
+ }
12131
+ collapseAll() {
12132
+ if (this.expandedRowIds.size === 0) {
12133
+ return;
12134
+ }
12135
+ this.expandedRowIds.clear();
12136
+ this.calcTree();
12137
+ }
12138
+ get expandTreeGridLevel() {
12139
+ return {
12140
+ title: '',
12141
+ color: 'primary',
12142
+ type: UiActionButtonType.MINI_FAB,
12143
+ icon: 'add',
12144
+ iconPosition: IconPosition.PRE,
12145
+ };
12146
+ }
12147
+ get closeTreeGridLevel() {
12148
+ return {
12149
+ title: '',
12150
+ color: 'primary',
12151
+ type: UiActionButtonType.MINI_FAB,
12152
+ icon: 'remove',
12153
+ iconPosition: IconPosition.PRE,
12154
+ };
12155
+ }
11817
12156
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: Table, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11818
12157
  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
12158
  }
@@ -11874,11 +12213,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
11874
12213
 
11875
12214
  class MaterialTableComponent extends Table {
11876
12215
  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" }] }); }
12216
+ 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
12217
  }
11879
12218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MaterialTableComponent, decorators: [{
11880
12219
  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"] }]
12220
+ 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
12221
  }] });
11883
12222
 
11884
12223
  class MobileTableComponent extends Table {
@@ -15606,11 +15945,11 @@ class SmarttreeGenericService extends SmarttreeService {
15606
15945
  let nodeId = uiActionRequest.params['nodeUuid'];
15607
15946
  delete uiActionRequest.params['nodeUuid'];
15608
15947
  let viewUuid = this.viewContext.getUuidOfPage(this.pageName);
15609
- this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.service.performAction2(viewUuid, this.treeId, nodeId, uiActionRequest).toPromise());
15948
+ this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.viewContext.withModelSync(uiActionRequest, (request) => this.service.performAction2(viewUuid, this.treeId, nodeId, request).toPromise()));
15610
15949
  }
15611
15950
  async performMainUiActionRequest(uiActionRequest) {
15612
15951
  let viewUuid = this.viewContext.getUuidOfPage(this.pageName);
15613
- this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.service.performMainAction2(viewUuid, this.treeId, uiActionRequest).toPromise());
15952
+ this.treeFromBackend = await this.viewContext.handlePerformActionResponse(await this.viewContext.withModelSync(uiActionRequest, (request) => this.service.performMainAction2(viewUuid, this.treeId, request).toPromise()));
15614
15953
  }
15615
15954
  handleSpecificDemandsAsynchronously(uiAction, uiActionRequest) {
15616
15955
  throw new Error('Method not implemented.');
@@ -15652,11 +15991,13 @@ class SmartComponentApiClient {
15652
15991
  }
15653
15992
  if (this.uuid) {
15654
15993
  this.viewContext.unfollow(this.uuid);
15994
+ this.viewContext.leaveModelSync(this.uuid, this);
15655
15995
  }
15656
15996
  this.uuidState.set(uuid);
15657
15997
  // Widgets read `widgetUuid` themselves; nothing is pushed into them from here. (ADR-0005)
15658
15998
  if (uuid) {
15659
15999
  this.viewContext.follow(this.uuid, this.detectChange);
16000
+ this.viewContext.joinModelSync(this.uuid, this);
15660
16001
  this.onUuidResolved(uuid);
15661
16002
  }
15662
16003
  }
@@ -15746,7 +16087,6 @@ class SmartComponentApiClient {
15746
16087
  */
15747
16088
  this.commands = new Subject();
15748
16089
  this.dataChanged = new Subject();
15749
- this.sendModelOnWidgetAction = false;
15750
16090
  this.inmediateDataChangeKeys = [];
15751
16091
  this.blurDataChangeKeys = [];
15752
16092
  // check and calculate pageName
@@ -15783,6 +16123,7 @@ class SmartComponentApiClient {
15783
16123
  }
15784
16124
  _ngOnDestroy() {
15785
16125
  this.viewContext.unfollow(this.uuid);
16126
+ this.viewContext.leaveModelSync(this.uuid, this);
15786
16127
  this._destroy$.next();
15787
16128
  this._destroy$.complete();
15788
16129
  }
@@ -15868,6 +16209,7 @@ class SmartComponentApiClient {
15868
16209
  // grids are already loaded in setUuid()
15869
16210
  this.handleChangeWidgets(this.model.widgets, true);
15870
16211
  }
16212
+ this.viewContext.markModelSynced(uuid);
15871
16213
  }
15872
16214
  async executeUiAction(uiAction, options) {
15873
16215
  const uiActionModel = {
@@ -15894,7 +16236,7 @@ class SmartComponentApiClient {
15894
16236
  }
15895
16237
  let blurIdx = this.blurDataChangeKeys.indexOf(key);
15896
16238
  if (blurIdx >= 0) {
15897
- this.inmediateDataChangeKeys.splice(blurIdx, 1);
16239
+ this.blurDataChangeKeys.splice(blurIdx, 1);
15898
16240
  }
15899
16241
  }
15900
16242
  /**
@@ -15906,7 +16248,6 @@ class SmartComponentApiClient {
15906
16248
  if (changeKeys.includes(event.key)) {
15907
16249
  this.executeUiAction({
15908
16250
  code: event.key,
15909
- model: true,
15910
16251
  params: {
15911
16252
  item: event.value,
15912
16253
  },
@@ -15952,7 +16293,6 @@ class SmartComponentApiClient {
15952
16293
  delete uiActionRequest.params['_files'];
15953
16294
  delete uiActionRequest.params['_uploadDescriptor'];
15954
16295
  delete uiActionRequest.params['isMultiple'];
15955
- // await this.sendModelToServer();
15956
16296
  if (!isMultiple) {
15957
16297
  await this.viewContext.performUploadAction(this.uuid, uiActionRequest, param, files[0]);
15958
16298
  }
@@ -15992,38 +16332,15 @@ class SmartComponentApiClient {
15992
16332
  }
15993
16333
  }
15994
16334
  else if (widgetId && nodeId) {
15995
- // await this.sendModelToServer();
15996
- this.addModelToWidgetAction(uiActionRequest);
15997
16335
  await this.viewContext.performWidgetAction(this.uuid, widgetId, nodeId, uiActionRequest);
15998
16336
  }
15999
16337
  else if (widgetId) {
16000
- // await this.sendModelToServer();
16001
- this.addModelToWidgetAction(uiActionRequest);
16002
16338
  await this.viewContext.performWidgetMainAction(this.uuid, widgetId, uiActionRequest);
16003
16339
  }
16004
16340
  else {
16005
16341
  await this.viewContext.performAction(this.uuid, uiActionRequest);
16006
16342
  }
16007
16343
  }
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
16344
  handleSpecificDemandsAsynchronously(uiAction, uiActionRequest) {
16028
16345
  throw new Error('handleSpecificDemandsAsynchronously method not implemented.');
16029
16346
  }
@@ -16073,27 +16390,10 @@ class SmartComponentApiClient {
16073
16390
  return matData?.uuid;
16074
16391
  }
16075
16392
  // #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
16393
  handleChanges(change) {
16394
+ // What of the data the push wrote: the paths under `data`, or everything on a whole-model
16395
+ // replacement. Tells the view context how much of the data to take as the backend's.
16396
+ let pushedKeys = [];
16097
16397
  try {
16098
16398
  if (!this.componentModelLoaded) {
16099
16399
  // initial load
@@ -16108,6 +16408,7 @@ class SmartComponentApiClient {
16108
16408
  Object.keys(changes).map((changeKey) => {
16109
16409
  if (changeKey.startsWith('data.')) {
16110
16410
  this.handleDataChange(changes, changeKey);
16411
+ pushedKeys?.push(changeKey.substring('data.'.length));
16111
16412
  }
16112
16413
  else if (changeKey.startsWith('layouts.') && this.model?.layouts) {
16113
16414
  this.handleLayoutChange(changes, changeKey);
@@ -16127,6 +16428,7 @@ class SmartComponentApiClient {
16127
16428
  else if (changeKey === '') {
16128
16429
  this.model = changes[''];
16129
16430
  dataChangeHasBeenNexted = true;
16431
+ pushedKeys = undefined;
16130
16432
  }
16131
16433
  });
16132
16434
  if (!dataChangeHasBeenNexted) {
@@ -16137,9 +16439,14 @@ class SmartComponentApiClient {
16137
16439
  catch (error) {
16138
16440
  console.error(error);
16139
16441
  this.model = change.value;
16442
+ pushedKeys = undefined;
16140
16443
  }
16141
16444
  if (!change.changedWidgets && !change.changes && change.value) {
16142
16445
  this.model = change.value;
16446
+ pushedKeys = undefined;
16447
+ }
16448
+ if (pushedKeys === undefined || pushedKeys.length) {
16449
+ this.viewContext.markModelSynced(this.uuid, pushedKeys);
16143
16450
  }
16144
16451
  }
16145
16452
  /**
@@ -16293,6 +16600,7 @@ var SmartLayoutDef;
16293
16600
  SmartLayoutDef["EXPANDABLE"] = "EXPANDABLE";
16294
16601
  SmartLayoutDef["CARD"] = "CARD";
16295
16602
  SmartLayoutDef["TREE"] = "TREE";
16603
+ SmartLayoutDef["TREE_GRID"] = "TREE_GRID";
16296
16604
  })(SmartLayoutDef || (SmartLayoutDef = {}));
16297
16605
  var SmartGridButtonType;
16298
16606
  (function (SmartGridButtonType) {
@@ -16996,18 +17304,6 @@ var GridDataAccessConfigKindEnum;
16996
17304
  })(GridDataAccessConfigKindEnum || (GridDataAccessConfigKindEnum = {}));
16997
17305
  ;
16998
17306
 
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
17307
  /**
17012
17308
  * Grid api
17013
17309
  * The grid api is resposible for the grid components that shows a list of item.
@@ -17048,9 +17344,46 @@ var GridViewDescriptorKindEnum;
17048
17344
  GridViewDescriptorKindEnum["TABLE"] = "TABLE";
17049
17345
  GridViewDescriptorKindEnum["CARDS"] = "CARDS";
17050
17346
  GridViewDescriptorKindEnum["TREE"] = "TREE";
17347
+ GridViewDescriptorKindEnum["TREE_GRID"] = "TREE_GRID";
17051
17348
  })(GridViewDescriptorKindEnum || (GridViewDescriptorKindEnum = {}));
17052
17349
  ;
17053
17350
 
17351
+ class ApiModule {
17352
+ static forRoot(configurationFactory) {
17353
+ return {
17354
+ ngModule: ApiModule,
17355
+ providers: [{ provide: Configuration$2, useFactory: configurationFactory }]
17356
+ };
17357
+ }
17358
+ constructor(parentModule, http) {
17359
+ if (parentModule) {
17360
+ throw new Error('ApiModule is already loaded. Import in your base AppModule only.');
17361
+ }
17362
+ if (!http) {
17363
+ throw new Error('You need to import the HttpClientModule in your AppModule! \n' +
17364
+ 'See also https://github.com/angular/angular/issues/20575');
17365
+ }
17366
+ }
17367
+ 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 }); }
17368
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: ApiModule }); }
17369
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ApiModule }); }
17370
+ }
17371
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ApiModule, decorators: [{
17372
+ type: NgModule,
17373
+ args: [{
17374
+ imports: [],
17375
+ declarations: [],
17376
+ exports: [],
17377
+ providers: []
17378
+ }]
17379
+ }], ctorParameters: () => [{ type: ApiModule, decorators: [{
17380
+ type: Optional
17381
+ }, {
17382
+ type: SkipSelf
17383
+ }] }, { type: i1.HttpClient, decorators: [{
17384
+ type: Optional
17385
+ }] }] });
17386
+
17054
17387
  class TableLayoutDefinerComponent {
17055
17388
  constructor() {
17056
17389
  this.data = inject(MAT_DIALOG_DATA);
@@ -17236,6 +17569,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
17236
17569
  args: ['forms']
17237
17570
  }] } });
17238
17571
 
17572
+ /** The model sync carrier of a selection call; the view context puts the envelope on it. */
17573
+ function selection(selected, unselected) {
17574
+ return { selected, unselected, params: {} };
17575
+ }
17239
17576
  class SmartGridService {
17240
17577
  constructor() {
17241
17578
  this.api = inject(GridService);
@@ -17273,27 +17610,19 @@ class SmartGridService {
17273
17610
  }
17274
17611
  async select(smartGrid, gridRow) {
17275
17612
  gridRow.selected = !gridRow.selected;
17276
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, [], []);
17277
- return await this.api
17613
+ return await smartGrid.viewContextService.withModelSync(selection([], []), (gridSelectionChange) => this.api
17278
17614
  .select(smartGrid.gridModel.viewUuid, smartGrid.gridIdentifier, gridRow.id, gridRow.selected, gridSelectionChange)
17279
- .toPromise();
17615
+ .toPromise());
17280
17616
  }
17281
17617
  async selectRows(smartGrid, selected, unselected) {
17282
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, selected, unselected);
17283
- return await this.api
17618
+ return await smartGrid.viewContextService.withModelSync(selection(selected, unselected), (gridSelectionChange) => this.api
17284
17619
  .selectRows(smartGrid.gridModel.viewUuid, smartGrid.gridIdentifier, gridSelectionChange)
17285
- .toPromise();
17620
+ .toPromise());
17286
17621
  }
17287
17622
  async selectAll(smartGrid, selected) {
17288
- const gridSelectionChange = this.buildGridSelectionChange(smartGrid, [], []);
17289
- return await this.api
17623
+ return await smartGrid.viewContextService.withModelSync(selection([], []), (gridSelectionChange) => this.api
17290
17624
  .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;
17625
+ .toPromise());
17297
17626
  }
17298
17627
  async update(uuid, identifier, updateData) {
17299
17628
  if (!updateData.pageSize) {
@@ -17838,6 +18167,9 @@ class SmartGridComponent {
17838
18167
  if (kind === GridViewDescriptorKindEnum.TABLE) {
17839
18168
  layoutDef = SmartLayoutDef.TABLE;
17840
18169
  }
18170
+ else if (kind === GridViewDescriptorKindEnum.TREE_GRID) {
18171
+ layoutDef = SmartLayoutDef.TREE_GRID;
18172
+ }
17841
18173
  else if (kind === GridViewDescriptorKindEnum.TREE) {
17842
18174
  layoutDef = SmartLayoutDef.TREE;
17843
18175
  }
@@ -17863,6 +18195,9 @@ class SmartGridComponent {
17863
18195
  if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE) {
17864
18196
  this.renderTable();
17865
18197
  }
18198
+ else if (this.smartGrid.layoutDef === SmartLayoutDef.TREE_GRID) {
18199
+ this.renderTable();
18200
+ }
17866
18201
  else if (this.smartGrid.layoutDef === SmartLayoutDef.EXPANDABLE) {
17867
18202
  this.renderExpandableSections();
17868
18203
  }
@@ -17900,7 +18235,7 @@ class SmartGridComponent {
17900
18235
  else {
17901
18236
  this.tableType = SmartTableType.INHERITED;
17902
18237
  }
17903
- if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE) {
18238
+ if (this.smartGrid.layoutDef === SmartLayoutDef.TABLE || this.smartGrid.layoutDef === SmartLayoutDef.TREE_GRID) {
17904
18239
  let tableConfig = {
17905
18240
  ...this.smartGrid.tableConfig,
17906
18241
  title: this.smartGrid?.gridModel.title,
@@ -18430,12 +18765,21 @@ class SmartGridComponent {
18430
18765
  };
18431
18766
  this.dialog.open(TableLayoutDefinerComponent, { data: dialogData });
18432
18767
  }
18768
+ get showEditColumns() {
18769
+ return {
18770
+ title: '',
18771
+ color: 'primary',
18772
+ type: UiActionButtonType.MINI_FAB,
18773
+ icon: 'view_columns',
18774
+ iconPosition: IconPosition.PRE,
18775
+ };
18776
+ }
18433
18777
  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"] }] }); }
18778
+ 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
18779
  }
18436
18780
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SmartGridComponent, decorators: [{
18437
18781
  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"] }]
18782
+ 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
18783
  }], ctorParameters: () => [], propDecorators: { smartGrid: [{
18440
18784
  type: Input
18441
18785
  }], uuid: [{
@@ -22391,7 +22735,6 @@ class GenericPageComponent extends SmartComponent {
22391
22735
  /** Written from `dataChanged`, so a signal — the page has no template event that would. */
22392
22736
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
22393
22737
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
22394
- this.sendModelOnWidgetAction = true;
22395
22738
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
22396
22739
  if (this.model?.componentLayouts) {
22397
22740
  this.setUpComponentLayout();
@@ -22453,7 +22796,6 @@ class SearchPageComponent extends SmartComponent {
22453
22796
  this.layoutComponent = viewChild(SmartComponentLayoutComponent, /* @ts-ignore */
22454
22797
  ...(ngDevMode ? [{ debugName: "layoutComponent" }] : /* istanbul ignore next */ []));
22455
22798
  this.setupGrid();
22456
- this.sendModelOnWidgetAction = true;
22457
22799
  // uuid is set in onUuidResolved — it is not known at construction for
22458
22800
  // dynamic default-component views. (#28870)
22459
22801
  this.filterService.config = {
@@ -23374,7 +23716,6 @@ class NoPermissionPageComponent extends SmartComponent {
23374
23716
  /** Written from `dataChanged`, so a signal. */
23375
23717
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
23376
23718
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
23377
- this.sendModelOnWidgetAction = true;
23378
23719
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
23379
23720
  if (this.model?.componentLayouts) {
23380
23721
  this.setUpComponentLayout();
@@ -23416,7 +23757,6 @@ class InvalidSmartlinkComponent extends SmartComponent {
23416
23757
  /** Written from `dataChanged`, so a signal. */
23417
23758
  this.componentLayoutState = signal(undefined, /* @ts-ignore */
23418
23759
  ...(ngDevMode ? [{ debugName: "componentLayoutState" }] : /* istanbul ignore next */ []));
23419
- this.sendModelOnWidgetAction = true;
23420
23760
  this.dataChanged.pipe(takeUntil(this._destroy$)).subscribe(() => {
23421
23761
  if (this.model?.componentLayouts) {
23422
23762
  this.setUpComponentLayout();