@memberjunction/ng-list-management 5.34.1 → 5.36.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.
- package/README.md +179 -85
- package/dist/lib/components/audience-source-picker/audience-source-picker.component.d.ts +74 -0
- package/dist/lib/components/audience-source-picker/audience-source-picker.component.d.ts.map +1 -0
- package/dist/lib/components/audience-source-picker/audience-source-picker.component.js +396 -0
- package/dist/lib/components/audience-source-picker/audience-source-picker.component.js.map +1 -0
- package/dist/lib/components/audience-source-summary/audience-source-summary.component.d.ts +34 -0
- package/dist/lib/components/audience-source-summary/audience-source-summary.component.d.ts.map +1 -0
- package/dist/lib/components/audience-source-summary/audience-source-summary.component.js +136 -0
- package/dist/lib/components/audience-source-summary/audience-source-summary.component.js.map +1 -0
- package/dist/lib/components/list-audit-log/list-audit-log.component.d.ts +55 -0
- package/dist/lib/components/list-audit-log/list-audit-log.component.d.ts.map +1 -0
- package/dist/lib/components/list-audit-log/list-audit-log.component.js +280 -0
- package/dist/lib/components/list-audit-log/list-audit-log.component.js.map +1 -0
- package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.d.ts +64 -0
- package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.d.ts.map +1 -0
- package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.js +323 -0
- package/dist/lib/components/list-delta-confirm/list-delta-confirm.component.js.map +1 -0
- package/dist/lib/components/list-invitations/list-invitations.component.d.ts +60 -0
- package/dist/lib/components/list-invitations/list-invitations.component.d.ts.map +1 -0
- package/dist/lib/components/list-invitations/list-invitations.component.js +367 -0
- package/dist/lib/components/list-invitations/list-invitations.component.js.map +1 -0
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.js +0 -4
- package/dist/lib/components/list-management-dialog/list-management-dialog.component.js.map +1 -1
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts +18 -1
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.d.ts.map +1 -1
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.js +115 -66
- package/dist/lib/components/list-share-dialog/list-share-dialog.component.js.map +1 -1
- package/dist/lib/components/list-stats/list-stats.component.d.ts +52 -0
- package/dist/lib/components/list-stats/list-stats.component.d.ts.map +1 -0
- package/dist/lib/components/list-stats/list-stats.component.js +283 -0
- package/dist/lib/components/list-stats/list-stats.component.js.map +1 -0
- package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.d.ts +68 -0
- package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.d.ts.map +1 -0
- package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.js +316 -0
- package/dist/lib/components/save-view-as-list-dialog/save-view-as-list-dialog.component.js.map +1 -0
- package/dist/lib/components/shared-with-me/shared-with-me.component.d.ts +47 -0
- package/dist/lib/components/shared-with-me/shared-with-me.component.d.ts.map +1 -0
- package/dist/lib/components/shared-with-me/shared-with-me.component.js +231 -0
- package/dist/lib/components/shared-with-me/shared-with-me.component.js.map +1 -0
- package/dist/lib/components/tag-chips/tag-chips.component.d.ts +85 -0
- package/dist/lib/components/tag-chips/tag-chips.component.d.ts.map +1 -0
- package/dist/lib/components/tag-chips/tag-chips.component.js +392 -0
- package/dist/lib/components/tag-chips/tag-chips.component.js.map +1 -0
- package/dist/lib/models/list-sharing.models.d.ts +5 -0
- package/dist/lib/models/list-sharing.models.d.ts.map +1 -1
- package/dist/lib/models/list-sharing.models.js.map +1 -1
- package/dist/lib/module.d.ts +17 -8
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +51 -6
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/services/list-management.service.d.ts.map +1 -1
- package/dist/lib/services/list-management.service.js +0 -9
- package/dist/lib/services/list-management.service.js.map +1 -1
- package/dist/lib/services/list-sharing.service.d.ts +8 -3
- package/dist/lib/services/list-sharing.service.d.ts.map +1 -1
- package/dist/lib/services/list-sharing.service.js +33 -15
- package/dist/lib/services/list-sharing.service.js.map +1 -1
- package/dist/public-api.d.ts +9 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +9 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +13 -11
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Output, inject } from '@angular/core';
|
|
2
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
+
import { GraphQLListsClient } from '@memberjunction/graphql-dataprovider';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
import * as i2 from "@angular/forms";
|
|
7
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
8
|
+
import * as i4 from "@memberjunction/ng-shared-generic";
|
|
9
|
+
const _forTrack0 = ($index, $item) => $item.ListID;
|
|
10
|
+
function ListsSharedWithMeComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
11
|
+
i0.ɵɵelementStart(0, "div", 12);
|
|
12
|
+
i0.ɵɵelement(1, "mj-loading", 16);
|
|
13
|
+
i0.ɵɵelementEnd();
|
|
14
|
+
} }
|
|
15
|
+
function ListsSharedWithMeComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
16
|
+
i0.ɵɵelementStart(0, "div", 13);
|
|
17
|
+
i0.ɵɵelement(1, "i", 17);
|
|
18
|
+
i0.ɵɵelementStart(2, "span");
|
|
19
|
+
i0.ɵɵtext(3);
|
|
20
|
+
i0.ɵɵelementEnd()();
|
|
21
|
+
} if (rf & 2) {
|
|
22
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
23
|
+
i0.ɵɵadvance(3);
|
|
24
|
+
i0.ɵɵtextInterpolate(ctx_r0.errorMessage);
|
|
25
|
+
} }
|
|
26
|
+
function ListsSharedWithMeComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
28
|
+
i0.ɵɵelement(1, "i", 18);
|
|
29
|
+
i0.ɵɵelementStart(2, "h3");
|
|
30
|
+
i0.ɵɵtext(3, "No lists shared with you");
|
|
31
|
+
i0.ɵɵelementEnd();
|
|
32
|
+
i0.ɵɵelementStart(4, "p");
|
|
33
|
+
i0.ɵɵtext(5, "When someone shares a list with you, it'll appear here.");
|
|
34
|
+
i0.ɵɵelementEnd()();
|
|
35
|
+
} }
|
|
36
|
+
function ListsSharedWithMeComponent_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
37
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
38
|
+
i0.ɵɵelementStart(0, "div", 20);
|
|
39
|
+
i0.ɵɵlistener("click", function ListsSharedWithMeComponent_Conditional_20_For_2_Template_div_click_0_listener() { const share_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnCardClick(share_r3.ListID)); });
|
|
40
|
+
i0.ɵɵelementStart(1, "div", 21)(2, "div", 22);
|
|
41
|
+
i0.ɵɵelement(3, "i", 23);
|
|
42
|
+
i0.ɵɵelementEnd();
|
|
43
|
+
i0.ɵɵelementStart(4, "div", 24);
|
|
44
|
+
i0.ɵɵtext(5);
|
|
45
|
+
i0.ɵɵelementEnd()();
|
|
46
|
+
i0.ɵɵelementStart(6, "div", 25)(7, "span", 26);
|
|
47
|
+
i0.ɵɵtext(8);
|
|
48
|
+
i0.ɵɵelementEnd();
|
|
49
|
+
i0.ɵɵelementStart(9, "span", 27);
|
|
50
|
+
i0.ɵɵtext(10);
|
|
51
|
+
i0.ɵɵelementEnd()()();
|
|
52
|
+
} if (rf & 2) {
|
|
53
|
+
const share_r3 = ctx.$implicit;
|
|
54
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
55
|
+
i0.ɵɵadvance(5);
|
|
56
|
+
i0.ɵɵtextInterpolate(share_r3.ListName);
|
|
57
|
+
i0.ɵɵadvance(2);
|
|
58
|
+
i0.ɵɵproperty("ngClass", ctx_r0.badgeClass(share_r3.PermissionLevel));
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.badgeLabel(share_r3.PermissionLevel), " ");
|
|
61
|
+
i0.ɵɵadvance(2);
|
|
62
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatRelative(share_r3.SharedAt));
|
|
63
|
+
} }
|
|
64
|
+
function ListsSharedWithMeComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
66
|
+
i0.ɵɵrepeaterCreate(1, ListsSharedWithMeComponent_Conditional_20_For_2_Template, 11, 4, "div", 19, _forTrack0);
|
|
67
|
+
i0.ɵɵelementEnd();
|
|
68
|
+
} if (rf & 2) {
|
|
69
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
70
|
+
i0.ɵɵadvance();
|
|
71
|
+
i0.ɵɵrepeater(ctx_r0.visibleShares);
|
|
72
|
+
} }
|
|
73
|
+
/**
|
|
74
|
+
* "Shared With Me" view (mockup 17). Lists every `MJ: List` the current
|
|
75
|
+
* user has direct-share access to, plus a permission badge per row.
|
|
76
|
+
*
|
|
77
|
+
* Drop into the Lists app as a tab/resource. Click events bubble up via
|
|
78
|
+
* `OpenList` so the host app can route through its own navigation
|
|
79
|
+
* (NavigationService etc.) — keeps this component framework-agnostic.
|
|
80
|
+
*/
|
|
81
|
+
export class ListsSharedWithMeComponent extends BaseAngularComponent {
|
|
82
|
+
cdr = inject(ChangeDetectorRef);
|
|
83
|
+
/** Emitted when the user clicks a card. Host wires this to navigation.
|
|
84
|
+
* Includes ListName so the host can open a properly-titled tab without
|
|
85
|
+
* a second fetch. */
|
|
86
|
+
OpenList = new EventEmitter();
|
|
87
|
+
/** Permission-level filter (empty = "All Permissions"). */
|
|
88
|
+
filterLevel = '';
|
|
89
|
+
/** Free-text filter on list name. */
|
|
90
|
+
filterText = '';
|
|
91
|
+
loading = false;
|
|
92
|
+
errorMessage = null;
|
|
93
|
+
allShares = [];
|
|
94
|
+
async ngOnInit() {
|
|
95
|
+
await this.loadShares();
|
|
96
|
+
}
|
|
97
|
+
get visibleShares() {
|
|
98
|
+
const term = this.filterText.trim().toLowerCase();
|
|
99
|
+
return this.allShares.filter((s) => {
|
|
100
|
+
if (this.filterLevel && s.PermissionLevel !== this.filterLevel)
|
|
101
|
+
return false;
|
|
102
|
+
if (term && !s.ListName.toLowerCase().includes(term))
|
|
103
|
+
return false;
|
|
104
|
+
return true;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
OnFilterChange() {
|
|
108
|
+
this.cdr.markForCheck();
|
|
109
|
+
}
|
|
110
|
+
OnCardClick(listId) {
|
|
111
|
+
const share = this.allShares.find((s) => s.ListID === listId);
|
|
112
|
+
this.OpenList.emit({ ListID: listId, ListName: share?.ListName ?? '' });
|
|
113
|
+
}
|
|
114
|
+
async Refresh() {
|
|
115
|
+
await this.loadShares();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Friendly-format the "shared at" timestamp into a relative phrase
|
|
119
|
+
* ("3d ago", "2w ago"). Matches the mockup; falls back to absolute on
|
|
120
|
+
* older entries.
|
|
121
|
+
*/
|
|
122
|
+
formatRelative(date) {
|
|
123
|
+
const diffMs = Date.now() - date.getTime();
|
|
124
|
+
const seconds = Math.floor(diffMs / 1000);
|
|
125
|
+
if (seconds < 60)
|
|
126
|
+
return 'just now';
|
|
127
|
+
const minutes = Math.floor(seconds / 60);
|
|
128
|
+
if (minutes < 60)
|
|
129
|
+
return `${minutes}m ago`;
|
|
130
|
+
const hours = Math.floor(minutes / 60);
|
|
131
|
+
if (hours < 24)
|
|
132
|
+
return `${hours}h ago`;
|
|
133
|
+
const days = Math.floor(hours / 24);
|
|
134
|
+
if (days < 7)
|
|
135
|
+
return `${days}d ago`;
|
|
136
|
+
const weeks = Math.floor(days / 7);
|
|
137
|
+
if (weeks < 5)
|
|
138
|
+
return `${weeks}w ago`;
|
|
139
|
+
const months = Math.floor(days / 30);
|
|
140
|
+
if (months < 12)
|
|
141
|
+
return `${months}mo ago`;
|
|
142
|
+
return date.toLocaleDateString();
|
|
143
|
+
}
|
|
144
|
+
/** Badge variant class for the permission-level chip. */
|
|
145
|
+
badgeClass(level) {
|
|
146
|
+
switch (level) {
|
|
147
|
+
case 'Owner':
|
|
148
|
+
return 'badge--owner';
|
|
149
|
+
case 'Edit':
|
|
150
|
+
return 'badge--editor';
|
|
151
|
+
default:
|
|
152
|
+
return 'badge--viewer';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
badgeLabel(level) {
|
|
156
|
+
switch (level) {
|
|
157
|
+
case 'Owner':
|
|
158
|
+
return 'Owner';
|
|
159
|
+
case 'Edit':
|
|
160
|
+
return 'Editor';
|
|
161
|
+
default:
|
|
162
|
+
return 'Viewer';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async loadShares() {
|
|
166
|
+
this.loading = true;
|
|
167
|
+
this.errorMessage = null;
|
|
168
|
+
this.cdr.markForCheck();
|
|
169
|
+
try {
|
|
170
|
+
const provider = this.ProviderToUse;
|
|
171
|
+
const client = new GraphQLListsClient(provider);
|
|
172
|
+
this.allShares = await client.ListsSharedWithMe();
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
this.errorMessage = e instanceof Error ? e.message : String(e);
|
|
176
|
+
this.allShares = [];
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
this.loading = false;
|
|
180
|
+
this.cdr.markForCheck();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵListsSharedWithMeComponent_BaseFactory; return function ListsSharedWithMeComponent_Factory(__ngFactoryType__) { return (ɵListsSharedWithMeComponent_BaseFactory || (ɵListsSharedWithMeComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ListsSharedWithMeComponent)))(__ngFactoryType__ || ListsSharedWithMeComponent); }; })();
|
|
184
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ListsSharedWithMeComponent, selectors: [["mj-lists-shared-with-me"]], outputs: { OpenList: "OpenList" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 21, vars: 4, consts: [[1, "shared-with-me"], [1, "shared-toolbar"], [1, "search-box"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Filter shared lists\u2026", 1, "mj-input", 3, "ngModelChange", "ngModel"], ["title", "Filter by permission", 1, "mj-input", "mj-select", "permission-filter", 3, "ngModelChange", "ngModel"], ["value", ""], ["value", "View"], ["value", "Edit"], ["value", "Owner"], ["mjButton", "", "variant", "outline", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate"], [1, "state-block"], [1, "state-block", "state-block--error"], [1, "state-block", "state-block--empty"], [1, "list-grid"], ["text", "Loading shared lists...", "size", "medium"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "fa-solid", "fa-share-nodes"], ["tabindex", "0", 1, "list-card"], ["tabindex", "0", 1, "list-card", 3, "click"], [1, "list-card__header"], [1, "list-card__icon"], [1, "fa-solid", "fa-list"], [1, "list-card__title"], [1, "list-card__footer"], [1, "permission-badge", 3, "ngClass"], [1, "list-card__shared-at"]], template: function ListsSharedWithMeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
185
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
186
|
+
i0.ɵɵelement(3, "i", 3);
|
|
187
|
+
i0.ɵɵelementStart(4, "input", 4);
|
|
188
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ListsSharedWithMeComponent_Template_input_ngModelChange_4_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filterText, $event) || (ctx.filterText = $event); return $event; });
|
|
189
|
+
i0.ɵɵlistener("ngModelChange", function ListsSharedWithMeComponent_Template_input_ngModelChange_4_listener() { return ctx.OnFilterChange(); });
|
|
190
|
+
i0.ɵɵelementEnd()();
|
|
191
|
+
i0.ɵɵelementStart(5, "select", 5);
|
|
192
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ListsSharedWithMeComponent_Template_select_ngModelChange_5_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filterLevel, $event) || (ctx.filterLevel = $event); return $event; });
|
|
193
|
+
i0.ɵɵlistener("ngModelChange", function ListsSharedWithMeComponent_Template_select_ngModelChange_5_listener() { return ctx.OnFilterChange(); });
|
|
194
|
+
i0.ɵɵelementStart(6, "option", 6);
|
|
195
|
+
i0.ɵɵtext(7, "All Permissions");
|
|
196
|
+
i0.ɵɵelementEnd();
|
|
197
|
+
i0.ɵɵelementStart(8, "option", 7);
|
|
198
|
+
i0.ɵɵtext(9, "Viewer");
|
|
199
|
+
i0.ɵɵelementEnd();
|
|
200
|
+
i0.ɵɵelementStart(10, "option", 8);
|
|
201
|
+
i0.ɵɵtext(11, "Editor");
|
|
202
|
+
i0.ɵɵelementEnd();
|
|
203
|
+
i0.ɵɵelementStart(12, "option", 9);
|
|
204
|
+
i0.ɵɵtext(13, "Owner");
|
|
205
|
+
i0.ɵɵelementEnd()();
|
|
206
|
+
i0.ɵɵelementStart(14, "button", 10);
|
|
207
|
+
i0.ɵɵlistener("click", function ListsSharedWithMeComponent_Template_button_click_14_listener() { return ctx.Refresh(); });
|
|
208
|
+
i0.ɵɵelement(15, "i", 11);
|
|
209
|
+
i0.ɵɵtext(16, " Refresh ");
|
|
210
|
+
i0.ɵɵelementEnd()();
|
|
211
|
+
i0.ɵɵconditionalCreate(17, ListsSharedWithMeComponent_Conditional_17_Template, 2, 0, "div", 12)(18, ListsSharedWithMeComponent_Conditional_18_Template, 4, 1, "div", 13)(19, ListsSharedWithMeComponent_Conditional_19_Template, 6, 0, "div", 14)(20, ListsSharedWithMeComponent_Conditional_20_Template, 3, 0, "div", 15);
|
|
212
|
+
i0.ɵɵelementEnd();
|
|
213
|
+
} if (rf & 2) {
|
|
214
|
+
i0.ɵɵadvance(4);
|
|
215
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.filterText);
|
|
216
|
+
i0.ɵɵadvance();
|
|
217
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.filterLevel);
|
|
218
|
+
i0.ɵɵadvance(9);
|
|
219
|
+
i0.ɵɵproperty("disabled", ctx.loading);
|
|
220
|
+
i0.ɵɵadvance(3);
|
|
221
|
+
i0.ɵɵconditional(ctx.loading ? 17 : ctx.errorMessage ? 18 : ctx.visibleShares.length === 0 ? 19 : 20);
|
|
222
|
+
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.MJButtonDirective, i4.LoadingComponent], styles: [".shared-with-me[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n}\n\n.shared-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-box[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 320px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n pointer-events: none;\n}\n\n.search-box[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n width: 100%;\n padding-left: 32px;\n}\n\n.permission-filter[_ngcontent-%COMP%] {\n width: 160px;\n}\n\n.state-block[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 48px 24px;\n color: var(--mj-text-secondary);\n font-size: 13.5px;\n}\n\n.state-block--error[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.state-block--empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n color: var(--mj-text-primary);\n}\n\n.state-block--empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.list-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.list-card[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: border-color 0.15s ease, background 0.15s ease;\n}\n\n.list-card[_ngcontent-%COMP%]:hover, \n.list-card[_ngcontent-%COMP%]:focus-visible {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n outline: none;\n}\n\n.list-card__header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.list-card__icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.list-card__title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.list-card__footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.list-card__shared-at[_ngcontent-%COMP%] {\n margin-left: auto;\n}\n\n.permission-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 999px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n.badge--viewer[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.badge--editor[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n}\n\n.badge--owner[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n}"], changeDetection: 0 });
|
|
223
|
+
}
|
|
224
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ListsSharedWithMeComponent, [{
|
|
225
|
+
type: Component,
|
|
226
|
+
args: [{ standalone: false, selector: 'mj-lists-shared-with-me', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"shared-with-me\">\n <!-- Toolbar -->\n <div class=\"shared-toolbar\">\n <div class=\"search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n class=\"mj-input\"\n type=\"text\"\n [(ngModel)]=\"filterText\"\n (ngModelChange)=\"OnFilterChange()\"\n placeholder=\"Filter shared lists\u2026\" />\n </div>\n <select\n class=\"mj-input mj-select permission-filter\"\n [(ngModel)]=\"filterLevel\"\n (ngModelChange)=\"OnFilterChange()\"\n title=\"Filter by permission\">\n <option value=\"\">All Permissions</option>\n <option value=\"View\">Viewer</option>\n <option value=\"Edit\">Editor</option>\n <option value=\"Owner\">Owner</option>\n </select>\n <button mjButton variant=\"outline\" (click)=\"Refresh()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-rotate\"></i>\n Refresh\n </button>\n </div>\n\n @if (loading) {\n <div class=\"state-block\">\n <mj-loading text=\"Loading shared lists...\" size=\"medium\"></mj-loading>\n </div>\n } @else if (errorMessage) {\n <div class=\"state-block state-block--error\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (visibleShares.length === 0) {\n <div class=\"state-block state-block--empty\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <h3>No lists shared with you</h3>\n <p>When someone shares a list with you, it'll appear here.</p>\n </div>\n } @else {\n <div class=\"list-grid\">\n @for (share of visibleShares; track share.ListID) {\n <div class=\"list-card\" (click)=\"OnCardClick(share.ListID)\" tabindex=\"0\">\n <div class=\"list-card__header\">\n <div class=\"list-card__icon\">\n <i class=\"fa-solid fa-list\"></i>\n </div>\n <div class=\"list-card__title\">{{ share.ListName }}</div>\n </div>\n <div class=\"list-card__footer\">\n <span class=\"permission-badge\" [ngClass]=\"badgeClass(share.PermissionLevel)\">\n {{ badgeLabel(share.PermissionLevel) }}\n </span>\n <span class=\"list-card__shared-at\">{{ formatRelative(share.SharedAt) }}</span>\n </div>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".shared-with-me {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 16px;\n}\n\n.shared-toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.search-box {\n flex: 1;\n max-width: 320px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.search-box i {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n pointer-events: none;\n}\n\n.search-box input {\n width: 100%;\n padding-left: 32px;\n}\n\n.permission-filter {\n width: 160px;\n}\n\n.state-block {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 48px 24px;\n color: var(--mj-text-secondary);\n font-size: 13.5px;\n}\n\n.state-block--error {\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.state-block--empty h3 {\n margin: 0;\n font-size: 18px;\n color: var(--mj-text-primary);\n}\n\n.state-block--empty i {\n font-size: 32px;\n color: var(--mj-text-muted);\n}\n\n.list-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.list-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n cursor: pointer;\n transition: border-color 0.15s ease, background 0.15s ease;\n}\n\n.list-card:hover,\n.list-card:focus-visible {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 4%, var(--mj-bg-surface));\n outline: none;\n}\n\n.list-card__header {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.list-card__icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.list-card__title {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.list-card__footer {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.list-card__shared-at {\n margin-left: auto;\n}\n\n.permission-badge {\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 999px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n.badge--viewer {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.badge--editor {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n}\n\n.badge--owner {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n}\n"] }]
|
|
227
|
+
}], null, { OpenList: [{
|
|
228
|
+
type: Output
|
|
229
|
+
}] }); })();
|
|
230
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ListsSharedWithMeComponent, { className: "ListsSharedWithMeComponent", filePath: "src/lib/components/shared-with-me/shared-with-me.component.ts", lineNumber: 22 }); })();
|
|
231
|
+
//# sourceMappingURL=shared-with-me.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-with-me.component.js","sourceRoot":"","sources":["../../../../src/lib/components/shared-with-me/shared-with-me.component.ts","../../../../src/lib/components/shared-with-me/shared-with-me.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, Output, inject } from '@angular/core';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { GraphQLDataProvider, GraphQLListsClient } from '@memberjunction/graphql-dataprovider';\nimport type { SharedListSummary, SharePermissionLevel } from '@memberjunction/lists-base';\n\n/**\n * \"Shared With Me\" view (mockup 17). Lists every `MJ: List` the current\n * user has direct-share access to, plus a permission badge per row.\n *\n * Drop into the Lists app as a tab/resource. Click events bubble up via\n * `OpenList` so the host app can route through its own navigation\n * (NavigationService etc.) — keeps this component framework-agnostic.\n */\n@Component({\n standalone: false,\n selector: 'mj-lists-shared-with-me',\n templateUrl: './shared-with-me.component.html',\n styleUrls: ['./shared-with-me.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ListsSharedWithMeComponent extends BaseAngularComponent implements OnInit {\n private readonly cdr = inject(ChangeDetectorRef);\n\n /** Emitted when the user clicks a card. Host wires this to navigation.\n * Includes ListName so the host can open a properly-titled tab without\n * a second fetch. */\n @Output() OpenList = new EventEmitter<{ ListID: string; ListName: string }>();\n\n /** Permission-level filter (empty = \"All Permissions\"). */\n public filterLevel: SharePermissionLevel | '' = '';\n\n /** Free-text filter on list name. */\n public filterText = '';\n\n public loading = false;\n public errorMessage: string | null = null;\n private allShares: SharedListSummary[] = [];\n\n async ngOnInit(): Promise<void> {\n await this.loadShares();\n }\n\n public get visibleShares(): SharedListSummary[] {\n const term = this.filterText.trim().toLowerCase();\n return this.allShares.filter((s) => {\n if (this.filterLevel && s.PermissionLevel !== this.filterLevel) return false;\n if (term && !s.ListName.toLowerCase().includes(term)) return false;\n return true;\n });\n }\n\n public OnFilterChange(): void {\n this.cdr.markForCheck();\n }\n\n public OnCardClick(listId: string): void {\n const share = this.allShares.find((s) => s.ListID === listId);\n this.OpenList.emit({ ListID: listId, ListName: share?.ListName ?? '' });\n }\n\n public async Refresh(): Promise<void> {\n await this.loadShares();\n }\n\n /**\n * Friendly-format the \"shared at\" timestamp into a relative phrase\n * (\"3d ago\", \"2w ago\"). Matches the mockup; falls back to absolute on\n * older entries.\n */\n public formatRelative(date: Date): string {\n const diffMs = Date.now() - date.getTime();\n const seconds = Math.floor(diffMs / 1000);\n if (seconds < 60) return 'just now';\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 7) return `${days}d ago`;\n const weeks = Math.floor(days / 7);\n if (weeks < 5) return `${weeks}w ago`;\n const months = Math.floor(days / 30);\n if (months < 12) return `${months}mo ago`;\n return date.toLocaleDateString();\n }\n\n /** Badge variant class for the permission-level chip. */\n public badgeClass(level: SharePermissionLevel): string {\n switch (level) {\n case 'Owner':\n return 'badge--owner';\n case 'Edit':\n return 'badge--editor';\n default:\n return 'badge--viewer';\n }\n }\n\n public badgeLabel(level: SharePermissionLevel): string {\n switch (level) {\n case 'Owner':\n return 'Owner';\n case 'Edit':\n return 'Editor';\n default:\n return 'Viewer';\n }\n }\n\n private async loadShares(): Promise<void> {\n this.loading = true;\n this.errorMessage = null;\n this.cdr.markForCheck();\n try {\n const provider = this.ProviderToUse as unknown as GraphQLDataProvider;\n const client = new GraphQLListsClient(provider);\n this.allShares = await client.ListsSharedWithMe();\n } catch (e) {\n this.errorMessage = e instanceof Error ? e.message : String(e);\n this.allShares = [];\n } finally {\n this.loading = false;\n this.cdr.markForCheck();\n }\n }\n}\n","<div class=\"shared-with-me\">\n <!-- Toolbar -->\n <div class=\"shared-toolbar\">\n <div class=\"search-box\">\n <i class=\"fa-solid fa-search\"></i>\n <input\n class=\"mj-input\"\n type=\"text\"\n [(ngModel)]=\"filterText\"\n (ngModelChange)=\"OnFilterChange()\"\n placeholder=\"Filter shared lists…\" />\n </div>\n <select\n class=\"mj-input mj-select permission-filter\"\n [(ngModel)]=\"filterLevel\"\n (ngModelChange)=\"OnFilterChange()\"\n title=\"Filter by permission\">\n <option value=\"\">All Permissions</option>\n <option value=\"View\">Viewer</option>\n <option value=\"Edit\">Editor</option>\n <option value=\"Owner\">Owner</option>\n </select>\n <button mjButton variant=\"outline\" (click)=\"Refresh()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-rotate\"></i>\n Refresh\n </button>\n </div>\n\n @if (loading) {\n <div class=\"state-block\">\n <mj-loading text=\"Loading shared lists...\" size=\"medium\"></mj-loading>\n </div>\n } @else if (errorMessage) {\n <div class=\"state-block state-block--error\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ errorMessage }}</span>\n </div>\n } @else if (visibleShares.length === 0) {\n <div class=\"state-block state-block--empty\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <h3>No lists shared with you</h3>\n <p>When someone shares a list with you, it'll appear here.</p>\n </div>\n } @else {\n <div class=\"list-grid\">\n @for (share of visibleShares; track share.ListID) {\n <div class=\"list-card\" (click)=\"OnCardClick(share.ListID)\" tabindex=\"0\">\n <div class=\"list-card__header\">\n <div class=\"list-card__icon\">\n <i class=\"fa-solid fa-list\"></i>\n </div>\n <div class=\"list-card__title\">{{ share.ListName }}</div>\n </div>\n <div class=\"list-card__footer\">\n <span class=\"permission-badge\" [ngClass]=\"badgeClass(share.PermissionLevel)\">\n {{ badgeLabel(share.PermissionLevel) }}\n </span>\n <span class=\"list-card__shared-at\">{{ formatRelative(share.SharedAt) }}</span>\n </div>\n </div>\n }\n </div>\n }\n</div>\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { EventEmitter, OnInit } from '@angular/core';
|
|
2
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
+
import type { MJTagEntity } from '@memberjunction/core-entities';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Compact tag chips for a single record (mockup 22). Loads tags by
|
|
7
|
+
* querying `MJ: Tagged Items` filtered to `(EntityID, RecordID)`, then
|
|
8
|
+
* resolves names from `MJ: Tags` in a single batch. Render-only by
|
|
9
|
+
* default; pass `Editable=true` to surface an inline add field and
|
|
10
|
+
* per-chip remove buttons.
|
|
11
|
+
*
|
|
12
|
+
* Intentionally lightweight — not a tag manager. For richer tag tooling
|
|
13
|
+
* (cloud view, related records, etc.) use `mj-record-tags` from
|
|
14
|
+
* `@memberjunction/ng-record-tags`.
|
|
15
|
+
*/
|
|
16
|
+
interface DisplayTag {
|
|
17
|
+
/** TaggedItem row ID — used for removal. */
|
|
18
|
+
TaggedItemID: string;
|
|
19
|
+
/** Tag.ID — useful for downstream filtering / lookups. */
|
|
20
|
+
TagID: string;
|
|
21
|
+
/** Tag display name. */
|
|
22
|
+
Name: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class TagChipsComponent extends BaseAngularComponent implements OnInit {
|
|
25
|
+
private readonly cdr;
|
|
26
|
+
/** Entity name (e.g. 'MJ: Lists'). Required. */
|
|
27
|
+
set EntityName(value: string | null);
|
|
28
|
+
get EntityName(): string | null;
|
|
29
|
+
private _entityName;
|
|
30
|
+
/** Record ID (the row's primary key, serialized). Required. */
|
|
31
|
+
set RecordID(value: string | null);
|
|
32
|
+
get RecordID(): string | null;
|
|
33
|
+
private _recordId;
|
|
34
|
+
/** When true, shows add input + remove buttons on chips. */
|
|
35
|
+
Editable: boolean;
|
|
36
|
+
/** Cap visible chips and surface "+N more". Defaults to 6 for cards. */
|
|
37
|
+
MaxDisplay: number;
|
|
38
|
+
/** Emitted when a chip is clicked. Lets the parent drive filter-by-tag. */
|
|
39
|
+
TagClicked: EventEmitter<{
|
|
40
|
+
TagID: string;
|
|
41
|
+
Name: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Emitted after add/remove so parents can refresh dependent data. */
|
|
44
|
+
TagsChanged: EventEmitter<void>;
|
|
45
|
+
tags: DisplayTag[];
|
|
46
|
+
loading: boolean;
|
|
47
|
+
addInput: string;
|
|
48
|
+
suggestions: MJTagEntity[];
|
|
49
|
+
showSuggestions: boolean;
|
|
50
|
+
/** True when the trimmed input doesn't exactly match any existing tag —
|
|
51
|
+
* drives the "Create '<term>'" affordance at the top of the dropdown. */
|
|
52
|
+
canCreateNew: boolean;
|
|
53
|
+
private initialized;
|
|
54
|
+
private entityID;
|
|
55
|
+
ngOnInit(): Promise<void>;
|
|
56
|
+
get displayedTags(): DisplayTag[];
|
|
57
|
+
get extraTagCount(): number;
|
|
58
|
+
OnTagClick(tag: DisplayTag): void;
|
|
59
|
+
OnRemove(tag: DisplayTag, event: Event): Promise<void>;
|
|
60
|
+
OnAddInputChange(value: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Enter-key handler on the input. If suggestions are showing,
|
|
63
|
+
* picks the first one (existing tag); otherwise creates a new tag
|
|
64
|
+
* from the typed text and applies it. Closes the suggestion menu
|
|
65
|
+
* on either path.
|
|
66
|
+
*/
|
|
67
|
+
OnAddInputSubmit(event?: Event): Promise<void>;
|
|
68
|
+
OnAddTag(tag: MJTagEntity): Promise<void>;
|
|
69
|
+
/** Click handler for the "Create '<term>'" affordance. Creates the
|
|
70
|
+
* `MJ: Tags` row then attaches it via the standard apply path. */
|
|
71
|
+
OnCreateNew(): Promise<void>;
|
|
72
|
+
private CreateAndAddTag;
|
|
73
|
+
private applyTagToRecord;
|
|
74
|
+
/**
|
|
75
|
+
* Bulk-load tags + their names in two RunViews — one for the join
|
|
76
|
+
* rows and one to resolve display names. Cheap; this typically returns
|
|
77
|
+
* fewer than 10 rows.
|
|
78
|
+
*/
|
|
79
|
+
private loadTags;
|
|
80
|
+
private metadata;
|
|
81
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TagChipsComponent, never>;
|
|
82
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TagChipsComponent, "mj-tag-chips", never, { "EntityName": { "alias": "EntityName"; "required": false; }; "RecordID": { "alias": "RecordID"; "required": false; }; "Editable": { "alias": "Editable"; "required": false; }; "MaxDisplay": { "alias": "MaxDisplay"; "required": false; }; }, { "TagClicked": "TagClicked"; "TagsChanged": "TagsChanged"; }, never, never, false, never>;
|
|
83
|
+
}
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=tag-chips.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag-chips.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/tag-chips/tag-chips.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,YAAY,EAAS,MAAM,EAAkB,MAAM,eAAe,CAAC;AAEnI,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,+BAA+B,CAAC;;AAErF;;;;;;;;;;GAUG;AAEH,UAAU,UAAU;IAClB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAOa,iBAAkB,SAAQ,oBAAqB,YAAW,MAAM;IAC3E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD,gDAAgD;IAChD,IACI,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAKlC;IACD,IAAI,UAAU,IAAI,MAAM,GAAG,IAAI,CAE9B;IACD,OAAO,CAAC,WAAW,CAAuB;IAE1C,+DAA+D;IAC/D,IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAKhC;IACD,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IACD,OAAO,CAAC,SAAS,CAAuB;IAExC,4DAA4D;IACnD,QAAQ,UAAS;IAE1B,wEAAwE;IAC/D,UAAU,SAAK;IAExB,2EAA2E;IACjE,UAAU;eAA6B,MAAM;cAAQ,MAAM;OAAM;IAE3E,sEAAsE;IAC5D,WAAW,qBAA4B;IAE1C,IAAI,EAAE,UAAU,EAAE,CAAM;IACxB,OAAO,UAAS;IAChB,QAAQ,SAAM;IACd,WAAW,EAAE,WAAW,EAAE,CAAM;IAChC,eAAe,UAAS;IAC/B;8EAC0E;IACnE,YAAY,UAAS;IAE5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAuB;IAEjC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B,IAAW,aAAa,IAAI,UAAU,EAAE,CAEvC;IAED,IAAW,aAAa,IAAI,MAAM,CAEjC;IAEM,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAI3B,QAAQ,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBtD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC3D;;;;;OAKG;IACU,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAe9C,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD;uEACmE;IACtD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAM3B,eAAe;YAsBf,gBAAgB;IA4B9B;;;;OAIG;YACW,QAAQ;IAuDtB,OAAO,CAAC,QAAQ;yCA/QL,iBAAiB;2CAAjB,iBAAiB;CAkR7B"}
|