@memberjunction/ng-dashboard-viewer 6.2.0-edge.3 → 6.2.0-edge.4

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 (99) hide show
  1. package/README.md +165 -17
  2. package/dist/lib/config-dialogs/confirm-dialog.component.d.ts +3 -4
  3. package/dist/lib/config-dialogs/confirm-dialog.component.d.ts.map +1 -1
  4. package/dist/lib/config-dialogs/confirm-dialog.component.js +3 -2
  5. package/dist/lib/config-dialogs/confirm-dialog.component.js.map +1 -1
  6. package/dist/lib/config-panels/artifact-config-panel.component.d.ts.map +1 -1
  7. package/dist/lib/config-panels/artifact-config-panel.component.js +59 -50
  8. package/dist/lib/config-panels/artifact-config-panel.component.js.map +1 -1
  9. package/dist/lib/config-panels/base-config-panel.d.ts +8 -3
  10. package/dist/lib/config-panels/base-config-panel.d.ts.map +1 -1
  11. package/dist/lib/config-panels/base-config-panel.js +10 -3
  12. package/dist/lib/config-panels/base-config-panel.js.map +1 -1
  13. package/dist/lib/config-panels/query-config-panel.component.js +124 -99
  14. package/dist/lib/config-panels/query-config-panel.component.js.map +1 -1
  15. package/dist/lib/config-panels/view-config-panel.component.js +111 -103
  16. package/dist/lib/config-panels/view-config-panel.component.js.map +1 -1
  17. package/dist/lib/config-panels/weburl-config-panel.component.js +89 -80
  18. package/dist/lib/config-panels/weburl-config-panel.component.js.map +1 -1
  19. package/dist/lib/dashboard-browser/dashboard-browser.component.d.ts +79 -28
  20. package/dist/lib/dashboard-browser/dashboard-browser.component.d.ts.map +1 -1
  21. package/dist/lib/dashboard-browser/dashboard-browser.component.js +446 -447
  22. package/dist/lib/dashboard-browser/dashboard-browser.component.js.map +1 -1
  23. package/dist/lib/dashboard-card/dashboard-card.component.d.ts +69 -0
  24. package/dist/lib/dashboard-card/dashboard-card.component.d.ts.map +1 -0
  25. package/dist/lib/dashboard-card/dashboard-card.component.js +281 -0
  26. package/dist/lib/dashboard-card/dashboard-card.component.js.map +1 -0
  27. package/dist/lib/dashboard-card/dashboard-card.helpers.d.ts +18 -0
  28. package/dist/lib/dashboard-card/dashboard-card.helpers.d.ts.map +1 -0
  29. package/dist/lib/dashboard-card/dashboard-card.helpers.js +43 -0
  30. package/dist/lib/dashboard-card/dashboard-card.helpers.js.map +1 -0
  31. package/dist/lib/dashboard-card/layout-preview-cache.d.ts +15 -0
  32. package/dist/lib/dashboard-card/layout-preview-cache.d.ts.map +1 -0
  33. package/dist/lib/dashboard-card/layout-preview-cache.js +22 -0
  34. package/dist/lib/dashboard-card/layout-preview-cache.js.map +1 -0
  35. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts +69 -12
  36. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts.map +1 -1
  37. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js +173 -145
  38. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js.map +1 -1
  39. package/dist/lib/dashboard-viewer.module.d.ts +24 -20
  40. package/dist/lib/dashboard-viewer.module.d.ts.map +1 -1
  41. package/dist/lib/dashboard-viewer.module.js +42 -5
  42. package/dist/lib/dashboard-viewer.module.js.map +1 -1
  43. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.d.ts +7 -12
  44. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.d.ts.map +1 -1
  45. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.js +3 -1
  46. package/dist/lib/dialogs/add-panel-dialog/add-panel-dialog.component.js.map +1 -1
  47. package/dist/lib/dialogs/dashboard-name-dialog/dashboard-name-dialog.component.d.ts +54 -0
  48. package/dist/lib/dialogs/dashboard-name-dialog/dashboard-name-dialog.component.d.ts.map +1 -0
  49. package/dist/lib/dialogs/dashboard-name-dialog/dashboard-name-dialog.component.js +156 -0
  50. package/dist/lib/dialogs/dashboard-name-dialog/dashboard-name-dialog.component.js.map +1 -0
  51. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.d.ts +5 -11
  52. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.d.ts.map +1 -1
  53. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.js +3 -1
  54. package/dist/lib/dialogs/edit-part-dialog/edit-part-dialog.component.js.map +1 -1
  55. package/dist/lib/dialogs/part-dialog/dashboard-part-dialog.component.d.ts +147 -0
  56. package/dist/lib/dialogs/part-dialog/dashboard-part-dialog.component.d.ts.map +1 -0
  57. package/dist/lib/dialogs/part-dialog/dashboard-part-dialog.component.js +536 -0
  58. package/dist/lib/dialogs/part-dialog/dashboard-part-dialog.component.js.map +1 -0
  59. package/dist/lib/layout-preview/dashboard-layout-preview-node.component.d.ts +20 -0
  60. package/dist/lib/layout-preview/dashboard-layout-preview-node.component.d.ts.map +1 -0
  61. package/dist/lib/layout-preview/dashboard-layout-preview-node.component.js +80 -0
  62. package/dist/lib/layout-preview/dashboard-layout-preview-node.component.js.map +1 -0
  63. package/dist/lib/layout-preview/dashboard-layout-preview.component.d.ts +28 -0
  64. package/dist/lib/layout-preview/dashboard-layout-preview.component.d.ts.map +1 -0
  65. package/dist/lib/layout-preview/dashboard-layout-preview.component.js +62 -0
  66. package/dist/lib/layout-preview/dashboard-layout-preview.component.js.map +1 -0
  67. package/dist/lib/layout-preview/dashboard-layout-preview.d.ts +33 -0
  68. package/dist/lib/layout-preview/dashboard-layout-preview.d.ts.map +1 -0
  69. package/dist/lib/layout-preview/dashboard-layout-preview.js +138 -0
  70. package/dist/lib/layout-preview/dashboard-layout-preview.js.map +1 -0
  71. package/dist/lib/models/dashboard-layout-editor.d.ts +78 -0
  72. package/dist/lib/models/dashboard-layout-editor.d.ts.map +1 -0
  73. package/dist/lib/models/dashboard-layout-editor.js +374 -0
  74. package/dist/lib/models/dashboard-layout-editor.js.map +1 -0
  75. package/dist/lib/models/remove-part-confirm.d.ts +8 -0
  76. package/dist/lib/models/remove-part-confirm.d.ts.map +1 -0
  77. package/dist/lib/models/remove-part-confirm.js +23 -0
  78. package/dist/lib/models/remove-part-confirm.js.map +1 -0
  79. package/dist/lib/parts/artifact-part.component.js +2 -2
  80. package/dist/lib/parts/artifact-part.component.js.map +1 -1
  81. package/dist/lib/parts/query-part.component.js +2 -2
  82. package/dist/lib/parts/query-part.component.js.map +1 -1
  83. package/dist/lib/parts/view-part.component.js +2 -2
  84. package/dist/lib/parts/view-part.component.js.map +1 -1
  85. package/dist/lib/parts/weburl-part.component.js +2 -2
  86. package/dist/lib/parts/weburl-part.component.js.map +1 -1
  87. package/dist/lib/services/golden-layout-wrapper.service.d.ts +40 -0
  88. package/dist/lib/services/golden-layout-wrapper.service.d.ts.map +1 -1
  89. package/dist/lib/services/golden-layout-wrapper.service.js +117 -9
  90. package/dist/lib/services/golden-layout-wrapper.service.js.map +1 -1
  91. package/dist/lib/services/stack-part-actions.d.ts +11 -0
  92. package/dist/lib/services/stack-part-actions.d.ts.map +1 -0
  93. package/dist/lib/services/stack-part-actions.js +41 -0
  94. package/dist/lib/services/stack-part-actions.js.map +1 -0
  95. package/dist/public-api.d.ts +9 -0
  96. package/dist/public-api.d.ts.map +1 -1
  97. package/dist/public-api.js +13 -0
  98. package/dist/public-api.js.map +1 -1
  99. package/package.json +13 -13
@@ -0,0 +1,281 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { HighlightSearchMatches } from '@memberjunction/global';
3
+ import { FormatDashboardDate } from './dashboard-card.helpers';
4
+ import { LayoutPreviewCache } from './layout-preview-cache';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "../layout-preview/dashboard-layout-preview.component";
7
+ function DashboardCardComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
8
+ i0.ɵɵelementStart(0, "span", 2)(1, "span", 18);
9
+ i0.ɵɵelement(2, "i", 19);
10
+ i0.ɵɵelementEnd();
11
+ i0.ɵɵelementStart(3, "span", 20);
12
+ i0.ɵɵtext(4, "Not set up yet");
13
+ i0.ɵɵelementEnd()();
14
+ } }
15
+ function DashboardCardComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
16
+ i0.ɵɵelement(0, "img", 3);
17
+ } if (rf & 2) {
18
+ const ctx_r0 = i0.ɵɵnextContext();
19
+ i0.ɵɵproperty("src", ctx_r0.Dashboard.Thumbnail, i0.ɵɵsanitizeUrl);
20
+ } }
21
+ function DashboardCardComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
22
+ i0.ɵɵelement(0, "mj-dashboard-layout-preview", 4);
23
+ } if (rf & 2) {
24
+ i0.ɵɵproperty("Preview", ctx);
25
+ } }
26
+ function DashboardCardComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵelementStart(0, "span", 2)(1, "span", 18);
28
+ i0.ɵɵelement(2, "i", 19);
29
+ i0.ɵɵelementEnd()();
30
+ } }
31
+ function DashboardCardComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
32
+ const _r2 = i0.ɵɵgetCurrentView();
33
+ i0.ɵɵelementStart(0, "label", 21);
34
+ i0.ɵɵlistener("click", function DashboardCardComponent_Conditional_6_Template_label_click_0_listener($event) { return $event.stopPropagation(); })("dblclick", function DashboardCardComponent_Conditional_6_Template_label_dblclick_0_listener($event) { return $event.stopPropagation(); });
35
+ i0.ɵɵelementStart(1, "input", 22);
36
+ i0.ɵɵlistener("change", function DashboardCardComponent_Conditional_6_Template_input_change_1_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SelectionToggle.emit(ctx_r0.Dashboard)); });
37
+ i0.ɵɵelementEnd()();
38
+ } if (rf & 2) {
39
+ const ctx_r0 = i0.ɵɵnextContext();
40
+ i0.ɵɵadvance();
41
+ i0.ɵɵproperty("checked", ctx_r0.Selected);
42
+ i0.ɵɵattribute("aria-label", "Select " + ctx_r0.Dashboard.Name);
43
+ } }
44
+ function DashboardCardComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
45
+ const _r3 = i0.ɵɵgetCurrentView();
46
+ i0.ɵɵelementStart(0, "button", 23);
47
+ i0.ɵɵlistener("click", function DashboardCardComponent_Conditional_8_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnAction($event, ctx_r0.Edit)); });
48
+ i0.ɵɵelement(1, "i", 24);
49
+ i0.ɵɵelementEnd();
50
+ } if (rf & 2) {
51
+ const ctx_r0 = i0.ɵɵnextContext();
52
+ i0.ɵɵattribute("aria-label", "Edit " + ctx_r0.Dashboard.Name);
53
+ } }
54
+ function DashboardCardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
55
+ const _r4 = i0.ɵɵgetCurrentView();
56
+ i0.ɵɵelementStart(0, "button", 25);
57
+ i0.ɵɵlistener("click", function DashboardCardComponent_Conditional_9_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnAction($event, ctx_r0.Delete)); });
58
+ i0.ɵɵelement(1, "i", 26);
59
+ i0.ɵɵelementEnd();
60
+ } if (rf & 2) {
61
+ const ctx_r0 = i0.ɵɵnextContext();
62
+ i0.ɵɵattribute("aria-label", "Delete " + ctx_r0.Dashboard.Name);
63
+ } }
64
+ function DashboardCardComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
65
+ const _r5 = i0.ɵɵgetCurrentView();
66
+ i0.ɵɵelementStart(0, "button", 27);
67
+ i0.ɵɵlistener("click", function DashboardCardComponent_Conditional_10_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnAction($event, ctx_r0.ToggleFavorite)); });
68
+ i0.ɵɵelement(1, "i", 28);
69
+ i0.ɵɵelementEnd();
70
+ } if (rf & 2) {
71
+ const ctx_r0 = i0.ɵɵnextContext();
72
+ i0.ɵɵclassProp("on", ctx_r0.IsFavorite);
73
+ i0.ɵɵattribute("aria-pressed", ctx_r0.IsFavorite ? "true" : "false")("aria-label", "Favorite " + ctx_r0.Dashboard.Name);
74
+ i0.ɵɵadvance();
75
+ i0.ɵɵclassMap(ctx_r0.IsFavorite ? "fa-solid fa-star" : "fa-regular fa-star");
76
+ } }
77
+ function DashboardCardComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
78
+ i0.ɵɵelement(0, "p", 12);
79
+ } if (rf & 2) {
80
+ const ctx_r0 = i0.ɵɵnextContext();
81
+ i0.ɵɵproperty("innerHTML", ctx_r0.DescriptionHtml, i0.ɵɵsanitizeHtml);
82
+ } }
83
+ function DashboardCardComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
84
+ i0.ɵɵelementStart(0, "span", 14);
85
+ i0.ɵɵelement(1, "i", 29);
86
+ i0.ɵɵtext(2);
87
+ i0.ɵɵelementEnd();
88
+ } if (rf & 2) {
89
+ const ctx_r0 = i0.ɵɵnextContext();
90
+ i0.ɵɵadvance(2);
91
+ i0.ɵɵtextInterpolate(ctx_r0.OwnerLabel);
92
+ } }
93
+ function DashboardCardComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
94
+ i0.ɵɵelementStart(0, "span", 15);
95
+ i0.ɵɵelement(1, "i", 30);
96
+ i0.ɵɵtext(2, "Shared");
97
+ i0.ɵɵelementEnd();
98
+ } }
99
+ function DashboardCardComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
100
+ i0.ɵɵelementStart(0, "span", 16);
101
+ i0.ɵɵtext(1);
102
+ i0.ɵɵelementEnd();
103
+ } if (rf & 2) {
104
+ const ctx_r0 = i0.ɵɵnextContext();
105
+ i0.ɵɵadvance();
106
+ i0.ɵɵtextInterpolate(ctx_r0.CategoryPath);
107
+ } }
108
+ function DashboardCardComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
109
+ i0.ɵɵelementStart(0, "span", 17);
110
+ i0.ɵɵelement(1, "i", 31);
111
+ i0.ɵɵtext(2);
112
+ i0.ɵɵelementEnd();
113
+ } if (rf & 2) {
114
+ const ctx_r0 = i0.ɵɵnextContext();
115
+ i0.ɵɵadvance(2);
116
+ i0.ɵɵtextInterpolate(ctx_r0.UpdatedLabel);
117
+ } }
118
+ /**
119
+ * A dashboard card: a picture, the name, the description, and a meta row with the owner, a Shared
120
+ * marker, the category and the last update. The picture is the screenshot (Thumbnail), else a
121
+ * miniature of the saved panel layout, else an icon. A Config dashboard with no parts shows the icon
122
+ * and "Not set up yet". Presentational: the host decides what each event does.
123
+ */
124
+ export class DashboardCardComponent {
125
+ Dashboard;
126
+ /** True when the dashboard is one of the user's favorites: the star is filled. */
127
+ IsFavorite = false;
128
+ /** Whether the card shows the favorite star. */
129
+ ShowFavorite = true;
130
+ /** True when another user owns the dashboard and shared it with this user. */
131
+ IsShared = false;
132
+ /** Who owns the dashboard, for example "You" or "Ana Ruiz". Null shows no owner. */
133
+ OwnerLabel = null;
134
+ /** The category path, for example "Sales › Pipeline". Null shows no category. */
135
+ CategoryPath = null;
136
+ /** Search text to mark in the name and description. */
137
+ HighlightQuery = '';
138
+ /** True in selection mode: the card shows a checkbox. */
139
+ Selectable = false;
140
+ /** True when the card is selected. */
141
+ Selected = false;
142
+ /** Whether the card offers Edit. */
143
+ CanEdit = false;
144
+ /** Whether the card offers Delete. */
145
+ CanDelete = false;
146
+ /** A click on the card outside its buttons. */
147
+ CardClick = new EventEmitter();
148
+ /** A double-click on the card outside its buttons. */
149
+ CardDoubleClick = new EventEmitter();
150
+ /** A click on the star. */
151
+ ToggleFavorite = new EventEmitter();
152
+ /** A change of the selection checkbox. */
153
+ SelectionToggle = new EventEmitter();
154
+ /** A click on Edit. */
155
+ Edit = new EventEmitter();
156
+ /** A click on Delete. */
157
+ Delete = new EventEmitter();
158
+ layoutPreview = new LayoutPreviewCache();
159
+ /** The miniature of the saved panel layout: a Config dashboard's saved panels, else null. */
160
+ get LayoutPreview() {
161
+ return this.layoutPreview.PreviewFor(this.Dashboard);
162
+ }
163
+ /** True for a Config dashboard with no parts. Uses the cached preview, so the JSON is parsed once. */
164
+ get IsNotSetUp() {
165
+ return this.Dashboard.Type === 'Config' && this.LayoutPreview === null;
166
+ }
167
+ /** The name, with the search text marked. */
168
+ get NameHtml() {
169
+ return HighlightSearchMatches(this.Dashboard.Name ?? '', this.HighlightQuery);
170
+ }
171
+ /** The description, with the search text marked. */
172
+ get DescriptionHtml() {
173
+ return HighlightSearchMatches(this.Dashboard.Description ?? '', this.HighlightQuery);
174
+ }
175
+ /** When the dashboard was last updated, for example "Yesterday". Empty without a date. */
176
+ get UpdatedLabel() {
177
+ return FormatDashboardDate(this.Dashboard.__mj_UpdatedAt);
178
+ }
179
+ OnCardClick(event) {
180
+ this.CardClick.emit({ Dashboard: this.Dashboard, MouseEvent: event });
181
+ }
182
+ OnCardDoubleClick(event) {
183
+ this.CardDoubleClick.emit({ Dashboard: this.Dashboard, MouseEvent: event });
184
+ }
185
+ /** Runs a card button's action without the click also counting as a click on the card. */
186
+ OnAction(event, action) {
187
+ event.stopPropagation();
188
+ action.emit(this.Dashboard);
189
+ }
190
+ static ɵfac = function DashboardCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DashboardCardComponent)(); };
191
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DashboardCardComponent, selectors: [["mj-dashboard-card"]], inputs: { Dashboard: "Dashboard", IsFavorite: "IsFavorite", ShowFavorite: "ShowFavorite", IsShared: "IsShared", OwnerLabel: "OwnerLabel", CategoryPath: "CategoryPath", HighlightQuery: "HighlightQuery", Selectable: "Selectable", Selected: "Selected", CanEdit: "CanEdit", CanDelete: "CanDelete" }, outputs: { CardClick: "CardClick", CardDoubleClick: "CardDoubleClick", ToggleFavorite: "ToggleFavorite", SelectionToggle: "SelectionToggle", Edit: "Edit", Delete: "Delete" }, standalone: false, decls: 19, vars: 14, consts: [[1, "dc-card", 3, "click", "dblclick"], ["aria-hidden", "true", 1, "dc-thumb"], [1, "dc-placeholder"], ["alt", "", "draggable", "false", 3, "src"], [3, "Preview"], [1, "dc-select"], [1, "dc-tools", 3, "dblclick"], ["type", "button", "title", "Edit", 1, "dc-tool", "dc-edit"], ["type", "button", "title", "Delete", 1, "dc-tool", "dc-delete"], ["type", "button", 1, "dc-tool", "dc-star", 3, "on"], [1, "dc-body"], ["type", "button", 1, "dc-name", 3, "innerHTML"], [1, "dc-desc", 3, "innerHTML"], [1, "dc-meta"], [1, "dc-owner"], ["title", "Shared with you", 1, "dc-shared"], [1, "dc-category"], ["title", "Last updated", 1, "dc-updated"], [1, "dc-icon-tile"], [1, "fa-solid", "fa-gauge-high"], [1, "dc-not-set-up"], [1, "dc-select", 3, "click", "dblclick"], ["type", "checkbox", 1, "mj-checkbox", 3, "change", "checked"], ["type", "button", "title", "Edit", 1, "dc-tool", "dc-edit", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-pen"], ["type", "button", "title", "Delete", 1, "dc-tool", "dc-delete", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash-can"], ["type", "button", 1, "dc-tool", "dc-star", 3, "click"], ["aria-hidden", "true"], ["aria-hidden", "true", 1, "fa-regular", "fa-user"], ["aria-hidden", "true", 1, "fa-solid", "fa-share-nodes"], ["aria-hidden", "true", 1, "fa-regular", "fa-clock"]], template: function DashboardCardComponent_Template(rf, ctx) { if (rf & 1) {
192
+ i0.ɵɵelementStart(0, "article", 0);
193
+ i0.ɵɵlistener("click", function DashboardCardComponent_Template_article_click_0_listener($event) { return ctx.OnCardClick($event); })("dblclick", function DashboardCardComponent_Template_article_dblclick_0_listener($event) { return ctx.OnCardDoubleClick($event); });
194
+ i0.ɵɵelementStart(1, "div", 1);
195
+ i0.ɵɵconditionalCreate(2, DashboardCardComponent_Conditional_2_Template, 5, 0, "span", 2)(3, DashboardCardComponent_Conditional_3_Template, 1, 1, "img", 3)(4, DashboardCardComponent_Conditional_4_Template, 1, 1, "mj-dashboard-layout-preview", 4)(5, DashboardCardComponent_Conditional_5_Template, 3, 0, "span", 2);
196
+ i0.ɵɵelementEnd();
197
+ i0.ɵɵconditionalCreate(6, DashboardCardComponent_Conditional_6_Template, 2, 2, "label", 5);
198
+ i0.ɵɵelementStart(7, "div", 6);
199
+ i0.ɵɵlistener("dblclick", function DashboardCardComponent_Template_div_dblclick_7_listener($event) { return $event.stopPropagation(); });
200
+ i0.ɵɵconditionalCreate(8, DashboardCardComponent_Conditional_8_Template, 2, 1, "button", 7);
201
+ i0.ɵɵconditionalCreate(9, DashboardCardComponent_Conditional_9_Template, 2, 1, "button", 8);
202
+ i0.ɵɵconditionalCreate(10, DashboardCardComponent_Conditional_10_Template, 2, 6, "button", 9);
203
+ i0.ɵɵelementEnd();
204
+ i0.ɵɵelementStart(11, "div", 10);
205
+ i0.ɵɵelement(12, "button", 11);
206
+ i0.ɵɵconditionalCreate(13, DashboardCardComponent_Conditional_13_Template, 1, 1, "p", 12);
207
+ i0.ɵɵelementStart(14, "div", 13);
208
+ i0.ɵɵconditionalCreate(15, DashboardCardComponent_Conditional_15_Template, 3, 1, "span", 14);
209
+ i0.ɵɵconditionalCreate(16, DashboardCardComponent_Conditional_16_Template, 3, 0, "span", 15);
210
+ i0.ɵɵconditionalCreate(17, DashboardCardComponent_Conditional_17_Template, 2, 1, "span", 16);
211
+ i0.ɵɵconditionalCreate(18, DashboardCardComponent_Conditional_18_Template, 3, 1, "span", 17);
212
+ i0.ɵɵelementEnd()()();
213
+ } if (rf & 2) {
214
+ let tmp_1_0;
215
+ i0.ɵɵclassProp("selected", ctx.Selected);
216
+ i0.ɵɵadvance(2);
217
+ i0.ɵɵconditional(ctx.IsNotSetUp ? 2 : ctx.Dashboard.Thumbnail ? 3 : (tmp_1_0 = ctx.LayoutPreview) ? 4 : 5, tmp_1_0);
218
+ i0.ɵɵadvance(4);
219
+ i0.ɵɵconditional(ctx.Selectable ? 6 : -1);
220
+ i0.ɵɵadvance(2);
221
+ i0.ɵɵconditional(ctx.CanEdit ? 8 : -1);
222
+ i0.ɵɵadvance();
223
+ i0.ɵɵconditional(ctx.CanDelete ? 9 : -1);
224
+ i0.ɵɵadvance();
225
+ i0.ɵɵconditional(ctx.ShowFavorite ? 10 : -1);
226
+ i0.ɵɵadvance(2);
227
+ i0.ɵɵproperty("innerHTML", ctx.NameHtml, i0.ɵɵsanitizeHtml);
228
+ i0.ɵɵattribute("aria-label", "Open " + ctx.Dashboard.Name);
229
+ i0.ɵɵadvance();
230
+ i0.ɵɵconditional(ctx.Dashboard.Description ? 13 : -1);
231
+ i0.ɵɵadvance(2);
232
+ i0.ɵɵconditional(ctx.OwnerLabel ? 15 : -1);
233
+ i0.ɵɵadvance();
234
+ i0.ɵɵconditional(ctx.IsShared ? 16 : -1);
235
+ i0.ɵɵadvance();
236
+ i0.ɵɵconditional(ctx.CategoryPath ? 17 : -1);
237
+ i0.ɵɵadvance();
238
+ i0.ɵɵconditional(ctx.UpdatedLabel ? 18 : -1);
239
+ } }, dependencies: [i1.DashboardLayoutPreviewComponent], styles: ["\n\n[_nghost-%COMP%] {\n display: block;\n min-width: 0;\n}\n\n.dc-card[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n cursor: pointer;\n transition:\n border-color var(--mj-transition-fast),\n box-shadow var(--mj-transition-fast),\n transform var(--mj-transition-fast);\n}\n\n.dc-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.dc-card[_ngcontent-%COMP%]:focus-within {\n border-color: var(--mj-border-focus);\n}\n\n.dc-card.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n\n.dc-thumb[_ngcontent-%COMP%] {\n position: relative;\n aspect-ratio: 16 / 9;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n overflow: hidden;\n}\n\n.dc-thumb[_ngcontent-%COMP%] img[_ngcontent-%COMP%], \n.dc-thumb[_ngcontent-%COMP%] mj-dashboard-layout-preview[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n}\n\n.dc-thumb[_ngcontent-%COMP%] img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.dc-placeholder[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--mj-space-2);\n}\n\n.dc-icon-tile[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 22px;\n}\n\n.dc-not-set-up[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n\n.dc-select[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n left: 8px;\n z-index: 1;\n display: flex;\n padding: 6px;\n border-radius: var(--mj-radius-md);\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n border: 1px solid var(--mj-border-default);\n}\n\n\n.dc-tools[_ngcontent-%COMP%] {\n position: absolute;\n top: 6px;\n right: 6px;\n z-index: 1;\n display: flex;\n gap: 4px;\n}\n\n.dc-tool[_ngcontent-%COMP%] {\n width: 26px;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.dc-tool[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.dc-tool[_ngcontent-%COMP%]:focus-visible {\n outline: var(--mj-ring-width) solid var(--mj-focus-ring-color);\n outline-offset: var(--mj-ring-offset);\n}\n\n\n.dc-edit[_ngcontent-%COMP%], \n.dc-delete[_ngcontent-%COMP%] {\n opacity: 0;\n transition: opacity var(--mj-transition-fast);\n}\n\n.dc-card[_ngcontent-%COMP%]:hover .dc-edit[_ngcontent-%COMP%], \n.dc-card[_ngcontent-%COMP%]:hover .dc-delete[_ngcontent-%COMP%], \n.dc-card[_ngcontent-%COMP%]:focus-within .dc-edit[_ngcontent-%COMP%], \n.dc-card[_ngcontent-%COMP%]:focus-within .dc-delete[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n@media (hover: none) {\n .dc-edit[_ngcontent-%COMP%], \n .dc-delete[_ngcontent-%COMP%] {\n opacity: 1;\n }\n}\n\n.dc-delete[_ngcontent-%COMP%]:hover {\n color: var(--mj-status-error);\n}\n\n.dc-star.on[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n\n.dc-body[_ngcontent-%COMP%] {\n padding: 10px 12px 12px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.dc-name[_ngcontent-%COMP%] {\n border: none;\n background: none;\n padding: 0;\n text-align: left;\n font: inherit;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dc-name[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n}\n\n.dc-name[_ngcontent-%COMP%]:focus-visible {\n outline: var(--mj-ring-width) solid var(--mj-focus-ring-color);\n outline-offset: var(--mj-ring-offset);\n border-radius: var(--mj-radius-sm);\n}\n\n.dc-desc[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.45;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.dc-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 10px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.dc-owner[_ngcontent-%COMP%], \n.dc-shared[_ngcontent-%COMP%], \n.dc-updated[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.dc-shared[_ngcontent-%COMP%] {\n padding: 1px 8px;\n border-radius: var(--mj-radius-full);\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.dc-category[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n}\n\n\n[_nghost-%COMP%] mark {\n background: color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n color: inherit;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dc-card[_ngcontent-%COMP%] {\n transition: none;\n }\n\n .dc-card[_ngcontent-%COMP%]:hover {\n transform: none;\n }\n}"] });
240
+ }
241
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DashboardCardComponent, [{
242
+ type: Component,
243
+ args: [{ standalone: false, selector: 'mj-dashboard-card', template: "<article class=\"dc-card\" [class.selected]=\"Selected\" (click)=\"OnCardClick($event)\" (dblclick)=\"OnCardDoubleClick($event)\">\n <div class=\"dc-thumb\" aria-hidden=\"true\">\n @if (IsNotSetUp) {\n <span class=\"dc-placeholder\">\n <span class=\"dc-icon-tile\"><i class=\"fa-solid fa-gauge-high\"></i></span>\n <span class=\"dc-not-set-up\">Not set up yet</span>\n </span>\n } @else if (Dashboard.Thumbnail) {\n <img [src]=\"Dashboard.Thumbnail\" alt=\"\" draggable=\"false\" />\n } @else if (LayoutPreview; as preview) {\n <mj-dashboard-layout-preview [Preview]=\"preview\"></mj-dashboard-layout-preview>\n } @else {\n <span class=\"dc-placeholder\"><span class=\"dc-icon-tile\"><i class=\"fa-solid fa-gauge-high\"></i></span></span>\n }\n </div>\n @if (Selectable) {\n <label class=\"dc-select\" (click)=\"$event.stopPropagation()\" (dblclick)=\"$event.stopPropagation()\">\n <input type=\"checkbox\" class=\"mj-checkbox\" [checked]=\"Selected\" [attr.aria-label]=\"'Select ' + Dashboard.Name\"\n (change)=\"SelectionToggle.emit(Dashboard)\" />\n </label>\n }\n <div class=\"dc-tools\" (dblclick)=\"$event.stopPropagation()\">\n @if (CanEdit) {\n <button type=\"button\" class=\"dc-tool dc-edit\" title=\"Edit\" [attr.aria-label]=\"'Edit ' + Dashboard.Name\" (click)=\"OnAction($event, Edit)\">\n <i class=\"fa-solid fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (CanDelete) {\n <button type=\"button\" class=\"dc-tool dc-delete\" title=\"Delete\" [attr.aria-label]=\"'Delete ' + Dashboard.Name\" (click)=\"OnAction($event, Delete)\">\n <i class=\"fa-solid fa-trash-can\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowFavorite) {\n <button type=\"button\" class=\"dc-tool dc-star\" [class.on]=\"IsFavorite\" [attr.aria-pressed]=\"IsFavorite ? 'true' : 'false'\"\n [attr.aria-label]=\"'Favorite ' + Dashboard.Name\" (click)=\"OnAction($event, ToggleFavorite)\">\n <i [class]=\"IsFavorite ? 'fa-solid fa-star' : 'fa-regular fa-star'\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dc-body\">\n <button type=\"button\" class=\"dc-name\" [attr.aria-label]=\"'Open ' + Dashboard.Name\" [innerHTML]=\"NameHtml\"></button>\n @if (Dashboard.Description) {\n <p class=\"dc-desc\" [innerHTML]=\"DescriptionHtml\"></p>\n }\n <div class=\"dc-meta\">\n @if (OwnerLabel) {\n <span class=\"dc-owner\"><i class=\"fa-regular fa-user\" aria-hidden=\"true\"></i>{{ OwnerLabel }}</span>\n }\n @if (IsShared) {\n <span class=\"dc-shared\" title=\"Shared with you\"><i class=\"fa-solid fa-share-nodes\" aria-hidden=\"true\"></i>Shared</span>\n }\n @if (CategoryPath) {\n <span class=\"dc-category\">{{ CategoryPath }}</span>\n }\n @if (UpdatedLabel) {\n <span class=\"dc-updated\" title=\"Last updated\"><i class=\"fa-regular fa-clock\" aria-hidden=\"true\"></i>{{ UpdatedLabel }}</span>\n }\n </div>\n </div>\n</article>\n", styles: ["/* Dashboard card: picture, name, description, meta row */\n\n:host {\n display: block;\n min-width: 0;\n}\n\n.dc-card {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-sm);\n overflow: hidden;\n cursor: pointer;\n transition:\n border-color var(--mj-transition-fast),\n box-shadow var(--mj-transition-fast),\n transform var(--mj-transition-fast);\n}\n\n.dc-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: var(--mj-shadow-md);\n transform: translateY(-2px);\n}\n\n.dc-card:focus-within {\n border-color: var(--mj-border-focus);\n}\n\n.dc-card.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n/* Picture: the screenshot, the layout miniature or the placeholder fills the 16:9 area */\n.dc-thumb {\n position: relative;\n aspect-ratio: 16 / 9;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n overflow: hidden;\n}\n\n.dc-thumb img,\n.dc-thumb mj-dashboard-layout-preview {\n position: absolute;\n inset: 0;\n}\n\n.dc-thumb img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.dc-placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--mj-space-2);\n}\n\n.dc-icon-tile {\n width: 52px;\n height: 52px;\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 22px;\n}\n\n.dc-not-set-up {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n/* Selection checkbox, top left */\n.dc-select {\n position: absolute;\n top: 8px;\n left: 8px;\n z-index: 1;\n display: flex;\n padding: 6px;\n border-radius: var(--mj-radius-md);\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n border: 1px solid var(--mj-border-default);\n}\n\n/* Edit, Delete and the star, top right */\n.dc-tools {\n position: absolute;\n top: 6px;\n right: 6px;\n z-index: 1;\n display: flex;\n gap: 4px;\n}\n\n.dc-tool {\n width: 26px;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.dc-tool:hover {\n color: var(--mj-text-primary);\n}\n\n.dc-tool:focus-visible {\n outline: var(--mj-ring-width) solid var(--mj-focus-ring-color);\n outline-offset: var(--mj-ring-offset);\n}\n\n/* Edit and Delete show on hover or focus; on touch screens they always show */\n.dc-edit,\n.dc-delete {\n opacity: 0;\n transition: opacity var(--mj-transition-fast);\n}\n\n.dc-card:hover .dc-edit,\n.dc-card:hover .dc-delete,\n.dc-card:focus-within .dc-edit,\n.dc-card:focus-within .dc-delete {\n opacity: 1;\n}\n\n@media (hover: none) {\n .dc-edit,\n .dc-delete {\n opacity: 1;\n }\n}\n\n.dc-delete:hover {\n color: var(--mj-status-error);\n}\n\n.dc-star.on {\n color: var(--mj-status-warning);\n}\n\n/* Name, description, meta row */\n.dc-body {\n padding: 10px 12px 12px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.dc-name {\n border: none;\n background: none;\n padding: 0;\n text-align: left;\n font: inherit;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.dc-name:hover {\n color: var(--mj-brand-primary);\n}\n\n.dc-name:focus-visible {\n outline: var(--mj-ring-width) solid var(--mj-focus-ring-color);\n outline-offset: var(--mj-ring-offset);\n border-radius: var(--mj-radius-sm);\n}\n\n.dc-desc {\n margin: 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.45;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.dc-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 10px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.dc-owner,\n.dc-shared,\n.dc-updated {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.dc-shared {\n padding: 1px 8px;\n border-radius: var(--mj-radius-full);\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.dc-category {\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n}\n\n/* Search marks come from innerHTML and get no _ngcontent attribute, so they are reached through ::ng-deep under the host */\n:host ::ng-deep mark {\n background: color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n color: inherit;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dc-card {\n transition: none;\n }\n\n .dc-card:hover {\n transform: none;\n }\n}\n"] }]
244
+ }], null, { Dashboard: [{
245
+ type: Input,
246
+ args: [{ required: true }]
247
+ }], IsFavorite: [{
248
+ type: Input
249
+ }], ShowFavorite: [{
250
+ type: Input
251
+ }], IsShared: [{
252
+ type: Input
253
+ }], OwnerLabel: [{
254
+ type: Input
255
+ }], CategoryPath: [{
256
+ type: Input
257
+ }], HighlightQuery: [{
258
+ type: Input
259
+ }], Selectable: [{
260
+ type: Input
261
+ }], Selected: [{
262
+ type: Input
263
+ }], CanEdit: [{
264
+ type: Input
265
+ }], CanDelete: [{
266
+ type: Input
267
+ }], CardClick: [{
268
+ type: Output
269
+ }], CardDoubleClick: [{
270
+ type: Output
271
+ }], ToggleFavorite: [{
272
+ type: Output
273
+ }], SelectionToggle: [{
274
+ type: Output
275
+ }], Edit: [{
276
+ type: Output
277
+ }], Delete: [{
278
+ type: Output
279
+ }] }); })();
280
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DashboardCardComponent, { className: "DashboardCardComponent", filePath: "src/lib/dashboard-card/dashboard-card.component.ts", lineNumber: 27 }); })();
281
+ //# sourceMappingURL=dashboard-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-card.component.js","sourceRoot":"","sources":["../../../src/lib/dashboard-card/dashboard-card.component.ts","../../../src/lib/dashboard-card/dashboard-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport type { MJDashboardEntity } from '@memberjunction/core-entities';\nimport { HighlightSearchMatches } from '@memberjunction/global';\nimport type { DashboardLayoutPreviewNode } from '../layout-preview/dashboard-layout-preview';\nimport { FormatDashboardDate } from './dashboard-card.helpers';\nimport { LayoutPreviewCache } from './layout-preview-cache';\n\n/** A click on a dashboard card outside its buttons. */\nexport interface DashboardCardClickEvent {\n Dashboard: MJDashboardEntity;\n /** The click; the host reads its Shift, Ctrl and Cmd keys. */\n MouseEvent: MouseEvent;\n}\n\n/**\n * A dashboard card: a picture, the name, the description, and a meta row with the owner, a Shared\n * marker, the category and the last update. The picture is the screenshot (Thumbnail), else a\n * miniature of the saved panel layout, else an icon. A Config dashboard with no parts shows the icon\n * and \"Not set up yet\". Presentational: the host decides what each event does.\n */\n@Component({\n standalone: false,\n selector: 'mj-dashboard-card',\n templateUrl: './dashboard-card.component.html',\n styleUrls: ['./dashboard-card.component.css'],\n})\nexport class DashboardCardComponent {\n @Input({ required: true }) Dashboard!: MJDashboardEntity;\n /** True when the dashboard is one of the user's favorites: the star is filled. */\n @Input() IsFavorite = false;\n /** Whether the card shows the favorite star. */\n @Input() ShowFavorite = true;\n /** True when another user owns the dashboard and shared it with this user. */\n @Input() IsShared = false;\n /** Who owns the dashboard, for example \"You\" or \"Ana Ruiz\". Null shows no owner. */\n @Input() OwnerLabel: string | null = null;\n /** The category path, for example \"Sales › Pipeline\". Null shows no category. */\n @Input() CategoryPath: string | null = null;\n /** Search text to mark in the name and description. */\n @Input() HighlightQuery = '';\n /** True in selection mode: the card shows a checkbox. */\n @Input() Selectable = false;\n /** True when the card is selected. */\n @Input() Selected = false;\n /** Whether the card offers Edit. */\n @Input() CanEdit = false;\n /** Whether the card offers Delete. */\n @Input() CanDelete = false;\n\n /** A click on the card outside its buttons. */\n @Output() CardClick = new EventEmitter<DashboardCardClickEvent>();\n /** A double-click on the card outside its buttons. */\n @Output() CardDoubleClick = new EventEmitter<DashboardCardClickEvent>();\n /** A click on the star. */\n @Output() ToggleFavorite = new EventEmitter<MJDashboardEntity>();\n /** A change of the selection checkbox. */\n @Output() SelectionToggle = new EventEmitter<MJDashboardEntity>();\n /** A click on Edit. */\n @Output() Edit = new EventEmitter<MJDashboardEntity>();\n /** A click on Delete. */\n @Output() Delete = new EventEmitter<MJDashboardEntity>();\n\n private layoutPreview = new LayoutPreviewCache();\n\n /** The miniature of the saved panel layout: a Config dashboard's saved panels, else null. */\n public get LayoutPreview(): DashboardLayoutPreviewNode | null {\n return this.layoutPreview.PreviewFor(this.Dashboard);\n }\n\n /** True for a Config dashboard with no parts. Uses the cached preview, so the JSON is parsed once. */\n public get IsNotSetUp(): boolean {\n return this.Dashboard.Type === 'Config' && this.LayoutPreview === null;\n }\n\n /** The name, with the search text marked. */\n public get NameHtml(): string {\n return HighlightSearchMatches(this.Dashboard.Name ?? '', this.HighlightQuery);\n }\n\n /** The description, with the search text marked. */\n public get DescriptionHtml(): string {\n return HighlightSearchMatches(this.Dashboard.Description ?? '', this.HighlightQuery);\n }\n\n /** When the dashboard was last updated, for example \"Yesterday\". Empty without a date. */\n public get UpdatedLabel(): string {\n return FormatDashboardDate(this.Dashboard.__mj_UpdatedAt);\n }\n\n public OnCardClick(event: MouseEvent): void {\n this.CardClick.emit({ Dashboard: this.Dashboard, MouseEvent: event });\n }\n\n public OnCardDoubleClick(event: MouseEvent): void {\n this.CardDoubleClick.emit({ Dashboard: this.Dashboard, MouseEvent: event });\n }\n\n /** Runs a card button's action without the click also counting as a click on the card. */\n public OnAction(event: Event, action: EventEmitter<MJDashboardEntity>): void {\n event.stopPropagation();\n action.emit(this.Dashboard);\n }\n}\n","<article class=\"dc-card\" [class.selected]=\"Selected\" (click)=\"OnCardClick($event)\" (dblclick)=\"OnCardDoubleClick($event)\">\n <div class=\"dc-thumb\" aria-hidden=\"true\">\n @if (IsNotSetUp) {\n <span class=\"dc-placeholder\">\n <span class=\"dc-icon-tile\"><i class=\"fa-solid fa-gauge-high\"></i></span>\n <span class=\"dc-not-set-up\">Not set up yet</span>\n </span>\n } @else if (Dashboard.Thumbnail) {\n <img [src]=\"Dashboard.Thumbnail\" alt=\"\" draggable=\"false\" />\n } @else if (LayoutPreview; as preview) {\n <mj-dashboard-layout-preview [Preview]=\"preview\"></mj-dashboard-layout-preview>\n } @else {\n <span class=\"dc-placeholder\"><span class=\"dc-icon-tile\"><i class=\"fa-solid fa-gauge-high\"></i></span></span>\n }\n </div>\n @if (Selectable) {\n <label class=\"dc-select\" (click)=\"$event.stopPropagation()\" (dblclick)=\"$event.stopPropagation()\">\n <input type=\"checkbox\" class=\"mj-checkbox\" [checked]=\"Selected\" [attr.aria-label]=\"'Select ' + Dashboard.Name\"\n (change)=\"SelectionToggle.emit(Dashboard)\" />\n </label>\n }\n <div class=\"dc-tools\" (dblclick)=\"$event.stopPropagation()\">\n @if (CanEdit) {\n <button type=\"button\" class=\"dc-tool dc-edit\" title=\"Edit\" [attr.aria-label]=\"'Edit ' + Dashboard.Name\" (click)=\"OnAction($event, Edit)\">\n <i class=\"fa-solid fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (CanDelete) {\n <button type=\"button\" class=\"dc-tool dc-delete\" title=\"Delete\" [attr.aria-label]=\"'Delete ' + Dashboard.Name\" (click)=\"OnAction($event, Delete)\">\n <i class=\"fa-solid fa-trash-can\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (ShowFavorite) {\n <button type=\"button\" class=\"dc-tool dc-star\" [class.on]=\"IsFavorite\" [attr.aria-pressed]=\"IsFavorite ? 'true' : 'false'\"\n [attr.aria-label]=\"'Favorite ' + Dashboard.Name\" (click)=\"OnAction($event, ToggleFavorite)\">\n <i [class]=\"IsFavorite ? 'fa-solid fa-star' : 'fa-regular fa-star'\" aria-hidden=\"true\"></i>\n </button>\n }\n </div>\n <div class=\"dc-body\">\n <button type=\"button\" class=\"dc-name\" [attr.aria-label]=\"'Open ' + Dashboard.Name\" [innerHTML]=\"NameHtml\"></button>\n @if (Dashboard.Description) {\n <p class=\"dc-desc\" [innerHTML]=\"DescriptionHtml\"></p>\n }\n <div class=\"dc-meta\">\n @if (OwnerLabel) {\n <span class=\"dc-owner\"><i class=\"fa-regular fa-user\" aria-hidden=\"true\"></i>{{ OwnerLabel }}</span>\n }\n @if (IsShared) {\n <span class=\"dc-shared\" title=\"Shared with you\"><i class=\"fa-solid fa-share-nodes\" aria-hidden=\"true\"></i>Shared</span>\n }\n @if (CategoryPath) {\n <span class=\"dc-category\">{{ CategoryPath }}</span>\n }\n @if (UpdatedLabel) {\n <span class=\"dc-updated\" title=\"Last updated\"><i class=\"fa-regular fa-clock\" aria-hidden=\"true\"></i>{{ UpdatedLabel }}</span>\n }\n </div>\n </div>\n</article>\n"]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @fileoverview Pure helpers for dashboard cards and the dashboard browser: whether a dashboard has
3
+ * no parts yet, how a last update reads, and a category's path.
4
+ */
5
+ import type { MJDashboardCategoryEntity, MJDashboardEntity } from '@memberjunction/core-entities';
6
+ /** True for a Config dashboard whose saved configuration has no panel layout: it has no parts yet. */
7
+ export declare function IsDashboardNotSetUp(dashboard: Pick<MJDashboardEntity, 'Type' | 'UIConfigDetails'>): boolean;
8
+ /**
9
+ * "Today", "Yesterday", "N days ago" (under a week), else the local date. A date later than `now`
10
+ * reads "Today". Empty for no date.
11
+ */
12
+ export declare function FormatDashboardDate(date: Date | null | undefined, now?: Date): string;
13
+ /**
14
+ * The category names from the top category down to `categoryId`, joined with " › ". Null when
15
+ * `categoryId` is empty or not in `categories`. Stops at a category it has already visited.
16
+ */
17
+ export declare function DashboardCategoryPath(categoryId: string | null, categories: readonly MJDashboardCategoryEntity[]): string | null;
18
+ //# sourceMappingURL=dashboard-card.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-card.helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/dashboard-card/dashboard-card.helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AASlG,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,iBAAiB,CAAC,GAAG,OAAO,CAE3G;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAQjG;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,SAAS,yBAAyB,EAAE,GAAG,MAAM,GAAG,IAAI,CAWhI"}
@@ -0,0 +1,43 @@
1
+ import { UUIDsEqual } from '@memberjunction/global';
2
+ import { BuildDashboardLayoutPreview } from '../layout-preview/dashboard-layout-preview';
3
+ /** Separator between category names in a category path. */
4
+ const CATEGORY_PATH_SEPARATOR = ' › ';
5
+ const DAY_MS = 24 * 60 * 60 * 1000;
6
+ /** True for a Config dashboard whose saved configuration has no panel layout: it has no parts yet. */
7
+ export function IsDashboardNotSetUp(dashboard) {
8
+ return dashboard.Type === 'Config' && BuildDashboardLayoutPreview(dashboard.UIConfigDetails) === null;
9
+ }
10
+ /**
11
+ * "Today", "Yesterday", "N days ago" (under a week), else the local date. A date later than `now`
12
+ * reads "Today". Empty for no date.
13
+ */
14
+ export function FormatDashboardDate(date, now = new Date()) {
15
+ if (!date)
16
+ return '';
17
+ const d = new Date(date);
18
+ const diffDays = Math.floor((now.getTime() - d.getTime()) / DAY_MS);
19
+ if (diffDays <= 0)
20
+ return 'Today';
21
+ if (diffDays === 1)
22
+ return 'Yesterday';
23
+ if (diffDays < 7)
24
+ return `${diffDays} days ago`;
25
+ return d.toLocaleDateString();
26
+ }
27
+ /**
28
+ * The category names from the top category down to `categoryId`, joined with " › ". Null when
29
+ * `categoryId` is empty or not in `categories`. Stops at a category it has already visited.
30
+ */
31
+ export function DashboardCategoryPath(categoryId, categories) {
32
+ const names = [];
33
+ const visited = new Set();
34
+ let current = categoryId ? categories.find(c => UUIDsEqual(c.ID, categoryId)) : undefined;
35
+ while (current && !visited.has(current)) {
36
+ visited.add(current);
37
+ names.unshift(current.Name);
38
+ const parentId = current.ParentID;
39
+ current = parentId ? categories.find(c => UUIDsEqual(c.ID, parentId)) : undefined;
40
+ }
41
+ return names.length ? names.join(CATEGORY_PATH_SEPARATOR) : null;
42
+ }
43
+ //# sourceMappingURL=dashboard-card.helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-card.helpers.js","sourceRoot":"","sources":["../../../src/lib/dashboard-card/dashboard-card.helpers.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AAEzF,2DAA2D;AAC3D,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAEtC,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,sGAAsG;AACtG,MAAM,UAAU,mBAAmB,CAAC,SAA8D;IAC9F,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,2BAA2B,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;AAC1G,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAA6B,EAAE,MAAY,IAAI,IAAI,EAAE;IACrF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC;IACpE,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC;IAClC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACvC,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,GAAG,QAAQ,WAAW,CAAC;IAChD,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAyB,EAAE,UAAgD;IAC7G,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,IAAI,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrE,CAAC","sourcesContent":["/**\n * @fileoverview Pure helpers for dashboard cards and the dashboard browser: whether a dashboard has\n * no parts yet, how a last update reads, and a category's path.\n */\nimport type { MJDashboardCategoryEntity, MJDashboardEntity } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BuildDashboardLayoutPreview } from '../layout-preview/dashboard-layout-preview';\n\n/** Separator between category names in a category path. */\nconst CATEGORY_PATH_SEPARATOR = ' › ';\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** True for a Config dashboard whose saved configuration has no panel layout: it has no parts yet. */\nexport function IsDashboardNotSetUp(dashboard: Pick<MJDashboardEntity, 'Type' | 'UIConfigDetails'>): boolean {\n return dashboard.Type === 'Config' && BuildDashboardLayoutPreview(dashboard.UIConfigDetails) === null;\n}\n\n/**\n * \"Today\", \"Yesterday\", \"N days ago\" (under a week), else the local date. A date later than `now`\n * reads \"Today\". Empty for no date.\n */\nexport function FormatDashboardDate(date: Date | null | undefined, now: Date = new Date()): string {\n if (!date) return '';\n const d = new Date(date);\n const diffDays = Math.floor((now.getTime() - d.getTime()) / DAY_MS);\n if (diffDays <= 0) return 'Today';\n if (diffDays === 1) return 'Yesterday';\n if (diffDays < 7) return `${diffDays} days ago`;\n return d.toLocaleDateString();\n}\n\n/**\n * The category names from the top category down to `categoryId`, joined with \" › \". Null when\n * `categoryId` is empty or not in `categories`. Stops at a category it has already visited.\n */\nexport function DashboardCategoryPath(categoryId: string | null, categories: readonly MJDashboardCategoryEntity[]): string | null {\n const names: string[] = [];\n const visited = new Set<MJDashboardCategoryEntity>();\n let current = categoryId ? categories.find(c => UUIDsEqual(c.ID, categoryId)) : undefined;\n while (current && !visited.has(current)) {\n visited.add(current);\n names.unshift(current.Name);\n const parentId = current.ParentID;\n current = parentId ? categories.find(c => UUIDsEqual(c.ID, parentId)) : undefined;\n }\n return names.length ? names.join(CATEGORY_PATH_SEPARATOR) : null;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { MJDashboardEntity } from '@memberjunction/core-entities';
2
+ import { DashboardLayoutPreviewNode } from '../layout-preview/dashboard-layout-preview';
3
+ /**
4
+ * The layout preview a dashboard card draws: the tree of a Config dashboard's saved panel layout,
5
+ * or null (a Code dashboard, or no panels). It builds the tree again only when the saved
6
+ * configuration or the type changes, so a template can ask on every change detection, also after
7
+ * the same dashboard object is saved again, and the preview gets the same tree until then.
8
+ */
9
+ export declare class LayoutPreviewCache {
10
+ private checkedDetails;
11
+ private checkedType;
12
+ private preview;
13
+ PreviewFor(dashboard: Pick<MJDashboardEntity, 'Type' | 'UIConfigDetails'>): DashboardLayoutPreviewNode | null;
14
+ }
15
+ //# sourceMappingURL=layout-preview-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-preview-cache.d.ts","sourceRoot":"","sources":["../../../src/lib/dashboard-card/layout-preview-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAA+B,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAErH;;;;;GAKG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAA0C;IAC7D,OAAO,CAAC,OAAO,CAA2C;IAEnD,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,iBAAiB,CAAC,GAAG,0BAA0B,GAAG,IAAI;CASvH"}
@@ -0,0 +1,22 @@
1
+ import { BuildDashboardLayoutPreview } from '../layout-preview/dashboard-layout-preview';
2
+ /**
3
+ * The layout preview a dashboard card draws: the tree of a Config dashboard's saved panel layout,
4
+ * or null (a Code dashboard, or no panels). It builds the tree again only when the saved
5
+ * configuration or the type changes, so a template can ask on every change detection, also after
6
+ * the same dashboard object is saved again, and the preview gets the same tree until then.
7
+ */
8
+ export class LayoutPreviewCache {
9
+ checkedDetails = null;
10
+ checkedType = null;
11
+ preview = null;
12
+ PreviewFor(dashboard) {
13
+ const details = dashboard.UIConfigDetails ?? null;
14
+ if (details !== this.checkedDetails || dashboard.Type !== this.checkedType) {
15
+ this.checkedDetails = details;
16
+ this.checkedType = dashboard.Type;
17
+ this.preview = dashboard.Type === 'Config' ? BuildDashboardLayoutPreview(details) : null;
18
+ }
19
+ return this.preview;
20
+ }
21
+ }
22
+ //# sourceMappingURL=layout-preview-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-preview-cache.js","sourceRoot":"","sources":["../../../src/lib/dashboard-card/layout-preview-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAA8B,MAAM,4CAA4C,CAAC;AAErH;;;;;GAKG;AACH,MAAM,OAAO,kBAAkB;IACnB,cAAc,GAAkB,IAAI,CAAC;IACrC,WAAW,GAAqC,IAAI,CAAC;IACrD,OAAO,GAAsC,IAAI,CAAC;IAEnD,UAAU,CAAC,SAA8D;QAC5E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe,IAAI,IAAI,CAAC;QAClD,IAAI,OAAO,KAAK,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YACzE,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;YAC9B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC;YAClC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,2BAA2B,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7F,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;CACJ","sourcesContent":["import type { MJDashboardEntity } from '@memberjunction/core-entities';\nimport { BuildDashboardLayoutPreview, DashboardLayoutPreviewNode } from '../layout-preview/dashboard-layout-preview';\n\n/**\n * The layout preview a dashboard card draws: the tree of a Config dashboard's saved panel layout,\n * or null (a Code dashboard, or no panels). It builds the tree again only when the saved\n * configuration or the type changes, so a template can ask on every change detection, also after\n * the same dashboard object is saved again, and the preview gets the same tree until then.\n */\nexport class LayoutPreviewCache {\n private checkedDetails: string | null = null;\n private checkedType: MJDashboardEntity['Type'] | null = null;\n private preview: DashboardLayoutPreviewNode | null = null;\n\n public PreviewFor(dashboard: Pick<MJDashboardEntity, 'Type' | 'UIConfigDetails'>): DashboardLayoutPreviewNode | null {\n const details = dashboard.UIConfigDetails ?? null;\n if (details !== this.checkedDetails || dashboard.Type !== this.checkedType) {\n this.checkedDetails = details;\n this.checkedType = dashboard.Type;\n this.preview = dashboard.Type === 'Config' ? BuildDashboardLayoutPreview(details) : null;\n }\n return this.preview;\n }\n}\n"]}