@smallpearl/ngx-helper 0.31.1 → 0.31.6

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,7 +1,7 @@
1
1
  import * as i1$1 from '@angular/common/http';
2
2
  import { HttpContextToken, HttpContext } from '@angular/common/http';
3
3
  import * as i0 from '@angular/core';
4
- import { InjectionToken, inject, input, signal, viewChild, ViewContainerRef, Component, ChangeDetectionStrategy, computed, viewChildren, EventEmitter, effect, ContentChildren, Output, ChangeDetectorRef } from '@angular/core';
4
+ import { InjectionToken, inject, input, computed, signal, viewChild, ViewContainerRef, Component, ChangeDetectionStrategy, viewChildren, EventEmitter, effect, ContentChildren, Output, ChangeDetectorRef } from '@angular/core';
5
5
  import * as i4 from '@angular/common';
6
6
  import { CommonModule } from '@angular/common';
7
7
  import * as i1 from '@angular/material/button';
@@ -27,7 +27,7 @@ import * as i11 from 'angular-split';
27
27
  import { AngularSplitModule } from 'angular-split';
28
28
  import { startCase } from 'lodash';
29
29
  import { plural } from 'pluralize';
30
- import { Subscription, tap, switchMap, of, map } from 'rxjs';
30
+ import { Observable, of, Subscription, firstValueFrom, tap, switchMap, map } from 'rxjs';
31
31
  import * as i1$2 from '@angular/material/toolbar';
32
32
  import { MatToolbarModule } from '@angular/material/toolbar';
33
33
  import { setServerErrorsAsFormErrors } from '@smallpearl/ngx-helper/forms';
@@ -82,6 +82,14 @@ class FormViewHostComponent {
82
82
  clientViewTemplate = input(null);
83
83
  itemLabel = input.required();
84
84
  itemLabelPlural = input.required();
85
+ _itemLabel = computed(() => {
86
+ const label = this.itemLabel();
87
+ return label instanceof Observable ? label : of(label);
88
+ });
89
+ _itemLabelPlural = computed(() => {
90
+ const label = this.itemLabelPlural();
91
+ return label instanceof Observable ? label : of(label);
92
+ });
85
93
  entity = signal(undefined);
86
94
  title = signal('');
87
95
  params = signal(undefined);
@@ -103,10 +111,17 @@ class FormViewHostComponent {
103
111
  this.title.set(params.title);
104
112
  }
105
113
  else {
114
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
115
+ this.title.set(this.transloco.translate(entity ? 'editItem' : 'newItem', {
116
+ item: itemLabel,
117
+ }));
118
+ });
106
119
  // this.title.set(entity ? this.config.i18n.editItemLabel(this.itemLabel()) : this.config.i18n.newItemLabel(this.itemLabel()));
107
- this.title.set(this.transloco.translate(entity ? 'editItem' : 'newItem', {
108
- item: this.itemLabel(),
109
- }));
120
+ // this.title.set(
121
+ // this.transloco.translate(entity ? 'editItem' : 'newItem', {
122
+ // item: this.itemLabel(),
123
+ // })
124
+ // );
110
125
  }
111
126
  this.params.set(params);
112
127
  this.createClientView();
@@ -126,7 +141,9 @@ class FormViewHostComponent {
126
141
  // )}`
127
142
  // );
128
143
  const crudComponent = this.entityCrudComponentBase();
129
- return crudComponent?.create(entityValue).pipe(tap(() => this.close(false)));
144
+ return crudComponent
145
+ ?.create(entityValue)
146
+ .pipe(tap(() => this.close(false)));
130
147
  }
131
148
  update(id, entityValue) {
132
149
  // console.log(
@@ -135,7 +152,9 @@ class FormViewHostComponent {
135
152
  // )}, entity: ${entityValue}`
136
153
  // );
137
154
  const crudComponent = this.entityCrudComponentBase();
138
- return crudComponent?.update(id, entityValue).pipe(tap(() => this.close(false)));
155
+ return crudComponent
156
+ ?.update(id, entityValue)
157
+ .pipe(tap(() => this.close(false)));
139
158
  }
140
159
  /**
141
160
  * Creates the client view provided via template
@@ -149,7 +168,7 @@ class FormViewHostComponent {
149
168
  $implicit: {
150
169
  bridge: this,
151
170
  entity: this.entity(),
152
- params: this.params()
171
+ params: this.params(),
153
172
  },
154
173
  });
155
174
  this.clientFormView.detectChanges();
@@ -189,7 +208,12 @@ class FormViewHostComponent {
189
208
  }
190
209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: FormViewHostComponent, decorators: [{
191
210
  type: Component,
192
- args: [{ imports: [CommonModule, MatButtonModule, MatIconModule, SPMatHostBusyWheelDirective], selector: 'sp-create-edit-entity-host', template: `
211
+ args: [{ imports: [
212
+ CommonModule,
213
+ MatButtonModule,
214
+ MatIconModule,
215
+ SPMatHostBusyWheelDirective,
216
+ ], selector: 'sp-create-edit-entity-host', template: `
193
217
  <div spHostBusyWheel="formBusyWheel">
194
218
  <div class="create-edit-topbar">
195
219
  <div class="title">
@@ -440,14 +464,23 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
440
464
  }
441
465
  return startCase(source);
442
466
  };
443
- _itemLabel = computed(() => this.itemLabel()
444
- ? this.itemLabel()
445
- : this.getLabel(this.entityName()));
446
- _itemLabelPlural = computed(() => this.itemLabelPlural()
447
- ? this.itemLabelPlural()
448
- : this.getLabel(plural(this.entityName())));
467
+ _itemLabel = computed(() => {
468
+ const itemLabel = this.itemLabel();
469
+ const label = itemLabel ? itemLabel : this.getLabel(this.entityName());
470
+ return label instanceof Observable ? label : of(label);
471
+ });
472
+ _itemLabelPlural = computed(() => {
473
+ const itemLabelPlural = this.itemLabelPlural();
474
+ const label = itemLabelPlural
475
+ ? itemLabelPlural
476
+ : this.getLabel(plural(this.entityName()));
477
+ return label instanceof Observable ? label : of(label);
478
+ });
449
479
  // Computed title
450
- _title = computed(() => this.title() ? this.title() : this._itemLabelPlural());
480
+ _title = computed(() => {
481
+ const title = this.title() ? this.title() : this._itemLabelPlural();
482
+ return title instanceof Observable ? title : of(title);
483
+ });
451
484
  // endpoint with the QP string removed (if one was provided)
452
485
  _endpointSansParams = computed(() => this.endpoint().split('?')[0]);
453
486
  _endpointParams = computed(() => { });
@@ -532,31 +565,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
532
565
  }
533
566
  return cols;
534
567
  });
535
- // Use a custom computed() signal to derive the action items for each
536
- // entity so that we can run per item's allow item action function to
537
- // selectively disable one or more actions based on the item's state.
538
- _itemActions = computed(() => {
539
- return this.getItemActions();
540
- // const actions =
541
- // this.itemActions() && this.itemActions().length
542
- // ? this.itemActions()
543
- // : this.defaultItemCrudActions();
544
- // let actionsCopy: SPContextMenuItem[] = JSON.parse(JSON.stringify(actions));
545
- // actionsCopy.forEach((action, index: number) => {
546
- // const orgDisable = actions[index]?.disable;
547
- // action.disable = (entity: TEntity) => {
548
- // if (orgDisable) {
549
- // return orgDisable(entity);
550
- // }
551
- // const allowItemActionFn = this.allowEntityActionFn();
552
- // if (allowItemActionFn) {
553
- // return !allowItemActionFn(entity, action.role ?? action.label);
554
- // }
555
- // return false;
556
- // };
557
- // });
558
- // return actionsCopy;
559
- });
568
+ // Provide per entity actions as a function so that the actions are
569
+ // enumerated only when the user clicks on the context menu button.
570
+ _itemActions = (entity) => this.getItemActions(entity);
560
571
  // This uses the previewActive signal to compute the visible columns
561
572
  // when preview is activated. For now we just hide the 'action' column when
562
573
  // preview is active. We can further customize this logic by allowing the
@@ -589,16 +600,14 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
589
600
  ]);
590
601
  }
591
602
  }
592
- ngOnInit() {
593
- }
603
+ ngOnInit() { }
594
604
  ngOnDestroy() {
595
605
  this.sub$.unsubscribe();
596
606
  }
597
607
  /**
598
608
  * Override so that we can suppress default action in SPMatEntityListComponent
599
609
  */
600
- ngAfterViewInit() {
601
- }
610
+ ngAfterViewInit() { }
602
611
  /**
603
612
  * If the create/edit entity form is active, it calls its registered
604
613
  * canCancelEdit callback to determine if it's okay to cancel the edit.
@@ -761,36 +770,49 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
761
770
  if (!this.newItemLink() || this.newItemLink()?.length == 0) {
762
771
  event.preventDefault();
763
772
  event.stopImmediatePropagation();
764
- const params = {
765
- title: this.newItemLabel() ??
766
- this.transloco.translate('spMatEntityCrud.newItem', {
767
- item: this._itemLabel(),
768
- }),
769
- };
770
- this.showCreateEditView(undefined, params);
771
- // const tmpl = this.createEditFormTemplate();
772
- // if (tmpl) {
773
- // // If preview is active deactivate it
774
- // if (this.previewActive()) {
775
- // this.closePreview();
776
- // }
777
- // const createEditHost = this.createEditHostComponent();
778
- // createEditHost!.show(undefined);
779
- // this.createEditViewActive.set(true);
780
- // }
781
- }
782
- if (!this.createEditViewActive()) {
783
- this.action.emit({ role: '_new_' });
773
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
774
+ const params = {
775
+ title: this.newItemLabel() ??
776
+ this.transloco.translate('spMatEntityCrud.newItem', {
777
+ item: itemLabel
778
+ }),
779
+ };
780
+ this.showCreateEditView(undefined, params);
781
+ if (!this.createEditViewActive()) {
782
+ this.action.emit({ role: '_new_' });
783
+ }
784
+ });
785
+ // const params = {
786
+ // title:
787
+ // this.newItemLabel() ??
788
+ // this.transloco.translate('spMatEntityCrud.newItem', {
789
+ // item: this._itemLabel(),
790
+ // }),
791
+ // };
792
+ // this.showCreateEditView(undefined, params);
784
793
  }
785
794
  }
786
795
  onUpdate(entity) {
787
- const params = {
788
- title: this.editItemTitle() ??
789
- this.transloco.translate('spMatEntityCrud.editItem', {
790
- item: this._itemLabel(),
791
- }),
792
- };
793
- this.showCreateEditView(entity, params);
796
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
797
+ const params = {
798
+ title: this.editItemTitle() ??
799
+ this.transloco.translate('spMatEntityCrud.editItem', {
800
+ item: itemLabel
801
+ }),
802
+ };
803
+ this.showCreateEditView(entity, params);
804
+ if (!this.createEditViewActive()) {
805
+ this.action.emit({ role: '_update_' });
806
+ }
807
+ });
808
+ // const params = {
809
+ // title:
810
+ // this.editItemTitle() ??
811
+ // this.transloco.translate('spMatEntityCrud.editItem', {
812
+ // item: this._itemLabel(),
813
+ // }),
814
+ // };
815
+ // this.showCreateEditView(entity, params);
794
816
  // const tmpl = this.createEditFormTemplate();
795
817
  // if (tmpl) {
796
818
  // // If preview is active deactivate it
@@ -803,9 +825,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
803
825
  // this.createEditViewActive.set(true);
804
826
  // }
805
827
  // }
806
- if (!this.createEditViewActive()) {
807
- this.action.emit({ role: '_update_' });
808
- }
828
+ // if (!this.createEditViewActive()) {
829
+ // this.action.emit({ role: '_update_' });
830
+ // }
809
831
  }
810
832
  /**
811
833
  * Show the create/edit component. This is deliberately made public so as to
@@ -859,36 +881,41 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
859
881
  // Do the delete prompt asynchronously so that the context menu is
860
882
  // dismissed before the prompt is displayed.
861
883
  setTimeout(() => {
862
- const deletedItemPrompt = this.transloco.translate('spMatEntityCrud.deleteItemConfirm', { item: this._itemLabel().toLocaleLowerCase() });
863
- const yes = confirm(deletedItemPrompt);
864
- if (yes) {
865
- const entityId = entity[this.idKey()];
866
- // If preview is active deactivate it
867
- if (this.previewActive()) {
868
- this.closePreviewImpl(false);
869
- }
870
- let obs;
871
- const crudOpFn = this.crudOpFn();
872
- if (crudOpFn) {
873
- obs = crudOpFn('delete', entityId, undefined, this);
874
- }
875
- else {
876
- obs = this.http.delete(this.getEntityUrl(entityId), {
877
- context: this.getCrudReqHttpContext('delete'),
878
- });
884
+ // We use firstValueFrom() to get the value of the observable
885
+ // synchronously. firstValueFrom() also gracefully cleans up the
886
+ // observable after a value is emitted.
887
+ firstValueFrom(this._itemLabel()).then((itemLabel) => {
888
+ const deletedItemPrompt = this.transloco.translate('spMatEntityCrud.deleteItemConfirm', { item: itemLabel.toLocaleLowerCase() });
889
+ const yes = confirm(deletedItemPrompt);
890
+ if (yes) {
891
+ const entityId = entity[this.idKey()];
892
+ // If preview is active deactivate it
893
+ if (this.previewActive()) {
894
+ this.closePreviewImpl(false);
895
+ }
896
+ let obs;
897
+ const crudOpFn = this.crudOpFn();
898
+ if (crudOpFn) {
899
+ obs = crudOpFn('delete', entityId, undefined, this);
900
+ }
901
+ else {
902
+ obs = this.http.delete(this.getEntityUrl(entityId), {
903
+ context: this.getCrudReqHttpContext('delete'),
904
+ });
905
+ }
906
+ this.sub$.add(obs
907
+ .pipe(
908
+ // TODO: how to display a busy wheel?
909
+ // showBusyWheelUntilComplete(this.busyWheelId),
910
+ tap(() => {
911
+ this.spEntitiesList().removeEntity(entityId);
912
+ // TODO: customize by providing an interface via SPMatEntityCrudConfig?
913
+ const deletedMessage = this.transloco.translate('spMatEntityCrud.deleteItemSuccess', { item: this._itemLabel() });
914
+ this.snackBar.open(deletedMessage);
915
+ }))
916
+ .subscribe());
879
917
  }
880
- this.sub$.add(obs
881
- .pipe(
882
- // TODO: how to display a busy wheel?
883
- // showBusyWheelUntilComplete(this.busyWheelId),
884
- tap(() => {
885
- this.spEntitiesList().removeEntity(entityId);
886
- // TODO: customize by providing an interface via SPMatEntityCrudConfig?
887
- const deletedMessage = this.transloco.translate('spMatEntityCrud.deleteItemSuccess', { item: this._itemLabel() });
888
- this.snackBar.open(deletedMessage);
889
- }))
890
- .subscribe());
891
- }
918
+ });
892
919
  });
893
920
  }
894
921
  getUrl(endpoint) {
@@ -978,12 +1005,19 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
978
1005
  * to determine if the action is allowed for the given entity.
979
1006
  * @returns
980
1007
  */
981
- getItemActions() {
1008
+ getItemActions(entity) {
1009
+ // console.log(`SPMatEntityCrudComponent.getItemActions - entity: ${JSON.stringify(entity, null, 2)}`);
982
1010
  const actions = this.itemActions() && this.itemActions().length
983
1011
  ? this.itemActions()
984
1012
  : this.defaultItemCrudActions();
985
1013
  let actionsCopy = JSON.parse(JSON.stringify(actions));
986
1014
  actionsCopy.forEach((action, index) => {
1015
+ // localize default action item labels (Update & Delete)
1016
+ // Client specified action labels are to be localized by the client
1017
+ // before supplying them to the component.
1018
+ if (action.label.startsWith('spMatEntityCrud.')) {
1019
+ action.label = this.transloco.translate(action.label);
1020
+ }
987
1021
  const orgDisable = actions[index]?.disable;
988
1022
  action.disable = (entity) => {
989
1023
  if (orgDisable) {
@@ -1015,21 +1049,21 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1015
1049
  // SPMatEntityListComponent to use our component's any project MatColumnDef
1016
1050
  // content in the final mat-table.
1017
1051
  const clientColumnDefs = this.clientColumnDefs;
1018
- if (clientColumnDefs.length && spEntitiesList) {
1052
+ let contentColumnDefs = new Array();
1053
+ if (clientColumnDefs.length) {
1019
1054
  // Note that we process any content projected matColumnDef first and
1020
1055
  // our own internal content later. And when we process our own internal
1021
1056
  // columns (for now only 'action'), it's not added if a column with that
1022
1057
  // name has already been defined via content projection. This allows the
1023
1058
  // clients to override even internal columns with their column defintion.
1024
- let contentColumnDefs = new Array();
1025
1059
  clientColumnDefs.toArray().forEach((c) => contentColumnDefs.push(c));
1026
- this.componentColumns().forEach((ic) => {
1027
- if (!contentColumnDefs.find((c) => c.name === ic.name)) {
1028
- contentColumnDefs.push(ic);
1029
- }
1030
- });
1031
- spEntitiesList.contentColumnDefs = contentColumnDefs;
1032
1060
  }
1061
+ this.componentColumns().forEach((ic) => {
1062
+ if (!contentColumnDefs.find((c) => c.name === ic.name)) {
1063
+ contentColumnDefs.push(ic);
1064
+ }
1065
+ });
1066
+ spEntitiesList.contentColumnDefs = contentColumnDefs;
1033
1067
  // This is a replication of SPMatEntityCrudList.ngAfterViewInit. That
1034
1068
  // code is skipped as we declare <sp-mat-entity-list> with
1035
1069
  // deferViewInit=true.
@@ -1060,7 +1094,9 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1060
1094
  >
1061
1095
  {{
1062
1096
  newItemLabel() ??
1063
- t('spMatEntityCrud.newItem', { item: _itemLabel() })
1097
+ t('spMatEntityCrud.newItem', {
1098
+ item: _itemLabel() | async
1099
+ })
1064
1100
  }}
1065
1101
  <mat-icon>expand_circle_down</mat-icon>
1066
1102
  </button>
@@ -1085,8 +1121,11 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1085
1121
  >
1086
1122
  {{
1087
1123
  newItemLabel() ??
1088
- t('spMatEntityCrud.newItem', { item: _itemLabel() })
1124
+ t('spMatEntityCrud.newItem', {
1125
+ item: _itemLabel() | async
1126
+ })
1089
1127
  }}
1128
+ <mat-icon>add_circle</mat-icon>
1090
1129
  </button>
1091
1130
  } }
1092
1131
  </div>
@@ -1095,7 +1134,7 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1095
1134
  <ng-template #defaultHeaderTemplate>
1096
1135
  <div class="action-bar">
1097
1136
  <div class="action-bar-title">
1098
- {{ _title() }}
1137
+ {{ _title() | async }}
1099
1138
  </div>
1100
1139
  <span class="spacer"></span>
1101
1140
  <!-- Hide the action buttons when Preview/Edit pane is active -->
@@ -1138,19 +1177,19 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1138
1177
  -->
1139
1178
  <ng-container matColumnDef="action">
1140
1179
  <th mat-header-cell *matHeaderCellDef></th>
1141
- <td
1142
- mat-cell
1143
- *matCellDef="let element"
1144
- (click)="$event.stopImmediatePropagation()"
1145
- >
1146
- @if (_itemActions().length) {
1180
+ <td mat-cell *matCellDef="let element">
1181
+ <!-- <button
1182
+ mat-icon-button
1183
+ hoverDropDown
1184
+ >
1185
+ <mat-icon>more_vert</mat-icon>
1186
+ </button> -->
1147
1187
  <sp-mat-context-menu
1148
- [menuItems]="_itemActions()"
1188
+ [menuItems]="_itemActions"
1149
1189
  (selected)="onItemAction($event, element)"
1150
1190
  [contextData]="element"
1151
1191
  [hasBackdrop]="true"
1152
1192
  ></sp-mat-context-menu>
1153
- }
1154
1193
  </td>
1155
1194
  </ng-container>
1156
1195
  </as-split-area>
@@ -1167,15 +1206,15 @@ class SPMatEntityCrudComponent extends SPMatEntityListComponent {
1167
1206
  <!-- Create/Edit Entity -->
1168
1207
  <sp-create-edit-entity-host
1169
1208
  [ngClass]="createEditViewActive() ? 'd-inherit' : 'd-none'"
1170
- [itemLabel]="_itemLabel()"
1171
- [itemLabelPlural]="_itemLabelPlural()"
1209
+ itemLabel="{{ _itemLabel() | async }}"
1210
+ itemLabelPlural="{{ _itemLabelPlural() | async }}"
1172
1211
  [entityCrudComponentBase]="this"
1173
1212
  [clientViewTemplate]="createEditFormTemplate()"
1174
1213
  ></sp-create-edit-entity-host>
1175
1214
  </div>
1176
1215
  </as-split-area>
1177
1216
  </as-split>
1178
- `, isInline: true, styles: [".d-none{display:none}.d-inherit{display:inherit}.action-bar{display:flex;flex-direction:row;align-items:center;padding-bottom:.5em}.action-bar-title{font-size:1.5em;font-weight:600}.spacer{flex-grow:1}.action-bar-actions{text-align:end}.active-row{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i5.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "directive", type: i7.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i7.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i7.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i7.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i7.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "ngmodule", type: MatSortModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i8.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i10.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: AngularSplitModule }, { kind: "component", type: i11.SplitComponent, selector: "as-split", inputs: ["gutterSize", "gutterStep", "disabled", "gutterClickDeltaPx", "direction", "dir", "unit", "gutterAriaLabel", "restrictMove", "useTransition", "gutterDblClickDuration"], outputs: ["gutterClick", "gutterDblClick", "dragStart", "dragEnd", "transitionEnd"], exportAs: ["asSplit"] }, { kind: "component", type: i11.SplitAreaComponent, selector: "as-split-area", inputs: ["size", "minSize", "maxSize", "lockSize", "visible"], exportAs: ["asSplitArea"] }, { kind: "component", type: SPMatEntityListComponent, selector: "sp-mat-entity-list", inputs: ["entityName", "entityNamePlural", "endpoint", "entityLoaderFn", "columns", "displayedColumns", "pageSize", "idKey", "pagination", "paginator", "sorter", "disableSort", "infiniteScrollContainer", "infiniteScrollDistance", "infiniteScrollThrottle", "infiniteScrollWindow", "httpReqContext", "deferViewInit"], outputs: ["selectEntity"] }, { kind: "component", type: SPMatContextMenuComponent, selector: "sp-mat-context-menu", inputs: ["menuItems", "label", "menuIconName", "enableHover", "contextData", "hasBackdrop"], outputs: ["selected"] }, { kind: "component", type: FormViewHostComponent, selector: "sp-create-edit-entity-host", inputs: ["entityCrudComponentBase", "clientViewTemplate", "itemLabel", "itemLabelPlural"] }, { kind: "directive", type: SPMatHostBusyWheelDirective, selector: "[spHostBusyWheel]", inputs: ["spHostBusyWheel"] }, { kind: "component", type: PreviewHostComponent, selector: "sp-entity-crud-preview-host", inputs: ["entityCrudComponentBase", "clientViewTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1217
+ `, isInline: true, styles: [".d-none{display:none}.d-inherit{display:inherit}.action-bar{display:flex;flex-direction:row;align-items:center;padding-bottom:.5em}.action-bar-title{font-size:1.5em;font-weight:600}.spacer{flex-grow:1}.action-bar-actions{text-align:end}.active-row{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i5.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "directive", type: i7.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i7.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i7.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i7.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i7.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "ngmodule", type: MatSortModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i8.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i10.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: AngularSplitModule }, { kind: "component", type: i11.SplitComponent, selector: "as-split", inputs: ["gutterSize", "gutterStep", "disabled", "gutterClickDeltaPx", "direction", "dir", "unit", "gutterAriaLabel", "restrictMove", "useTransition", "gutterDblClickDuration"], outputs: ["gutterClick", "gutterDblClick", "dragStart", "dragEnd", "transitionEnd"], exportAs: ["asSplit"] }, { kind: "component", type: i11.SplitAreaComponent, selector: "as-split-area", inputs: ["size", "minSize", "maxSize", "lockSize", "visible"], exportAs: ["asSplitArea"] }, { kind: "component", type: SPMatEntityListComponent, selector: "sp-mat-entity-list", inputs: ["entityName", "entityNamePlural", "endpoint", "entityLoaderFn", "columns", "displayedColumns", "pageSize", "idKey", "pagination", "paginator", "sorter", "disableSort", "infiniteScrollContainer", "infiniteScrollDistance", "infiniteScrollThrottle", "infiniteScrollWindow", "httpReqContext", "deferViewInit"], outputs: ["selectEntity"] }, { kind: "component", type: SPMatContextMenuComponent, selector: "sp-mat-context-menu", inputs: ["menuItems", "label", "menuIconName", "enableHover", "contextData", "hasBackdrop"], outputs: ["selected"] }, { kind: "component", type: FormViewHostComponent, selector: "sp-create-edit-entity-host", inputs: ["entityCrudComponentBase", "clientViewTemplate", "itemLabel", "itemLabelPlural"] }, { kind: "directive", type: SPMatHostBusyWheelDirective, selector: "[spHostBusyWheel]", inputs: ["spHostBusyWheel"] }, { kind: "component", type: PreviewHostComponent, selector: "sp-entity-crud-preview-host", inputs: ["entityCrudComponentBase", "clientViewTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1179
1218
  }
1180
1219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: SPMatEntityCrudComponent, decorators: [{
1181
1220
  type: Component,
@@ -1216,7 +1255,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1216
1255
  >
1217
1256
  {{
1218
1257
  newItemLabel() ??
1219
- t('spMatEntityCrud.newItem', { item: _itemLabel() })
1258
+ t('spMatEntityCrud.newItem', {
1259
+ item: _itemLabel() | async
1260
+ })
1220
1261
  }}
1221
1262
  <mat-icon>expand_circle_down</mat-icon>
1222
1263
  </button>
@@ -1241,8 +1282,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1241
1282
  >
1242
1283
  {{
1243
1284
  newItemLabel() ??
1244
- t('spMatEntityCrud.newItem', { item: _itemLabel() })
1285
+ t('spMatEntityCrud.newItem', {
1286
+ item: _itemLabel() | async
1287
+ })
1245
1288
  }}
1289
+ <mat-icon>add_circle</mat-icon>
1246
1290
  </button>
1247
1291
  } }
1248
1292
  </div>
@@ -1251,7 +1295,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1251
1295
  <ng-template #defaultHeaderTemplate>
1252
1296
  <div class="action-bar">
1253
1297
  <div class="action-bar-title">
1254
- {{ _title() }}
1298
+ {{ _title() | async }}
1255
1299
  </div>
1256
1300
  <span class="spacer"></span>
1257
1301
  <!-- Hide the action buttons when Preview/Edit pane is active -->
@@ -1294,19 +1338,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1294
1338
  -->
1295
1339
  <ng-container matColumnDef="action">
1296
1340
  <th mat-header-cell *matHeaderCellDef></th>
1297
- <td
1298
- mat-cell
1299
- *matCellDef="let element"
1300
- (click)="$event.stopImmediatePropagation()"
1301
- >
1302
- @if (_itemActions().length) {
1341
+ <td mat-cell *matCellDef="let element">
1342
+ <!-- <button
1343
+ mat-icon-button
1344
+ hoverDropDown
1345
+ >
1346
+ <mat-icon>more_vert</mat-icon>
1347
+ </button> -->
1303
1348
  <sp-mat-context-menu
1304
- [menuItems]="_itemActions()"
1349
+ [menuItems]="_itemActions"
1305
1350
  (selected)="onItemAction($event, element)"
1306
1351
  [contextData]="element"
1307
1352
  [hasBackdrop]="true"
1308
1353
  ></sp-mat-context-menu>
1309
- }
1310
1354
  </td>
1311
1355
  </ng-container>
1312
1356
  </as-split-area>
@@ -1323,8 +1367,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1323
1367
  <!-- Create/Edit Entity -->
1324
1368
  <sp-create-edit-entity-host
1325
1369
  [ngClass]="createEditViewActive() ? 'd-inherit' : 'd-none'"
1326
- [itemLabel]="_itemLabel()"
1327
- [itemLabelPlural]="_itemLabelPlural()"
1370
+ itemLabel="{{ _itemLabel() | async }}"
1371
+ itemLabelPlural="{{ _itemLabelPlural() | async }}"
1328
1372
  [entityCrudComponentBase]="this"
1329
1373
  [clientViewTemplate]="createEditFormTemplate()"
1330
1374
  ></sp-create-edit-entity-host>