@memberjunction/ng-dashboards 5.47.0 → 5.49.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 (67) hide show
  1. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +15 -4
  2. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  3. package/dist/DataExplorer/data-explorer-dashboard.component.js +45 -35
  4. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  5. package/dist/DataExplorer/models/explorer-state.interface.d.ts +7 -0
  6. package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
  7. package/dist/DataExplorer/models/explorer-state.interface.js.map +1 -1
  8. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +2 -2
  9. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
  10. package/dist/Lists/components/lists-browse-resource.component.d.ts +4 -0
  11. package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
  12. package/dist/Lists/components/lists-browse-resource.component.js +39 -30
  13. package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
  14. package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
  15. package/dist/Lists/components/lists-my-lists-resource.component.js +14 -12
  16. package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
  17. package/dist/Lists/components/lists-operations-resource.component.d.ts.map +1 -1
  18. package/dist/Lists/components/lists-operations-resource.component.js +6 -1
  19. package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
  20. package/dist/Lists/services/list-set-operations.service.d.ts +11 -0
  21. package/dist/Lists/services/list-set-operations.service.d.ts.map +1 -1
  22. package/dist/Lists/services/list-set-operations.service.js +56 -14
  23. package/dist/Lists/services/list-set-operations.service.js.map +1 -1
  24. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +7 -1
  25. package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
  26. package/dist/PredictiveStudio/components/ps-pipelines.component.js +11 -4
  27. package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
  28. package/dist/Testing/components/testing-runs.component.d.ts.map +1 -1
  29. package/dist/Testing/components/testing-runs.component.js +35 -25
  30. package/dist/Testing/components/testing-runs.component.js.map +1 -1
  31. package/dist/Testing/services/testing-instrumentation.service.d.ts +5 -0
  32. package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -1
  33. package/dist/Testing/services/testing-instrumentation.service.js +8 -2
  34. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
  35. package/dist/ThemeStudio/theme-agent-context.d.ts +64 -0
  36. package/dist/ThemeStudio/theme-agent-context.d.ts.map +1 -0
  37. package/dist/ThemeStudio/theme-agent-context.js +129 -0
  38. package/dist/ThemeStudio/theme-agent-context.js.map +1 -0
  39. package/dist/ThemeStudio/theme-manager-dashboard.component.d.ts +62 -0
  40. package/dist/ThemeStudio/theme-manager-dashboard.component.d.ts.map +1 -0
  41. package/dist/ThemeStudio/theme-manager-dashboard.component.js +464 -0
  42. package/dist/ThemeStudio/theme-manager-dashboard.component.js.map +1 -0
  43. package/dist/ThemeStudio/theme-manager-resource.component.d.ts +31 -0
  44. package/dist/ThemeStudio/theme-manager-resource.component.d.ts.map +1 -0
  45. package/dist/ThemeStudio/theme-manager-resource.component.js +97 -0
  46. package/dist/ThemeStudio/theme-manager-resource.component.js.map +1 -0
  47. package/dist/ThemeStudio/theme-studio-dashboard.component.d.ts +351 -0
  48. package/dist/ThemeStudio/theme-studio-dashboard.component.d.ts.map +1 -0
  49. package/dist/ThemeStudio/theme-studio-dashboard.component.js +2931 -0
  50. package/dist/ThemeStudio/theme-studio-dashboard.component.js.map +1 -0
  51. package/dist/ThemeStudio/theme-studio-resource.component.d.ts +28 -0
  52. package/dist/ThemeStudio/theme-studio-resource.component.d.ts.map +1 -0
  53. package/dist/ThemeStudio/theme-studio-resource.component.js +96 -0
  54. package/dist/ThemeStudio/theme-studio-resource.component.js.map +1 -0
  55. package/dist/ThemeStudio/theme-studio.constants.d.ts +79 -0
  56. package/dist/ThemeStudio/theme-studio.constants.d.ts.map +1 -0
  57. package/dist/ThemeStudio/theme-studio.constants.js +217 -0
  58. package/dist/ThemeStudio/theme-studio.constants.js.map +1 -0
  59. package/dist/core-dashboards.module.d.ts +56 -52
  60. package/dist/core-dashboards.module.d.ts.map +1 -1
  61. package/dist/core-dashboards.module.js +24 -1
  62. package/dist/core-dashboards.module.js.map +1 -1
  63. package/dist/public-api.d.ts +4 -0
  64. package/dist/public-api.d.ts.map +1 -1
  65. package/dist/public-api.js +4 -0
  66. package/dist/public-api.js.map +1 -1
  67. package/package.json +63 -60
@@ -4,9 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
+ var ListsBrowseResource_1;
7
8
  import { Component, ViewEncapsulation, HostListener } from '@angular/core';
8
9
  import { RegisterClass, UUIDsEqual, MJGlobal } from '@memberjunction/global';
9
10
  import { BaseResourceComponent } from '@memberjunction/ng-shared';
11
+ import { UserInfoEngine } from '@memberjunction/core-entities';
10
12
  import { BaseEntity, RunView } from '@memberjunction/core';
11
13
  import { Subject } from 'rxjs';
12
14
  import { takeUntil } from 'rxjs/operators';
@@ -778,6 +780,7 @@ function ListsBrowseResource_Conditional_30_Template(rf, ctx) { if (rf & 1) {
778
780
  i0.ɵɵconditional(ctx_r2.filteredEntitiesList.length === 0 ? 4 : -1);
779
781
  } }
780
782
  let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponent {
783
+ static { ListsBrowseResource_1 = this; }
781
784
  cdr;
782
785
  tabService;
783
786
  notificationService;
@@ -912,8 +915,17 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
912
915
  this.closeEntityDropdown();
913
916
  }
914
917
  }
918
+ /** User-preference key for the favorites-only filter (F5a) — server-persisted so it survives reloads and follows the user across devices. */
919
+ static FAVORITES_FILTER_PREF_KEY = 'mj.lists.browse.showOnlyFavorites';
920
+ /** Persists the current favorites-filter state as a user preference (debounced). */
921
+ persistFavoritesFilter() {
922
+ UserInfoEngine.Instance.SetSettingDebounced(ListsBrowseResource_1.FAVORITES_FILTER_PREF_KEY, String(this.showOnlyFavorites));
923
+ }
915
924
  async ngOnInit() {
916
925
  super.ngOnInit();
926
+ // Restore the favorites-only filter preference (synchronous cache hit —
927
+ // UserInfoEngine is populated during app bootstrap)
928
+ this.showOnlyFavorites = UserInfoEngine.Instance.GetSetting(ListsBrowseResource_1.FAVORITES_FILTER_PREF_KEY) === 'true';
917
929
  this.subscribeToCategoryChanges();
918
930
  await this.loadData();
919
931
  this.registerAgentTools();
@@ -1130,12 +1142,14 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1130
1142
  const md = this.ProviderToUse;
1131
1143
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1132
1144
  this.currentUserId = md.CurrentUser?.ID || '';
1133
- // BypassCache on Lists + List Details: after a delete/duplicate, the
1134
- // RunView cache for these entities doesn't always reflect the latest
1135
- // state in time (event-driven invalidation races the immediate
1136
- // refresh). Trading a small perf hit for correctness here is worth
1137
- // it categories and users stay cache-warm.
1138
- const [listsResult, categoriesResult, detailsResult, usersResult] = await rv.RunViews([
1145
+ // BypassCache on Lists: after a delete/duplicate, the RunView cache
1146
+ // for this entity doesn't always reflect the latest state in time
1147
+ // (event-driven invalidation races the immediate refresh). Trading a
1148
+ // small perf hit for correctness here is worth it — categories stay
1149
+ // cache-warm. Owner names come from the denormalized `User` view
1150
+ // field on each list, and item counts from batched COUNT queries —
1151
+ // this deliberately does NOT download List Details or Users rows.
1152
+ const [listsResult, categoriesResult] = await rv.RunViews([
1139
1153
  {
1140
1154
  EntityName: 'MJ: Lists',
1141
1155
  OrderBy: 'Name',
@@ -1146,17 +1160,6 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1146
1160
  EntityName: 'MJ: List Categories',
1147
1161
  OrderBy: 'Name',
1148
1162
  ResultType: 'entity_object'
1149
- },
1150
- {
1151
- EntityName: 'MJ: List Details',
1152
- Fields: ['ListID'],
1153
- ResultType: 'simple',
1154
- BypassCache: true
1155
- },
1156
- {
1157
- EntityName: 'MJ: Users',
1158
- Fields: ['ID', 'Name'],
1159
- ResultType: 'simple'
1160
1163
  }
1161
1164
  ]);
1162
1165
  if (!listsResult.Success) {
@@ -1165,8 +1168,6 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1165
1168
  }
1166
1169
  const lists = listsResult.Results;
1167
1170
  this.categories = (categoriesResult.Results || []);
1168
- const details = (detailsResult.Results || []);
1169
- const users = (usersResult.Results || []);
1170
1171
  // Build category map
1171
1172
  this.categoryMap.clear();
1172
1173
  for (const cat of this.categories) {
@@ -1177,16 +1178,20 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1177
1178
  // loadData() already pulled fresh categories — clear the dirty
1178
1179
  // flag so the first dialog open doesn't redundantly refetch.
1179
1180
  this.categoriesDirty = false;
1180
- // Build user map
1181
- const userMap = new Map();
1182
- for (const user of users) {
1183
- userMap.set(user.ID, user.Name);
1184
- }
1185
- // Count items per list
1181
+ // Per-list item counts: one batched round trip of count_only queries
1182
+ // (each an index-seek COUNT on ListDetail.ListID server-side) instead
1183
+ // of transferring every membership row to the client.
1186
1184
  const itemCounts = new Map();
1187
- for (const detail of details) {
1188
- const count = itemCounts.get(detail.ListID) || 0;
1189
- itemCounts.set(detail.ListID, count + 1);
1185
+ if (lists.length > 0) {
1186
+ const countResults = await rv.RunViews(lists.map(list => ({
1187
+ EntityName: 'MJ: List Details',
1188
+ ExtraFilter: `ListID = '${list.ID}'`,
1189
+ ResultType: 'count_only',
1190
+ BypassCache: true
1191
+ })));
1192
+ countResults.forEach((res, idx) => {
1193
+ itemCounts.set(lists[idx].ID, res.Success ? res.TotalRowCount : 0);
1194
+ });
1190
1195
  }
1191
1196
  // Build entity info
1192
1197
  const entities = md.Entities;
@@ -1209,7 +1214,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1209
1214
  list,
1210
1215
  itemCount: itemCounts.get(list.ID) || 0,
1211
1216
  entityName,
1212
- ownerName: userMap.get(list.UserID) || 'Unknown',
1217
+ ownerName: list.User || 'Unknown',
1213
1218
  isOwner: UUIDsEqual(list.UserID, this.currentUserId)
1214
1219
  };
1215
1220
  });
@@ -1344,6 +1349,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1344
1349
  this.selectedOwner = values['selectedOwner'] ?? 'mine';
1345
1350
  this.selectedEntity = values['selectedEntity'] ?? 'all';
1346
1351
  this.showOnlyFavorites = values['favorites'] === 'favorites';
1352
+ this.persistFavoritesFilter();
1347
1353
  this.applyFilters();
1348
1354
  this.buildCategoryTree();
1349
1355
  this.publishAgentContext();
@@ -1353,6 +1359,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1353
1359
  this.selectedOwner = 'mine';
1354
1360
  this.selectedEntity = 'all';
1355
1361
  this.showOnlyFavorites = false;
1362
+ this.persistFavoritesFilter();
1356
1363
  this.applyFilters();
1357
1364
  this.buildCategoryTree();
1358
1365
  }
@@ -1374,6 +1381,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1374
1381
  this.selectedOwner = 'mine';
1375
1382
  this.selectedEntity = 'all';
1376
1383
  this.showOnlyFavorites = false;
1384
+ this.persistFavoritesFilter();
1377
1385
  this.tagFilters = [];
1378
1386
  void this.recomputeTagMembership();
1379
1387
  this.buildCategoryTree();
@@ -1411,6 +1419,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
1411
1419
  this.selectedEntity = 'all';
1412
1420
  this.selectedOwner = 'mine';
1413
1421
  this.showOnlyFavorites = false;
1422
+ this.persistFavoritesFilter();
1414
1423
  this.tagFilters = [];
1415
1424
  void this.recomputeTagMembership(); // empty tagFilters → clears tagFilteredListIds + re-applies
1416
1425
  this.buildCategoryTree();
@@ -2202,7 +2211,7 @@ let ListsBrowseResource = class ListsBrowseResource extends BaseResourceComponen
2202
2211
  i0.ɵɵconditional(ctx.showEntityDropdown && !ctx.editingList ? 30 : -1);
2203
2212
  } }, dependencies: [i4.NgTemplateOutlet, i5.NgSelectOption, i5.ɵNgSelectMultipleOption, i5.DefaultValueAccessor, i5.SelectControlValueAccessor, i5.NgControlStatus, i5.NgModel, i6.MJButtonDirective, i6.MJDialogComponent, i6.MJDialogActionsComponent, i6.MJPageLayoutComponent, i6.MJPageHeaderComponent, i6.MJPageBodyComponent, i6.MJPageSearchComponent, i6.MJFilterPopoverComponent, i6.MJFilterPanelComponent, i6.MJViewToggleComponent, i6.MJStatBadgeComponent, i6.MJEmptyStateComponent, i7.LoadingComponent, i3.ListAuditLogComponent, i3.ListInvitationsComponent, i3.ListShareDialogComponent, i3.TagChipsComponent], styles: ["\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n }\n\n /* Control bar: on mobile search grows so the icon-only Filter + view toggle\n stay on one line. On desktop search keeps its natural width. */\n @media (max-width: 768px) {\n mj-page-search {\n flex: 1;\n }\n }\n\n .lists-browse-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n overflow: hidden;\n }\n\n /* Header */\n .browse-header {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n }\n\n .header-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-title i {\n font-size: 24px;\n color: var(--mj-brand-primary);\n }\n\n .header-title h2 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .header-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n }\n\n .search-box {\n position: relative;\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 200px;\n max-width: 300px;\n }\n\n .search-box i.fa-search {\n position: absolute;\n left: 12px;\n color: var(--mj-text-muted);\n }\n\n .search-box input {\n padding: 8px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: 20px;\n font-size: 14px;\n width: 100%;\n transition: border-color 0.2s, box-shadow 0.2s;\n }\n\n .search-box input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .clear-search {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n }\n\n .filter-group {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .filter-group label {\n font-size: 13px;\n color: var(--mj-text-secondary);\n }\n\n .filter-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n background: var(--mj-bg-surface-card);\n cursor: pointer;\n min-width: 120px;\n }\n\n .filter-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .sort-select {\n min-width: 140px;\n }\n\n .view-toggle-group {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n }\n\n .view-toggle {\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: none;\n border-right: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .view-toggle:last-child {\n border-right: none;\n }\n\n .view-toggle:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .view-toggle.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n }\n\n .btn-create {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .btn-create:hover {\n background: var(--mj-brand-primary-hover);\n }\n\n /* Loading */\n .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n }\n\n /* Onboarding feature checklist \u2014 projected into <mj-empty-state>. */\n .empty-state-features {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2);\n margin: var(--mj-space-5) 0 var(--mj-space-2);\n text-align: left;\n }\n\n .feature-item {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n }\n\n .feature-item i {\n font-size: 14px !important;\n color: var(--mj-status-success) !important;\n }\n\n /* Content */\n .browse-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 24px;\n }\n\n .results-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n }\n\n .result-count {\n font-size: 14px;\n color: var(--mj-text-secondary);\n }\n\n .sort-options {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .sort-options label {\n font-size: 13px;\n color: var(--mj-text-secondary);\n }\n\n /* Table View */\n .lists-table {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n overflow: hidden;\n box-shadow: var(--mj-shadow-sm);\n }\n\n .lists-table table {\n width: 100%;\n border-collapse: collapse;\n }\n\n .lists-table th {\n text-align: left;\n padding: 12px 16px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .lists-table td {\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 14px;\n color: var(--mj-text-primary);\n }\n\n .list-row {\n cursor: pointer;\n transition: background 0.15s;\n outline: none;\n }\n\n .list-row:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .list-row:focus {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n }\n\n .list-row:focus-visible {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n box-shadow: inset 3px 0 0 var(--mj-brand-primary);\n }\n\n .list-row:last-child td {\n border-bottom: none;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .col-name { width: 30%; }\n .col-entity { width: 15%; }\n .col-items { width: 8%; text-align: center; }\n .col-sharing { width: 8%; text-align: center; }\n .col-owner { width: 14%; }\n .col-updated { width: 15%; }\n .col-actions { width: 10%; text-align: right; }\n\n /* Sharing indicators */\n .sharing-indicator {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-brand-primary);\n font-size: 13px;\n }\n\n .sharing-indicator i {\n font-size: 14px;\n }\n\n .share-count {\n font-weight: 500;\n }\n\n .sharing-private {\n color: var(--mj-text-muted);\n font-size: 13px;\n }\n\n .sharing-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 50%;\n color: var(--mj-brand-primary);\n font-size: 11px;\n }\n\n .card-footer-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .name-cell {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .list-icon {\n width: 36px;\n height: 36px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 14px;\n flex-shrink: 0;\n }\n\n .name-content {\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n\n .list-name {\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .list-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .entity-badge {\n display: inline-block;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 4px;\n font-size: 12px;\n color: var(--mj-brand-primary-hover);\n }\n\n .owner-name {\n color: var(--mj-text-secondary);\n }\n\n .owner-name.is-me {\n color: var(--mj-brand-primary);\n font-weight: 500;\n }\n\n .action-btn {\n background: none;\n border: none;\n padding: 6px 10px;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.15s;\n }\n\n .action-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-secondary);\n }\n\n /* Card View */\n .lists-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 16px;\n }\n\n .list-card {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n cursor: pointer;\n transition: transform 0.2s, box-shadow 0.2s, outline 0.1s;\n outline: 2px solid transparent;\n }\n\n .list-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--mj-shadow-md);\n }\n\n .list-card:focus {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n }\n\n .list-card:focus:not(:focus-visible) {\n outline: none;\n }\n\n .list-card:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n }\n\n .card-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 16px 16px 0;\n }\n\n .card-icon {\n width: 40px;\n height: 40px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 18px;\n }\n\n .menu-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 4px;\n }\n\n .menu-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n }\n\n .card-body {\n padding: 12px 16px;\n }\n\n .card-title {\n margin: 0 0 4px;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .card-description {\n margin: 0 0 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .card-meta {\n display: flex;\n gap: 16px;\n }\n\n .meta-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n\n /* Tag chips on a card. Stop-propagation is set on the wrapper so\n clicks on chips don't open the underlying list. */\n .card-tags {\n margin-top: 8px;\n }\n\n /* Favorite star on cards (Phase 5.3). */\n .favorite-btn {\n background: none;\n border: none;\n padding: 4px;\n margin: -4px;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 14px;\n border-radius: 4px;\n transition: color 0.12s ease, background 0.12s ease;\n }\n\n .favorite-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-status-warning);\n }\n\n .favorite-btn--active {\n color: var(--mj-status-warning);\n }\n\n /* Favorites-only toggle in the toolbar. */\n .favorite-filter-toggle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: none;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12.5px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n }\n\n .favorite-filter-toggle:hover {\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n }\n\n .favorite-filter-toggle--active {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n font-weight: 600;\n }\n\n /* Active-tag filter row above the grid (Phase 4.3). */\n .tag-filter-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n margin-bottom: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px dashed var(--mj-border-default);\n border-radius: 8px;\n font-size: 12.5px;\n }\n\n .tag-filter-row__label {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-muted);\n font-weight: 500;\n }\n\n .tag-filter-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n font-size: 11.5px;\n cursor: pointer;\n }\n\n .tag-filter-chip:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 20%, var(--mj-bg-surface));\n }\n\n .tag-filter-row__clear {\n background: none;\n border: none;\n color: var(--mj-text-link);\n font-size: 11.5px;\n cursor: pointer;\n margin-left: auto;\n }\n\n .tag-filter-row__clear:hover {\n text-decoration: underline;\n }\n\n .card-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n }\n\n .owner-tag {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n }\n\n .owner-tag.is-me {\n color: var(--mj-brand-primary);\n }\n\n .date-info {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n\n /* Hierarchy View */\n .category-tree {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .category-section {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n overflow: hidden;\n }\n\n .category-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .category-header:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .category-header i:first-child {\n width: 16px;\n text-align: center;\n color: var(--mj-text-muted);\n }\n\n .category-header .fa-folder,\n .category-header .fa-folder-open {\n color: var(--mj-status-warning);\n }\n\n .category-header.uncategorized .fa-inbox {\n color: var(--mj-text-muted);\n }\n\n .category-name {\n flex: 1;\n font-weight: 500;\n color: var(--mj-text-primary);\n }\n\n .category-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 10px;\n }\n\n .category-lists {\n border-top: 1px solid var(--mj-border-default);\n }\n\n .hierarchy-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px 12px 40px;\n cursor: pointer;\n transition: background 0.2s;\n outline: none;\n }\n\n .hierarchy-row:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .hierarchy-row:focus {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n }\n\n .hierarchy-row:focus-visible {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n box-shadow: inset 3px 0 0 var(--mj-brand-primary);\n }\n\n .list-info {\n flex: 1;\n min-width: 0;\n }\n\n .list-meta {\n font-size: 12px;\n color: var(--mj-text-muted);\n }\n\n .list-actions {\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.2s;\n }\n\n .hierarchy-row:hover .list-actions {\n opacity: 1;\n }\n\n /* Context Menu */\n .context-menu-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n }\n\n .context-menu {\n position: fixed;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n min-width: 160px;\n padding: 4px 0;\n z-index: 1000;\n }\n\n .menu-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 10px 16px;\n background: none;\n border: none;\n text-align: left;\n font-size: 14px;\n color: var(--mj-text-primary);\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .menu-item:hover {\n background: var(--mj-bg-surface-sunken);\n }\n\n .menu-item.danger {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n\n .menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n }\n\n .menu-viewer-hint {\n padding: 10px 14px;\n font-size: 12px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 8px;\n font-style: italic;\n }\n .menu-viewer-hint i { color: var(--mj-text-muted); }\n\n /* Modal Styles */\n .modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n }\n\n .modal-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: var(--mj-bg-surface-card);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-lg);\n width: 500px;\n max-width: 90vw;\n max-height: 90vh;\n overflow: hidden;\n z-index: 1001;\n }\n\n .confirm-dialog {\n width: 400px;\n }\n\n .modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n }\n\n .modal-close {\n background: none;\n border: none;\n padding: 4px 8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 4px;\n }\n\n .modal-close:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n }\n\n .modal-body {\n padding: 20px;\n max-height: 60vh;\n overflow-y: auto;\n }\n\n .modal-body p {\n margin: 0 0 8px;\n color: var(--mj-text-primary);\n }\n\n .warning-text {\n color: var(--mj-status-error) !important;\n font-size: 13px;\n }\n\n .modal-footer {\n display: flex;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n }\n\n .btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n }\n\n .btn-primary:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .btn-secondary {\n padding: 10px 20px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n }\n\n .btn-danger {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .btn-danger:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 85%, black);\n }\n\n /* Form Styles */\n .form-group {\n margin-bottom: 16px;\n }\n\n .form-group:last-child {\n margin-bottom: 0;\n }\n\n .form-group label {\n display: block;\n margin-bottom: 6px;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n }\n\n .form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 14px;\n transition: border-color 0.2s, box-shadow 0.2s;\n box-sizing: border-box;\n }\n\n .form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n .form-input:disabled {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n textarea.form-input {\n resize: vertical;\n min-height: 80px;\n }\n\n select.form-input {\n cursor: pointer;\n }\n\n .custom-select-wrapper {\n position: relative;\n }\n\n /* Portal Dropdown */\n .entity-dropdown-portal {\n position: fixed;\n z-index: 10002;\n }\n\n .entity-dropdown-content {\n max-height: 200px;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n box-shadow: var(--mj-shadow-md);\n }\n\n .entity-dropdown-content.open-above {\n position: absolute;\n bottom: 0;\n }\n\n .dropdown-item {\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 14px;\n color: var(--mj-text-primary);\n }\n\n .dropdown-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n }\n\n .dropdown-item:first-child {\n border-radius: 6px 6px 0 0;\n }\n\n .dropdown-item:last-child {\n border-radius: 0 0 6px 6px;\n }\n\n .dropdown-empty {\n padding: 10px 12px;\n color: var(--mj-text-muted);\n font-style: italic;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .header-row {\n flex-direction: column;\n gap: 12px;\n align-items: stretch;\n }\n\n .btn-create {\n width: 100%;\n justify-content: center;\n }\n\n .header-actions {\n flex-direction: column;\n align-items: stretch;\n }\n\n .search-box {\n max-width: none;\n }\n\n .filter-group {\n width: 100%;\n }\n\n .filter-select {\n flex: 1;\n width: 100%;\n }\n\n .view-toggle-group {\n justify-content: center;\n }\n\n .lists-table {\n overflow-x: auto;\n }\n\n .col-entity, .col-items, .col-updated {\n display: none;\n }\n\n .lists-grid {\n grid-template-columns: 1fr;\n }\n\n .modal-dialog {\n width: 95vw;\n }\n }\n "], encapsulation: 2 });
2204
2213
  };
2205
- ListsBrowseResource = __decorate([
2214
+ ListsBrowseResource = ListsBrowseResource_1 = __decorate([
2206
2215
  RegisterClass(BaseResourceComponent, 'ListsBrowseResource')
2207
2216
  ], ListsBrowseResource);
2208
2217
  export { ListsBrowseResource };