@memberjunction/ng-explorer-core 1.4.0 → 1.5.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.
Files changed (45) hide show
  1. package/dist/app-routing.module.d.ts.map +1 -1
  2. package/dist/app-routing.module.js +6 -1
  3. package/dist/lib/app-view/application-view.component.d.ts.map +1 -1
  4. package/dist/lib/app-view/application-view.component.js +34 -24
  5. package/dist/lib/base-browser-component/base-browser-component.d.ts +3 -2
  6. package/dist/lib/base-browser-component/base-browser-component.d.ts.map +1 -1
  7. package/dist/lib/base-browser-component/base-browser-component.js +5 -4
  8. package/dist/lib/generic/resource-container-component.d.ts.map +1 -1
  9. package/dist/lib/generic-browser-list/generic-browser-list.component.d.ts +4 -0
  10. package/dist/lib/generic-browser-list/generic-browser-list.component.d.ts.map +1 -1
  11. package/dist/lib/generic-browser-list/generic-browser-list.component.js +104 -74
  12. package/dist/lib/header/header.component.d.ts +1 -1
  13. package/dist/lib/header/header.component.js +2 -2
  14. package/dist/lib/home-component/home.component.js +11 -5
  15. package/dist/lib/list-view/list-view.component.d.ts +36 -0
  16. package/dist/lib/list-view/list-view.component.d.ts.map +1 -0
  17. package/dist/lib/list-view/list-view.component.js +189 -0
  18. package/dist/lib/navigation/navigation.component.d.ts +32 -6
  19. package/dist/lib/navigation/navigation.component.d.ts.map +1 -1
  20. package/dist/lib/navigation/navigation.component.js +123 -46
  21. package/dist/lib/resource-wrappers/record-resource.component.d.ts +2 -2
  22. package/dist/lib/resource-wrappers/record-resource.component.d.ts.map +1 -1
  23. package/dist/lib/resource-wrappers/record-resource.component.js +15 -11
  24. package/dist/lib/single-list-detail/single-list-detail.component.d.ts +26 -0
  25. package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -0
  26. package/dist/lib/single-list-detail/single-list-detail.component.js +213 -0
  27. package/dist/lib/single-record/single-record.component.d.ts +7 -4
  28. package/dist/lib/single-record/single-record.component.d.ts.map +1 -1
  29. package/dist/lib/single-record/single-record.component.js +83 -29
  30. package/dist/lib/single-view/single-view.component.d.ts +2 -0
  31. package/dist/lib/single-view/single-view.component.d.ts.map +1 -1
  32. package/dist/lib/single-view/single-view.component.js +27 -26
  33. package/dist/module.d.ts +38 -37
  34. package/dist/module.d.ts.map +1 -1
  35. package/dist/module.js +18 -14
  36. package/dist/public-api.d.ts +2 -2
  37. package/dist/public-api.d.ts.map +1 -1
  38. package/dist/public-api.js +2 -2
  39. package/package.json +17 -16
  40. package/dist/lib/generic/section-loader-component.d.ts +0 -18
  41. package/dist/lib/generic/section-loader-component.d.ts.map +0 -1
  42. package/dist/lib/generic/section-loader-component.js +0 -66
  43. package/dist/lib/join-grid/join-grid.component.d.ts +0 -31
  44. package/dist/lib/join-grid/join-grid.component.d.ts.map +0 -1
  45. package/dist/lib/join-grid/join-grid.component.js +0 -222
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { Component, ElementRef, ViewChild, HostListener, HostBinding, Input } from '@angular/core';
11
11
  import { NavigationEnd, NavigationSkipped } from '@angular/router';
12
12
  import { DrawerComponent } from "@progress/kendo-angular-layout";
13
- import { Metadata, RunView, LogError } from '@memberjunction/core';
13
+ import { Metadata, RunView, LogError, LogStatus } from '@memberjunction/core';
14
14
  import { MJEventType, MJGlobal } from '@memberjunction/global';
15
15
  import { EventCodes, SharedService } from '@memberjunction/ng-shared';
16
16
  import { BaseResourceComponent, ResourceData } from '@memberjunction/ng-shared';
@@ -85,7 +85,7 @@ function NavigationComponent_kendo_drawer_container_3_For_12_Template(rf, ctx) {
85
85
  function NavigationComponent_kendo_drawer_container_3_For_14_Template(rf, ctx) { if (rf & 1) {
86
86
  const _r26 = i0.ɵɵgetCurrentView();
87
87
  i0.ɵɵelementStart(0, "mj-tab-body")(1, "mj-resource", 20);
88
- i0.ɵɵlistener("ResourceRecordSaved", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ResourceRecordSaved_1_listener() { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r25 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r25.SaveSingleWorkspaceItem(tab_r20)); })("ContentLoadingStarted", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ContentLoadingStarted_1_listener() { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r27 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r27.setTabContentLoadingStatus(tab_r20, true)); })("ContentLoadingComplete", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ContentLoadingComplete_1_listener() { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r28 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r28.setTabContentLoadingStatus(tab_r20, false)); });
88
+ i0.ɵɵlistener("ResourceRecordSaved", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ResourceRecordSaved_1_listener($event) { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r25 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r25.HandleResourceRecordSaved(tab_r20, $event)); })("ContentLoadingStarted", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ContentLoadingStarted_1_listener() { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r27 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r27.setTabContentLoadingStatus(tab_r20, true)); })("ContentLoadingComplete", function NavigationComponent_kendo_drawer_container_3_For_14_Template_mj_resource_ContentLoadingComplete_1_listener() { const restoredCtx = i0.ɵɵrestoreView(_r26); const tab_r20 = restoredCtx.$implicit; const ctx_r28 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r28.setTabContentLoadingStatus(tab_r20, false)); });
89
89
  i0.ɵɵelementEnd()();
90
90
  } if (rf & 2) {
91
91
  const tab_r20 = ctx.$implicit;
@@ -176,9 +176,7 @@ export class NavigationComponent {
176
176
  this.tabs = [];
177
177
  this.closedTabs = []; // should always be empty after using it
178
178
  this.tabQueryParams = {};
179
- // public activeTabIndex: number = 0;
180
- // public selectedTabIndex: number = 0;
181
- this.workSpace = {};
179
+ this.workSpace = undefined;
182
180
  this.workSpaceItems = [];
183
181
  this.panelItems = [];
184
182
  this.showExpansionPanel = false;
@@ -274,7 +272,7 @@ export class NavigationComponent {
274
272
  switch (event.event) {
275
273
  case MJEventType.LoggedIn:
276
274
  yield this.loadApp();
277
- yield this.getWorkspace();
275
+ yield this.loadWorkspace();
278
276
  this._loggedIn = true;
279
277
  // check for early events and replay them now that we're logged in
280
278
  for (let i = 0; i < this._earlyEvents.length; ++i) {
@@ -310,6 +308,14 @@ export class NavigationComponent {
310
308
  // another component requested that we add something to our tab structure
311
309
  this.AddOrSelectTab(event.args);
312
310
  break;
311
+ case EventCodes.CloseCurrentTab:
312
+ if (this.mjTabStrip && this.activeTabIndex > 0) {
313
+ this.mjTabStrip.CloseTab(this.activeTabIndex);
314
+ }
315
+ else {
316
+ LogError("no active tab to close or tabstrip not available");
317
+ }
318
+ break;
313
319
  default:
314
320
  break;
315
321
  }
@@ -374,12 +380,11 @@ export class NavigationComponent {
374
380
  // come back to this tab
375
381
  const urlParts = this.router.url.split('?');
376
382
  if (urlParts.length > 1) {
377
- // we have query params, so stash em
383
+ // we have query params, so stash them
378
384
  const params = new URLSearchParams(urlParts[1]);
379
- const keys = params.keys();
380
385
  const queryParams = {};
381
- for (const key of keys) {
382
- queryParams[key] = params.get(key);
386
+ for (const [key, value] of params.entries()) {
387
+ queryParams[key] = value;
383
388
  }
384
389
  this.tabQueryParams['tab_' + this.activeTabIndex] = queryParams;
385
390
  }
@@ -447,42 +452,54 @@ export class NavigationComponent {
447
452
  }
448
453
  }, 10);
449
454
  }
450
- getWorkspace() {
455
+ /**
456
+ * This method will load the user's workspace and all the workspace items that are part of the workspace from the database.
457
+ */
458
+ loadWorkspace() {
451
459
  return __awaiter(this, void 0, void 0, function* () {
452
460
  const md = new Metadata();
453
461
  const rv = new RunView();
454
462
  const workspaceParams = {
455
463
  EntityName: "Workspaces",
456
- ExtraFilter: `UserID=${md.CurrentUser.ID}`
464
+ ExtraFilter: `UserID=${md.CurrentUser.ID}`,
465
+ OrderBy: "UpdatedAt DESC", // by default get the workspace that was most recently updated
466
+ ResultType: "entity_object" /*we want entity objects back so that we can modify them as needed*/
457
467
  };
458
468
  const workspaces = yield rv.RunView(workspaceParams);
459
469
  if (workspaces.Success) {
460
- const workspaceRecord = yield md.GetEntityObject("Workspaces");
461
470
  if (workspaces.Results.length) {
462
- const workspace = workspaces.Results.find((workspace) => workspace.UserID === md.CurrentUser.ID);
463
- yield workspaceRecord.Load(workspace.ID);
471
+ this.workSpace = workspaces.Results[0]; // by default get the first one, and since we are sorting by UpdatedAt DESC above, will be most recently modified one. Future feature for multi-workspace support we'll have to adjust this
464
472
  }
465
473
  else {
466
- workspaceRecord.NewRecord();
467
- workspaceRecord.Name = `${md.CurrentUser.Name || md.CurrentUser.ID}'s Workspace`;
468
- workspaceRecord.UserID = md.CurrentUser.ID;
469
- yield workspaceRecord.Save();
474
+ // no matching record found, so create a new one
475
+ this.workSpace = yield md.GetEntityObject('Workspaces');
476
+ this.workSpace.NewRecord();
477
+ this.workSpace.Name = `${md.CurrentUser.Name || md.CurrentUser.ID}'s Workspace`;
478
+ this.workSpace.UserID = md.CurrentUser.ID;
479
+ yield this.workSpace.Save();
470
480
  }
471
- this.workSpace = workspaceRecord;
481
+ if (!this.workSpace)
482
+ throw new Error('Error loading workspace');
472
483
  const workspaceItemParams = {
473
484
  EntityName: "Workspace Items",
474
485
  ExtraFilter: `WorkspaceID='${this.workSpace.ID}'`,
486
+ OrderBy: "Sequence ASC", // get them in order
475
487
  ResultType: "entity_object" /*we want entity objects back so that we can modify them as needed*/
476
488
  };
477
489
  const workspaceItems = yield rv.RunView(workspaceItemParams);
478
490
  if (workspaceItems.Success) {
479
491
  this.workSpaceItems = workspaceItems.Results;
480
- yield this.LoadWorkSpace();
492
+ yield this.LoadWorkspaceItems();
481
493
  }
482
494
  }
495
+ else
496
+ throw new Error('Error loading workspace');
483
497
  });
484
498
  }
485
- LoadWorkSpace() {
499
+ /**
500
+ * This method will load all the workspace items that are part of the workspace currently set in the workSpace member variable
501
+ */
502
+ LoadWorkspaceItems() {
486
503
  return __awaiter(this, void 0, void 0, function* () {
487
504
  const md = new Metadata();
488
505
  this.tabs = []; // first clear out the tabs - this is often already the state but in case this is a full refresh, make sure we do this.
@@ -506,7 +523,7 @@ export class NavigationComponent {
506
523
  // now add to data structure
507
524
  yield this.internalAddTab(newTab);
508
525
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
509
- // non-blocking, load dynamically
526
+ // non-blocking, load the resource names dynamically as this requires additional DB lookups
510
527
  newTab.label = yield this.GetWorkspaceItemDisplayName(resourceData);
511
528
  newTab.labelLoading = false;
512
529
  if (newTab === this.tabs[this.activeTabIndex - 1]) // subtract one since the activeTabIndex is relative to the full set of tabs and the this.tabs array doesn't include the HOME tab
@@ -522,7 +539,12 @@ export class NavigationComponent {
522
539
  else
523
540
  this.titleService.setTitle(title + ' (' + this.applicationName + ')');
524
541
  }
525
- checkForExistingTab(data) {
542
+ /**
543
+ * This method is responsible for searching for a matching tab in the existing tab structure of the loaded workspace. It returns either a Tab object or null if one isn't found that matches the ResourceData provided.
544
+ * @param data
545
+ * @returns
546
+ */
547
+ findExistingTab(data) {
526
548
  let existingTab;
527
549
  if (data.ResourceType.trim().toLowerCase() === 'search results') {
528
550
  // we have a different matching logic for search results because we want to match on the search input as well as the entity
@@ -548,18 +570,36 @@ export class NavigationComponent {
548
570
  }
549
571
  }
550
572
  else {
551
- existingTab = this.tabs.find(t => t.data.ResourceTypeID === data.ResourceTypeID &&
552
- t.data.ResourceRecordID === data.ResourceRecordID &&
553
- data.ResourceRecordID // make sure that we don't match on null/undefined ResourceRecordID's - these should always be NEW tabs
554
- );
573
+ existingTab = this.tabs.find(t => {
574
+ if (t.data.ResourceTypeID === data.ResourceTypeID &&
575
+ t.data.ResourceRecordID === data.ResourceRecordID) {
576
+ // we now have to do one more check, we have to make sure that all of the values within the Configuration object match as well
577
+ let bMatch = true;
578
+ // ignore keys that start with an underscore or are the NewRecordValues key
579
+ const keys = Object.keys(data.Configuration).filter(k => !k.startsWith('_') && k.trim().toLowerCase() !== 'newrecordvalues');
580
+ for (const key of keys) {
581
+ if (data.Configuration[key] !== t.data.Configuration[key]) {
582
+ bMatch = false;
583
+ break;
584
+ }
585
+ }
586
+ return bMatch;
587
+ }
588
+ else
589
+ return false;
590
+ });
555
591
  }
556
592
  return existingTab;
557
593
  }
594
+ /**
595
+ * This utility method is used to either Add a tab if a matching tab for the given data parameter isn't found, or to select the existing tab if it already exists.
596
+ * @param data
597
+ */
558
598
  AddOrSelectTab(data) {
559
599
  return __awaiter(this, void 0, void 0, function* () {
560
600
  const t = this.tabs;
561
601
  this.loader = true;
562
- const existingTab = this.checkForExistingTab(data);
602
+ const existingTab = this.findExistingTab(data);
563
603
  if (existingTab) {
564
604
  const index = this.tabs.indexOf(existingTab);
565
605
  // add one because the HOME tab is not in the tabs array but it IS part of our tab structure
@@ -587,8 +627,6 @@ export class NavigationComponent {
587
627
  yield this.internalAddTab(newTab);
588
628
  // select the new tab
589
629
  this.activeTabIndex = this.tabs.length; // this is intentionally past array boundary because ActiveTabIndex includes the Home tab that is not part of the tabs array
590
- //this.tabstrip.selectTab(this.activeTabIndex);
591
- //this.renderer.selectRootElement(this.tabstrip.wrapper.nativeElement).focus()
592
630
  this.sharedService.InvokeManualResize();
593
631
  this.scrollIntoView();
594
632
  setTimeout(() => __awaiter(this, void 0, void 0, function* () {
@@ -648,7 +686,11 @@ export class NavigationComponent {
648
686
  url += `/query/${data.ResourceRecordID}`;
649
687
  break;
650
688
  case 'records':
651
- url += `/record/${data.ResourceRecordID}?Entity=${data.Configuration.Entity}`;
689
+ const recIDAsString = data.ResourceRecordID !== null && data.ResourceRecordID !== undefined ? (typeof data.ResourceRecordID === "string" ? data.ResourceRecordID : data.ResourceRecordID.toString()) : "";
690
+ url += `/record/${recIDAsString.trim()}?Entity=${data.Configuration.Entity}`;
691
+ if (data.Configuration.NewRecordValues) {
692
+ url += `&NewRecordValues=${data.Configuration.NewRecordValues}`;
693
+ }
652
694
  break;
653
695
  case 'search results':
654
696
  url += `/search/${data.Configuration.SearchInput}?Entity=${data.Configuration.Entity}`;
@@ -698,11 +740,8 @@ export class NavigationComponent {
698
740
  this.setAppTitle(tab.label);
699
741
  }
700
742
  scrollIntoView() {
701
- // const containerElement = this.tabstrip.wrapper.nativeElement;
702
- // setTimeout(() => {
703
- // const newTabElement = containerElement.querySelector(`li:nth-child(${this.activeTabIndex + 1})`);
704
- // newTabElement.scrollIntoView({ inline: 'nearest' });
705
- // }, 200);
743
+ if (this.mjTabStrip)
744
+ this.mjTabStrip.scrollIntoView(this.activeTabIndex);
706
745
  }
707
746
  GetWorkspaceItemDisplayName(data) {
708
747
  return __awaiter(this, void 0, void 0, function* () {
@@ -715,6 +754,10 @@ export class NavigationComponent {
715
754
  return `Workspace Item ${data.ID}`;
716
755
  });
717
756
  }
757
+ /**
758
+ * Saves the workspace to the database.
759
+ * @returns
760
+ */
718
761
  SaveWorkspace() {
719
762
  return __awaiter(this, void 0, void 0, function* () {
720
763
  let bSuccess = true;
@@ -725,10 +768,32 @@ export class NavigationComponent {
725
768
  return bSuccess;
726
769
  });
727
770
  }
771
+ HandleResourceRecordSaved(tab, resourceRecord) {
772
+ return __awaiter(this, void 0, void 0, function* () {
773
+ const oldId = tab.data.ResourceRecordID;
774
+ tab.data.ResourceRecordID = resourceRecord.PrimaryKey.ToURLSegment();
775
+ // we need to update the label in case the "Name" of the record changed, or if it was new and no longer is new
776
+ tab.label = yield this.GetWorkspaceItemDisplayName(tab.data);
777
+ // now check to see if the old id and the new ID are any different
778
+ // check for tab names that start with New as well...
779
+ // and if so we need to replace the state in the URL for Angular so that we don't have a New Record situation in the URL but have the actual ID now
780
+ // if (oldId !== tab.data.ResourceRecordID || tab.label?.toLowerCase().trim().startsWith('new') ) {
781
+ this.updateBrowserURL(tab, tab.data);
782
+ // }
783
+ return yield this.SaveSingleWorkspaceItem(tab);
784
+ });
785
+ }
786
+ /**
787
+ * Saves a single workspace item to the database.
788
+ * @param tab
789
+ * @returns
790
+ */
728
791
  SaveSingleWorkspaceItem(tab) {
729
792
  var _a;
730
793
  return __awaiter(this, void 0, void 0, function* () {
731
794
  try {
795
+ if (!this.workSpace)
796
+ throw new Error('No workspace loaded');
732
797
  let index = this.tabs.indexOf(tab);
733
798
  if (index < 0)
734
799
  index = this.tabs.length; // this situation occurs when the tab hasn't yet been added to the tabs collection so the index will be = the length of the tabs collection
@@ -790,8 +855,9 @@ export class NavigationComponent {
790
855
  return __awaiter(this, void 0, void 0, function* () {
791
856
  const tabIndex = this.tabs.indexOf(tab);
792
857
  if (tabIndex >= 0) {
793
- this.removeWorkspaceItem(this.tabs[tabIndex], null /*no transaction group*/); // INTENTIONAL - do not use await here, we want to let the database updates happen in the background
794
- // await this.waitForDomUpdate(); // make sure dom is up to date
858
+ // INTENTIONAL - do not use await here, we want to let the database updates happen in the background
859
+ this.removeWorkspaceItem(this.tabs[tabIndex], null /*no transaction group*/);
860
+ //await this.waitForDomUpdate(); // make sure dom is up to date
795
861
  // now, check to see how many tabs we have left and if we have none, then we need to select the HOME tab
796
862
  if (this.tabs.length > 0) {
797
863
  if (newTabIndex === 0) {
@@ -862,8 +928,6 @@ export class NavigationComponent {
862
928
  // make sure that the first tab is selected since this is showing stuff in the Home/Nav tab
863
929
  if (this.activeTabIndex !== 0) {
864
930
  this.activeTabIndex = 0;
865
- //this.tabstrip.selectTab(0);
866
- //this.renderer.selectRootElement(this.tabstrip.wrapper.nativeElement).focus()
867
931
  }
868
932
  this.setAppTitle(ev.item.text);
869
933
  }
@@ -878,9 +942,8 @@ export class NavigationComponent {
878
942
  this.mjTabStrip.SelectedTabIndex = index;
879
943
  }
880
944
  getEntityItemFromViewItem(viewItem) {
881
- let entityItem = null;
882
945
  for (let item of this.drawerItems) {
883
- if (item.id == viewItem.parentId) {
946
+ if (item.id === viewItem.parentId) {
884
947
  // got the parent, this is the entity
885
948
  return item;
886
949
  }
@@ -952,6 +1015,8 @@ export class NavigationComponent {
952
1015
  yield this.loadResourceType('Queries', 'Queries', '/queries', md.CurrentUser.ID);
953
1016
  // Files
954
1017
  yield this.loadFiles();
1018
+ // Lists
1019
+ yield this.loadLists();
955
1020
  // Settings
956
1021
  yield this.loadSettings(md);
957
1022
  this.loading = false;
@@ -993,6 +1058,18 @@ export class NavigationComponent {
993
1058
  this.drawerItems.push(drawerItem);
994
1059
  });
995
1060
  }
1061
+ loadLists() {
1062
+ return __awaiter(this, void 0, void 0, function* () {
1063
+ const drawerItem = {
1064
+ id: 'Lists',
1065
+ selected: false,
1066
+ text: 'Lists',
1067
+ path: '/lists',
1068
+ icon: "fa-solid fa-list"
1069
+ };
1070
+ this.drawerItems.push(drawerItem);
1071
+ });
1072
+ }
996
1073
  loadFiles() {
997
1074
  return __awaiter(this, void 0, void 0, function* () {
998
1075
  const rv = new RunView();
@@ -1039,7 +1116,7 @@ export class NavigationComponent {
1039
1116
  this.drawerItems.push(drawerItem);
1040
1117
  }
1041
1118
  else {
1042
- console.log("no resource type found for " + resourceType);
1119
+ LogStatus("no resource type found for " + resourceType);
1043
1120
  }
1044
1121
  });
1045
1122
  }
@@ -1061,7 +1138,7 @@ export class NavigationComponent {
1061
1138
  }
1062
1139
  }
1063
1140
  NavigationComponent.ɵfac = function NavigationComponent_Factory(t) { return new (t || NavigationComponent)(i0.ɵɵdirectiveInject(i1.Router), i0.ɵɵdirectiveInject(i1.ActivatedRoute), i0.ɵɵdirectiveInject(i2.SharedService), i0.ɵɵdirectiveInject(i3.Location), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i4.Title), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1064
- NavigationComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NavigationComponent, selectors: [["app-navigation"]], viewQuery: function NavigationComponent_Query(rf, ctx) { if (rf & 1) {
1141
+ NavigationComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NavigationComponent, selectors: [["mj-navigation"]], viewQuery: function NavigationComponent_Query(rf, ctx) { if (rf & 1) {
1065
1142
  i0.ɵɵviewQuery(DrawerComponent, 5);
1066
1143
  i0.ɵɵviewQuery(_c0, 5);
1067
1144
  i0.ɵɵviewQuery(_c1, 5);
@@ -1093,7 +1170,7 @@ NavigationComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: Navigat
1093
1170
  } }, dependencies: [i1.RouterOutlet, i3.NgClass, i3.NgIf, i3.NgStyle, i5.LoaderComponent, i6.FillContainer, i7.DrawerComponent, i7.DrawerContainerComponent, i7.DrawerContentComponent, i7.DrawerItemTemplateDirective, i8.SkipButtonComponent, i9.MJTabStripComponent, i9.MJTabBodyComponent, i9.MJTabComponent, i10.ResourceContainerComponent], styles: [".navigation-wrap[_ngcontent-%COMP%] {\n height: calc(100vh - 80px);\n width: 100%;\n overflow:hidden\n}\n\n.nav-tab-title[_ngcontent-%COMP%] {\n margin-left: 10px;\n}\n\n.drawer-item-icon[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n}\n\n.context-menu[_ngcontent-%COMP%] {\n position: fixed;\n z-index: 9999;\n background-color: #ffffff;\n border: 1px solid #ccc;\n padding: 3px 3px;\n box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);\n}\n\n.context-menu-item[_ngcontent-%COMP%] {\n padding: 8px 16px;\n cursor: pointer;\n}\n\n.context-menu-item[_ngcontent-%COMP%]:hover {\n background-color: #f1f1f1;\n}\n .navigation-wrap .drawer-container {\n background: var(--gray-color);\n}\n .navigation-wrap .drawer-container .k-content {\n padding: 25px;\n}\n .navigation-wrap .drawer-container .k-tabstrip-items-wrapper {\n background: var(--med-gray);\n padding-left: 20px;\n}\n .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item.k-active{\n border: 1px solid var(--light-gray);\n background: var(--light-gray);\n border-radius: 8px 8px 0 0;\n color: var(--blue-text);\n\n}\n .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item:hover {\n color: var(--blue-text);\n}\n\n .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item {\n\n background: var(--med-gray);\n border-radius: 0;\n border-right: 1px solid #909090;\n}\n\n.tab-resource[_ngcontent-%COMP%] {\n display: block;\n}"] });
1094
1171
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NavigationComponent, [{
1095
1172
  type: Component,
1096
- args: [{ selector: 'app-navigation', template: "<div class=\"navigation-wrap\" [ngClass]=\"{'waiting': loader}\" #drawerWrapper>\n <kendo-loader *ngIf=\"loading\" type=\"converging-spinner\" ></kendo-loader>\n <kendo-drawer-container *ngIf=\"!loading\" >\n <kendo-drawer\n #drawer\n [items]=\"drawerItems\"\n [mode]=\"mode\"\n [mini]=\"mini\"\n [animation]=\"false\"\n (select)=\"onDrawerSelect($event)\"\n [autoCollapse]=\"false\"\n >\n <ng-template kendoDrawerItemTemplate let-item>\n <div class=\"drawer-item-icon\">\n <span [class]=\"item.icon\"></span>\n </div>\n <div class=\"item-descr-wrap\" *ngIf=\"!mini\">\n <div>{{ item.text }}</div>\n <span class=\"item-descr\">{{ item.description }}</span>\n </div>\n </ng-template> \n </kendo-drawer>\n <kendo-drawer-content mjFillContainer>\n\n <mj-tabstrip #mjTabstrip mjFillContainer (TabClosed)=\"handleTabClosed($event)\" (TabSelected)=\"handleTabSelected($event)\" (TabContextMenu)=\"handleTabContextMenu($event)\">\n <mj-tab [TabCloseable]=\"false\">\n Home\n </mj-tab>\n <mj-tab-body>\n <router-outlet></router-outlet>\n </mj-tab-body>\n\n @for(tab of tabs; track tab.id; let i = $index) {\n <mj-tab [TabCloseable]=\"true\">\n @if(tab?.contentLoading) {\n <span class=\"fa-regular fa-clock\"></span>\n }\n @else if (tab?.icon) {\n <span [class]=\"tab.icon\"></span>\n }\n {{ tab.labelLoading ? 'Loading...' : tab.label }}\n </mj-tab>\n }\n @for(tab of tabs; track tab.id; let i = $index) {\n <mj-tab-body>\n <mj-resource [Data]=\"tab.data\" [isVisible]=\"activeTabIndex - 1 === i\"\n (ResourceRecordSaved)=\"SaveSingleWorkspaceItem(tab)\"\n (ContentLoadingStarted)=\"setTabContentLoadingStatus(tab, true)\"\n (ContentLoadingComplete)=\"setTabContentLoadingStatus(tab, false)\"\n mjFillContainer\n class=\"tab-resource\"\n ></mj-resource>\n </mj-tab-body> \n }\n </mj-tabstrip>\n </kendo-drawer-content>\n </kendo-drawer-container>\n\n \n <mj-skip-button\n action=\"route\"\n ></mj-skip-button>\n <!-- Skip Button shows up through the above line of code -->\n</div>\n\n<div class=\"context-menu\" [ngStyle]=\"contextMenuStyle\" *ngIf=\"contextMenuVisible\">\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(1)\">Close All</div>\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(2)\">Close Others</div>\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(3)\">Close Tabs to the Right</div>\n </div>\n", styles: [".navigation-wrap {\n height: calc(100vh - 80px);\n width: 100%;\n overflow:hidden\n}\n\n.nav-tab-title {\n margin-left: 10px;\n}\n\n.drawer-item-icon {\n width: 12px;\n height: 12px;\n}\n\n.context-menu {\n position: fixed;\n z-index: 9999;\n background-color: #ffffff;\n border: 1px solid #ccc;\n padding: 3px 3px;\n box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);\n}\n\n.context-menu-item {\n padding: 8px 16px;\n cursor: pointer;\n}\n\n.context-menu-item:hover {\n background-color: #f1f1f1;\n}\n::ng-deep .navigation-wrap .drawer-container {\n background: var(--gray-color);\n}\n::ng-deep .navigation-wrap .drawer-container .k-content {\n padding: 25px;\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper {\n background: var(--med-gray);\n padding-left: 20px;\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item.k-active{\n border: 1px solid var(--light-gray);\n background: var(--light-gray);\n border-radius: 8px 8px 0 0;\n color: var(--blue-text);\n\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item:hover {\n color: var(--blue-text);\n}\n\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item {\n\n background: var(--med-gray);\n border-radius: 0;\n border-right: 1px solid #909090;\n}\n\n.tab-resource {\n display: block;\n}"] }]
1173
+ args: [{ selector: 'mj-navigation', template: "<div class=\"navigation-wrap\" [ngClass]=\"{'waiting': loader}\" #drawerWrapper>\n <kendo-loader *ngIf=\"loading\" type=\"converging-spinner\" ></kendo-loader>\n <kendo-drawer-container *ngIf=\"!loading\" >\n <kendo-drawer\n #drawer\n [items]=\"drawerItems\"\n [mode]=\"mode\"\n [mini]=\"mini\"\n [animation]=\"false\"\n (select)=\"onDrawerSelect($event)\"\n [autoCollapse]=\"false\"\n >\n <ng-template kendoDrawerItemTemplate let-item>\n <div class=\"drawer-item-icon\">\n <span [class]=\"item.icon\"></span>\n </div>\n <div class=\"item-descr-wrap\" *ngIf=\"!mini\">\n <div>{{ item.text }}</div>\n <span class=\"item-descr\">{{ item.description }}</span>\n </div>\n </ng-template> \n </kendo-drawer>\n <kendo-drawer-content mjFillContainer>\n\n <mj-tabstrip #mjTabstrip mjFillContainer (TabClosed)=\"handleTabClosed($event)\" (TabSelected)=\"handleTabSelected($event)\" (TabContextMenu)=\"handleTabContextMenu($event)\">\n <mj-tab [TabCloseable]=\"false\">\n Home\n </mj-tab>\n <mj-tab-body>\n <router-outlet></router-outlet>\n </mj-tab-body>\n\n @for(tab of tabs; track tab.id; let i = $index) {\n <mj-tab [TabCloseable]=\"true\">\n @if(tab?.contentLoading) {\n <span class=\"fa-regular fa-clock\"></span>\n }\n @else if (tab?.icon) {\n <span [class]=\"tab.icon\"></span>\n }\n {{ tab.labelLoading ? 'Loading...' : tab.label }}\n </mj-tab>\n }\n @for(tab of tabs; track tab.id; let i = $index) {\n <mj-tab-body>\n <mj-resource [Data]=\"tab.data\" [isVisible]=\"activeTabIndex - 1 === i\"\n (ResourceRecordSaved)=\"HandleResourceRecordSaved(tab, $event)\"\n (ContentLoadingStarted)=\"setTabContentLoadingStatus(tab, true)\"\n (ContentLoadingComplete)=\"setTabContentLoadingStatus(tab, false)\"\n mjFillContainer\n class=\"tab-resource\"\n ></mj-resource>\n </mj-tab-body> \n }\n </mj-tabstrip>\n </kendo-drawer-content>\n </kendo-drawer-container>\n\n \n <mj-skip-button\n action=\"route\"\n ></mj-skip-button>\n <!-- Skip Button shows up through the above line of code -->\n</div>\n\n<div class=\"context-menu\" [ngStyle]=\"contextMenuStyle\" *ngIf=\"contextMenuVisible\">\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(1)\">Close All</div>\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(2)\">Close Others</div>\n <div class=\"context-menu-item\" (click)=\"handleContextMenuOption(3)\">Close Tabs to the Right</div>\n </div>\n", styles: [".navigation-wrap {\n height: calc(100vh - 80px);\n width: 100%;\n overflow:hidden\n}\n\n.nav-tab-title {\n margin-left: 10px;\n}\n\n.drawer-item-icon {\n width: 12px;\n height: 12px;\n}\n\n.context-menu {\n position: fixed;\n z-index: 9999;\n background-color: #ffffff;\n border: 1px solid #ccc;\n padding: 3px 3px;\n box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);\n}\n\n.context-menu-item {\n padding: 8px 16px;\n cursor: pointer;\n}\n\n.context-menu-item:hover {\n background-color: #f1f1f1;\n}\n::ng-deep .navigation-wrap .drawer-container {\n background: var(--gray-color);\n}\n::ng-deep .navigation-wrap .drawer-container .k-content {\n padding: 25px;\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper {\n background: var(--med-gray);\n padding-left: 20px;\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item.k-active{\n border: 1px solid var(--light-gray);\n background: var(--light-gray);\n border-radius: 8px 8px 0 0;\n color: var(--blue-text);\n\n}\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item:hover {\n color: var(--blue-text);\n}\n\n::ng-deep .navigation-wrap .drawer-container .k-tabstrip-items-wrapper .k-item {\n\n background: var(--med-gray);\n border-radius: 0;\n border-right: 1px solid #909090;\n}\n\n.tab-resource {\n display: block;\n}"] }]
1097
1174
  }], () => [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.SharedService }, { type: i3.Location }, { type: i0.Renderer2 }, { type: i4.Title }, { type: i0.ChangeDetectorRef }], { applicationName: [{
1098
1175
  type: Input
1099
1176
  }], isMobileScreen: [{
@@ -3,8 +3,8 @@ import { CompositeKey } from '@memberjunction/core';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare function LoadRecordResource(): void;
5
5
  export declare class EntityRecordResource extends BaseResourceComponent {
6
- get CompositeKey(): CompositeKey;
7
- static GetCompositeKey(data: ResourceData): CompositeKey;
6
+ get PrimaryKey(): CompositeKey;
7
+ static GetPrimaryKey(data: ResourceData): CompositeKey;
8
8
  GetResourceDisplayName(data: ResourceData): Promise<string>;
9
9
  static ɵfac: i0.ɵɵFactoryDeclaration<EntityRecordResource, never>;
10
10
  static ɵcmp: i0.ɵɵComponentDeclaration<EntityRecordResource, "mj-record-resource", never, {}, {}, never, never, false, never>;
@@ -1 +1 @@
1
- {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEhF,OAAO,EAAY,YAAY,EAAE,MAAM,sBAAsB,CAAC;;AAE9D,wBAAgB,kBAAkB,SAEjC;AAED,qBAKa,oBAAqB,SAAQ,qBAAqB;IAC3D,IAAW,YAAY,IAAI,YAAY,CAEtC;WAEa,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY;IAYzD,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCAjBxD,oBAAoB;2CAApB,oBAAoB;CA6BhC"}
1
+ {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEhF,OAAO,EAAY,YAAY,EAAE,MAAM,sBAAsB,CAAC;;AAE9D,wBAAgB,kBAAkB,SAEjC;AAED,qBAKa,oBAAqB,SAAQ,qBAAqB;IAC3D,IAAW,UAAU,IAAI,YAAY,CAEpC;WAEa,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY;IAYvD,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCAjBxD,oBAAoB;2CAApB,oBAAoB;CAiChC"}
@@ -25,10 +25,10 @@ export function LoadRecordResource() {
25
25
  const test = new EntityRecordResource(); // this looks really dumb. Thing is, in production builds, tree shaking causes the class below to not be included in the bundle. This is a hack to force it to be included.
26
26
  }
27
27
  let EntityRecordResource = EntityRecordResource_1 = class EntityRecordResource extends BaseResourceComponent {
28
- get CompositeKey() {
29
- return EntityRecordResource_1.GetCompositeKey(this.Data);
28
+ get PrimaryKey() {
29
+ return EntityRecordResource_1.GetPrimaryKey(this.Data);
30
30
  }
31
- static GetCompositeKey(data) {
31
+ static GetPrimaryKey(data) {
32
32
  const md = new Metadata();
33
33
  const e = md.Entities.find(e => e.Name.trim().toLowerCase() === data.Configuration.Entity.trim().toLowerCase());
34
34
  if (!e) {
@@ -45,21 +45,25 @@ let EntityRecordResource = EntityRecordResource_1 = class EntityRecordResource e
45
45
  }
46
46
  else {
47
47
  const md = new Metadata();
48
- let compositeKey = EntityRecordResource_1.GetCompositeKey(data);
49
- const name = yield md.GetEntityRecordName(data.Configuration.Entity, compositeKey);
50
- const displayId = compositeKey.KeyValuePairs.length > 1 ? compositeKey.Values() : compositeKey.GetValueByIndex(0);
51
- return (name ? name : data.Configuration.Entity) + ` (${displayId})`;
48
+ let pk = EntityRecordResource_1.GetPrimaryKey(data);
49
+ if (pk.HasValue) {
50
+ const name = yield md.GetEntityRecordName(data.Configuration.Entity, pk);
51
+ const displayId = pk.KeyValuePairs.length > 1 ? pk.Values() : pk.GetValueByIndex(0);
52
+ return (name ? name : data.Configuration.Entity) + ` (${displayId})`;
53
+ }
54
+ else
55
+ return `New ${data.Configuration.Entity} Record`;
52
56
  }
53
57
  });
54
58
  }
55
59
  };
56
60
  EntityRecordResource.ɵfac = /*@__PURE__*/ (() => { let ɵEntityRecordResource_BaseFactory; return function EntityRecordResource_Factory(t) { return (ɵEntityRecordResource_BaseFactory || (ɵEntityRecordResource_BaseFactory = i0.ɵɵgetInheritedFactory(EntityRecordResource)))(t || EntityRecordResource); }; })();
57
- EntityRecordResource.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityRecordResource, selectors: [["mj-record-resource"]], features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 2, consts: [["mjFillContainer", "", 3, "CompositeKey", "entityName", "loadComplete"]], template: function EntityRecordResource_Template(rf, ctx) { if (rf & 1) {
61
+ EntityRecordResource.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityRecordResource, selectors: [["mj-record-resource"]], features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 3, consts: [["mjFillContainer", "", 3, "PrimaryKey", "entityName", "newRecordValues", "loadComplete", "recordSaved"]], template: function EntityRecordResource_Template(rf, ctx) { if (rf & 1) {
58
62
  i0.ɵɵelementStart(0, "mj-single-record", 0);
59
- i0.ɵɵlistener("loadComplete", function EntityRecordResource_Template_mj_single_record_loadComplete_0_listener() { return ctx.NotifyLoadComplete(); });
63
+ i0.ɵɵlistener("loadComplete", function EntityRecordResource_Template_mj_single_record_loadComplete_0_listener() { return ctx.NotifyLoadComplete(); })("recordSaved", function EntityRecordResource_Template_mj_single_record_recordSaved_0_listener($event) { return ctx.ResourceRecordSaved($event); });
60
64
  i0.ɵɵelementEnd();
61
65
  } if (rf & 2) {
62
- i0.ɵɵproperty("CompositeKey", ctx.CompositeKey)("entityName", ctx.Data.Configuration.Entity);
66
+ i0.ɵɵproperty("PrimaryKey", ctx.PrimaryKey)("entityName", ctx.Data.Configuration.Entity)("newRecordValues", ctx.Data.Configuration.NewRecordValues);
63
67
  } }, dependencies: [i1.FillContainer, i2.SingleRecordComponent], encapsulation: 2 });
64
68
  EntityRecordResource = EntityRecordResource_1 = __decorate([
65
69
  RegisterClass(BaseResourceComponent, 'Records')
@@ -69,7 +73,7 @@ export { EntityRecordResource };
69
73
  type: Component,
70
74
  args: [{
71
75
  selector: 'mj-record-resource',
72
- template: `<mj-single-record [CompositeKey]="this.CompositeKey" [entityName]="Data.Configuration.Entity" (loadComplete)="NotifyLoadComplete()" mjFillContainer></mj-single-record>`
76
+ template: `<mj-single-record [PrimaryKey]="this.PrimaryKey" [entityName]="Data.Configuration.Entity" [newRecordValues]="Data.Configuration.NewRecordValues" (loadComplete)="NotifyLoadComplete()" (recordSaved)="ResourceRecordSaved($event)" mjFillContainer></mj-single-record>`
73
77
  }]
74
78
  }], null, null); })();
75
79
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityRecordResource, { className: "EntityRecordResource", filePath: "src/lib/resource-wrappers/record-resource.component.ts", lineNumber: 15 }); })();
@@ -0,0 +1,26 @@
1
+ import { OnInit } from '@angular/core';
2
+ import { Router, ActivatedRoute } from '@angular/router';
3
+ import { BaseEntity } from '@memberjunction/core';
4
+ import { SharedService } from '@memberjunction/ng-shared';
5
+ import * as i0 from "@angular/core";
6
+ export declare class SingleListDetailComponent implements OnInit {
7
+ private router;
8
+ private route;
9
+ private sharedService;
10
+ private listRecord;
11
+ showLoader: boolean;
12
+ gridData: BaseEntity[];
13
+ listName: string;
14
+ showAddDialog: boolean;
15
+ showAddLoader: boolean;
16
+ userViews: BaseEntity[];
17
+ selectedUserView: BaseEntity | null;
18
+ constructor(router: Router, route: ActivatedRoute, sharedService: SharedService);
19
+ ngOnInit(): Promise<void>;
20
+ toggleAddDialog(show: boolean): Promise<void>;
21
+ addTolist(): Promise<void>;
22
+ private loadEntityViews;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<SingleListDetailComponent, never>;
24
+ static ɵcmp: i0.ɵɵComponentDeclaration<SingleListDetailComponent, "mj-list-detail", never, {}, {}, never, never, false, never>;
25
+ }
26
+ //# sourceMappingURL=single-list-detail.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-list-detail.component.d.ts","sourceRoot":"","sources":["../../../src/lib/single-list-detail/single-list-detail.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,UAAU,EAA0D,MAAM,sBAAsB,CAAC;AAE1G,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;;AAE1D,qBAKa,yBAA0B,YAAW,MAAM;IAWvC,OAAO,CAAC,MAAM;IAAU,OAAO,CAAC,KAAK;IAAkB,OAAO,CAAC,aAAa;IAVzF,OAAO,CAAC,UAAU,CAA2B;IAEtC,UAAU,EAAE,OAAO,CAAS;IAC5B,QAAQ,EAAE,UAAU,EAAE,CAAM;IAC5B,QAAQ,EAAE,MAAM,CAAM;IACtB,aAAa,EAAE,OAAO,CAAS;IAC/B,aAAa,EAAE,OAAO,CAAS;IAC/B,SAAS,EAAE,UAAU,EAAE,CAAM;IAC7B,gBAAgB,EAAE,UAAU,GAAG,IAAI,CAAQ;gBAE7B,MAAM,EAAE,MAAM,EAAU,KAAK,EAAE,cAAc,EAAU,aAAa,EAAE,aAAa;IAE3F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAiEzB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7C,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;YAsBzB,eAAe;yCA7GpB,yBAAyB;2CAAzB,yBAAyB;CAsIrC"}