@mj-biz-apps/common-ng 5.43.0 → 5.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/lib/components/related-chips/__tests__/related-links.test.d.ts +2 -0
  2. package/dist/lib/components/related-chips/__tests__/related-links.test.d.ts.map +1 -0
  3. package/dist/lib/components/related-chips/__tests__/related-links.test.js +183 -0
  4. package/dist/lib/components/related-chips/__tests__/related-links.test.js.map +1 -0
  5. package/dist/lib/components/related-chips/related-chips.component.d.ts +132 -0
  6. package/dist/lib/components/related-chips/related-chips.component.d.ts.map +1 -0
  7. package/dist/lib/components/related-chips/related-chips.component.js +241 -0
  8. package/dist/lib/components/related-chips/related-chips.component.js.map +1 -0
  9. package/dist/lib/components/related-chips/related-links.d.ts +151 -0
  10. package/dist/lib/components/related-chips/related-links.d.ts.map +1 -0
  11. package/dist/lib/components/related-chips/related-links.js +178 -0
  12. package/dist/lib/components/related-chips/related-links.js.map +1 -0
  13. package/dist/lib/data/__tests__/directory-headline.test.d.ts +2 -0
  14. package/dist/lib/data/__tests__/directory-headline.test.d.ts.map +1 -0
  15. package/dist/lib/data/__tests__/directory-headline.test.js +102 -0
  16. package/dist/lib/data/__tests__/directory-headline.test.js.map +1 -0
  17. package/dist/lib/data/directory-stats.d.ts +23 -1
  18. package/dist/lib/data/directory-stats.d.ts.map +1 -1
  19. package/dist/lib/data/directory-stats.js +40 -0
  20. package/dist/lib/data/directory-stats.js.map +1 -1
  21. package/dist/lib/data/directory-types.d.ts +34 -0
  22. package/dist/lib/data/directory-types.d.ts.map +1 -1
  23. package/dist/lib/pages/common-dashboard.page.d.ts +7 -7
  24. package/dist/lib/pages/common-dashboard.page.d.ts.map +1 -1
  25. package/dist/lib/pages/common-dashboard.page.js +228 -202
  26. package/dist/lib/pages/common-dashboard.page.js.map +1 -1
  27. package/dist/public-api.d.ts +2 -0
  28. package/dist/public-api.d.ts.map +1 -1
  29. package/dist/public-api.js +2 -0
  30. package/dist/public-api.js.map +1 -1
  31. package/package.json +2 -2
@@ -0,0 +1,151 @@
1
+ import type { RecordNavigationEvent } from '@memberjunction/ng-base-forms';
2
+ /**
3
+ * One relationship a record header offers to follow.
4
+ *
5
+ * Give it either a {@link RecordID} (the ordinary case — this record holds the id) or a
6
+ * {@link Filter} (the reverse case — the other record holds the id, as with an Order whose Deal
7
+ * points at it). A link with neither names nothing and is dropped.
8
+ */
9
+ export interface BizAppsRelatedLink {
10
+ /** Stable identity, used to track the chip and to correlate it back to the caller's own model. */
11
+ Key: string;
12
+ /**
13
+ * Entity that owns the linked record, as a name — e.g. `'MJ_BizApps_Orders: Order Headers'`.
14
+ *
15
+ * An entity that is not in the catalog produces NO chip. That covers both "the app that owns
16
+ * this record is not installed here" and "this user may not read it", and the two are
17
+ * deliberately one outcome: the entity catalog is already permission-filtered, and a reader who
18
+ * cannot open the record is no better served by a chip than one whose host never had the app.
19
+ * `bizapps-sales`' `OrdersIsInstalled()` draws the same line for the same reason.
20
+ */
21
+ EntityName: string;
22
+ /** Forward link: the linked record's primary key value, as held on the record being displayed. */
23
+ RecordID?: string | null;
24
+ /**
25
+ * Reverse link: a filter that selects the linked record. The first row wins, so pass something
26
+ * that identifies one record. Composed by the caller, which is the only party that knows the
27
+ * other entity's column names.
28
+ */
29
+ Filter?: string;
30
+ /** Names the relationship outright. Wins over {@link LabelPrefix}. */
31
+ Label?: string;
32
+ /**
33
+ * Builds the label as `<prefix> <entity's singular name>` — "Source Deal", "Source Order".
34
+ *
35
+ * For a polymorphic link, where the caller knows the ROLE the other record plays but not which
36
+ * entity fills it until the id is resolved. Hardcoding "Deal" is what this avoids.
37
+ */
38
+ LabelPrefix?: string;
39
+ /** Font Awesome class for a small leading icon. Optional. */
40
+ Icon?: string;
41
+ }
42
+ /** The part of `EntityInfo` a link needs. `EntityInfo` satisfies this. */
43
+ export interface RelatedLinkEntity {
44
+ Name: string;
45
+ BaseTableDisplayName: string;
46
+ NameField: {
47
+ Name: string;
48
+ } | null;
49
+ PrimaryKeys: {
50
+ Name: string;
51
+ }[];
52
+ }
53
+ /** The part of `RunViewResult` a link needs. `RunViewResult<Record<string, unknown>>` satisfies this. */
54
+ export interface RelatedLinkReadResult {
55
+ Success: boolean;
56
+ Results?: Record<string, unknown>[];
57
+ }
58
+ /** Reads one row for a link. The component supplies a provider-scoped `RunView`. */
59
+ export type RelatedLinkReader = (params: {
60
+ EntityName: string;
61
+ Fields: string[];
62
+ ExtraFilter: string;
63
+ MaxRows: number;
64
+ }) => Promise<RelatedLinkReadResult>;
65
+ /** A link that resolved to something openable. Anything that did not resolve is absent, not blank. */
66
+ export interface ResolvedRelatedChip {
67
+ Key: string;
68
+ /** What the relationship is: "Source Deal", "Order". */
69
+ Label: string;
70
+ /** The linked record's name. Empty ONLY when the record exists but could not be read — see below. */
71
+ Name: string;
72
+ Icon: string | null;
73
+ EntityName: string;
74
+ PrimaryKeyField: string;
75
+ RecordID: string;
76
+ /** Accessible name for the chip's button, composed once here so the template stays declarative. */
77
+ AriaLabel: string;
78
+ }
79
+ /**
80
+ * The filter that selects the linked record, or `null` when the link names nothing to select.
81
+ *
82
+ * A `RecordID` is preferred over a `Filter` when both are given: the caller holding the id is the
83
+ * more direct statement of the same fact.
84
+ */
85
+ export declare function FilterForRelatedLink(link: BizAppsRelatedLink, entity: RelatedLinkEntity): string | null;
86
+ /** The entity's primary key column, defaulting to `ID` as every other link in these apps does. */
87
+ export declare function PrimaryKeyFieldFor(entity: RelatedLinkEntity): string;
88
+ /**
89
+ * The chip's label: what the caller called it, else `<prefix> <entity>`, else the entity's own name.
90
+ *
91
+ * `BaseTableDisplayName` rather than `DisplayName` because a chip labels ONE record and the entity
92
+ * name is plural — it is what turns a Deals link into "Source Deal" without guessing at plurals.
93
+ */
94
+ export declare function LabelForRelatedLink(link: BizAppsRelatedLink, entity: RelatedLinkEntity): string;
95
+ /**
96
+ * Resolve one link to a chip, or to `null` for "show nothing".
97
+ *
98
+ * ## The two rules this function exists to hold
99
+ *
100
+ * **A CHIP NEVER SHOWS A RAW ID.** The whole point of the row is that a reader recognises what they
101
+ * are about to open. So the name is read from the entity's own name field, and an entity with no
102
+ * name field produces no chip rather than a GUID wearing a label.
103
+ *
104
+ * **A CHIP THAT CANNOT NAVIGATE IS NOT RENDERED.** A link that goes nowhere is worse than an absent
105
+ * one: it invites a click and spends the reader's trust. Five ways a link produces nothing — the
106
+ * entity is not in the catalog, the entity has no name field, the link names neither a record nor a
107
+ * filter, the read succeeded while matching zero rows, and the read was refused.
108
+ *
109
+ * ## Why a read that THREW is treated differently from one that FAILED or found nothing
110
+ *
111
+ * Three different facts, and the line between them is whether the server answered.
112
+ *
113
+ * **Zero rows from a successful read** means the record is not there — `bizapps-contracts` hit
114
+ * exactly this with CTR-000026, whose hand-typed provenance pair names a row that does not exist,
115
+ * and whose header rendered an "Open" button that navigated nowhere. No chip.
116
+ *
117
+ * **`Success: false`** is the server answering and refusing. In MJ that is the channel for a
118
+ * permission denial as much as for a bad filter: `GraphQLDataProvider.InternalRunView` throws when
119
+ * the transport fails and returns `Success: false` with an `ErrorMessage` when the request reached
120
+ * the server and was turned down. A reader who may not read Orders would otherwise get an
121
+ * "Order · Open" chip that navigates to a record that will not open — the dead link this component
122
+ * exists to prevent. So a refusal produces NO chip.
123
+ *
124
+ * **A thrown read** means we do not know: the record may well exist and simply be unreachable this
125
+ * moment. So a throw keeps the chip when we already hold the id to open — labelled, with "Open"
126
+ * where the name would go — and drops it for a reverse link, where the throw also cost us the id.
127
+ */
128
+ export declare function ResolveRelatedChip(link: BizAppsRelatedLink, entities: RelatedLinkEntity[], read: RelatedLinkReader): Promise<ResolvedRelatedChip | null>;
129
+ /** The part of a `MouseEvent` that decides where a chip opens. `MouseEvent` satisfies this. */
130
+ export interface RelatedChipClick {
131
+ ctrlKey: boolean;
132
+ metaKey: boolean;
133
+ }
134
+ /**
135
+ * The navigation event a chip click produces.
136
+ *
137
+ * Ctrl (Windows/Linux) and Cmd (macOS) both mean "new tab", which is the idiom MJ uses everywhere a
138
+ * record link is clicked.
139
+ *
140
+ * `OpenInNewTab` is OMITTED rather than set to `false` on a plain click, and that is the whole of
141
+ * what makes shift-click work. `NavigationService.shouldForceNewTab` returns `options.forceNewTab`
142
+ * whenever it is `!== undefined` and only otherwise consults its global shift-key state, and
143
+ * Explorer passes `forceNewTab: event.OpenInNewTab` straight through. An explicit `false` therefore
144
+ * does not mean "no opinion" — it means "same tab", and it suppresses the shift detection outright.
145
+ *
146
+ * `CompositeKey.FromKeyValuePair` rather than `FromID`: the latter assumes the target's primary key
147
+ * is literally called `ID`, which is true of these apps today and is not a thing a shared component
148
+ * gets to assume.
149
+ */
150
+ export declare function RelatedChipNavigation(chip: ResolvedRelatedChip, event: RelatedChipClick): RecordNavigationEvent;
151
+ //# sourceMappingURL=related-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"related-links.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/related-chips/related-links.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAC/B,kGAAkG;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACnC;AAED,yGAAyG;AACzG,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACvC;AAED,oFAAoF;AACpF,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAErC,sGAAsG;AACtG,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,qGAAqG;IACrG,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,SAAS,EAAE,MAAM,CAAC;CACrB;AAYD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAKvG;AAED,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAQ/F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,kBAAkB,CACpC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,IAAI,EAAE,iBAAiB,GACxB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA4CrC;AAmCD,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,gBAAgB,GAAG,qBAAqB,CAU/G"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * @fileoverview The resolve-and-hide rules behind `bizapps-related-chips`, kept out of the component.
3
+ *
4
+ * WHY THIS IS NOT IN THE COMPONENT. Everything here is a decision about whether a chip may be shown
5
+ * at all — "is the app installed", "does the record still exist", "did the read fail or did it
6
+ * succeed and find nothing" — and those are exactly the things that must be pinned by tests. A rule
7
+ * declared inside an Angular component cannot be exercised without standing up DI, which this
8
+ * package's node-environment vitest setup deliberately does not do. Same split as
9
+ * `bizapps-contracts`' `source-record-candidates.ts`.
10
+ *
11
+ * The dependencies below are narrowed to the shape each function actually reads rather than taking
12
+ * `IMetadataProvider` / `RunView`. `EntityInfo[]` and `RunViewResult` satisfy them structurally, so
13
+ * the component passes the real objects while a test passes a literal.
14
+ *
15
+ * @module @mj-biz-apps/common-ng
16
+ */
17
+ import { CompositeKey } from '@memberjunction/core';
18
+ /** Single-quote escaping for a value going into an `ExtraFilter`. */
19
+ function quote(value) {
20
+ return value.replace(/'/g, "''");
21
+ }
22
+ /** `true` for a value that actually names a record — not null, not undefined, not blank. */
23
+ function isPresent(value) {
24
+ return value !== null && value !== undefined && String(value).trim().length > 0;
25
+ }
26
+ /**
27
+ * The filter that selects the linked record, or `null` when the link names nothing to select.
28
+ *
29
+ * A `RecordID` is preferred over a `Filter` when both are given: the caller holding the id is the
30
+ * more direct statement of the same fact.
31
+ */
32
+ export function FilterForRelatedLink(link, entity) {
33
+ if (isPresent(link.RecordID)) {
34
+ return `${PrimaryKeyFieldFor(entity)} = '${quote(String(link.RecordID).trim())}'`;
35
+ }
36
+ return isPresent(link.Filter) ? link.Filter.trim() : null;
37
+ }
38
+ /** The entity's primary key column, defaulting to `ID` as every other link in these apps does. */
39
+ export function PrimaryKeyFieldFor(entity) {
40
+ return entity.PrimaryKeys?.[0]?.Name ?? 'ID';
41
+ }
42
+ /**
43
+ * The chip's label: what the caller called it, else `<prefix> <entity>`, else the entity's own name.
44
+ *
45
+ * `BaseTableDisplayName` rather than `DisplayName` because a chip labels ONE record and the entity
46
+ * name is plural — it is what turns a Deals link into "Source Deal" without guessing at plurals.
47
+ */
48
+ export function LabelForRelatedLink(link, entity) {
49
+ if (isPresent(link.Label)) {
50
+ return link.Label.trim();
51
+ }
52
+ if (isPresent(link.LabelPrefix)) {
53
+ return `${link.LabelPrefix.trim()} ${entity.BaseTableDisplayName}`;
54
+ }
55
+ return entity.BaseTableDisplayName;
56
+ }
57
+ /**
58
+ * Resolve one link to a chip, or to `null` for "show nothing".
59
+ *
60
+ * ## The two rules this function exists to hold
61
+ *
62
+ * **A CHIP NEVER SHOWS A RAW ID.** The whole point of the row is that a reader recognises what they
63
+ * are about to open. So the name is read from the entity's own name field, and an entity with no
64
+ * name field produces no chip rather than a GUID wearing a label.
65
+ *
66
+ * **A CHIP THAT CANNOT NAVIGATE IS NOT RENDERED.** A link that goes nowhere is worse than an absent
67
+ * one: it invites a click and spends the reader's trust. Five ways a link produces nothing — the
68
+ * entity is not in the catalog, the entity has no name field, the link names neither a record nor a
69
+ * filter, the read succeeded while matching zero rows, and the read was refused.
70
+ *
71
+ * ## Why a read that THREW is treated differently from one that FAILED or found nothing
72
+ *
73
+ * Three different facts, and the line between them is whether the server answered.
74
+ *
75
+ * **Zero rows from a successful read** means the record is not there — `bizapps-contracts` hit
76
+ * exactly this with CTR-000026, whose hand-typed provenance pair names a row that does not exist,
77
+ * and whose header rendered an "Open" button that navigated nowhere. No chip.
78
+ *
79
+ * **`Success: false`** is the server answering and refusing. In MJ that is the channel for a
80
+ * permission denial as much as for a bad filter: `GraphQLDataProvider.InternalRunView` throws when
81
+ * the transport fails and returns `Success: false` with an `ErrorMessage` when the request reached
82
+ * the server and was turned down. A reader who may not read Orders would otherwise get an
83
+ * "Order · Open" chip that navigates to a record that will not open — the dead link this component
84
+ * exists to prevent. So a refusal produces NO chip.
85
+ *
86
+ * **A thrown read** means we do not know: the record may well exist and simply be unreachable this
87
+ * moment. So a throw keeps the chip when we already hold the id to open — labelled, with "Open"
88
+ * where the name would go — and drops it for a reverse link, where the throw also cost us the id.
89
+ */
90
+ export async function ResolveRelatedChip(link, entities, read) {
91
+ const entity = entities?.find((e) => e.Name === link.EntityName) ?? null;
92
+ if (!entity) {
93
+ return null;
94
+ }
95
+ const nameField = entity.NameField?.Name;
96
+ if (!isPresent(nameField)) {
97
+ return null;
98
+ }
99
+ const filter = FilterForRelatedLink(link, entity);
100
+ if (!filter) {
101
+ return null;
102
+ }
103
+ const pkField = PrimaryKeyFieldFor(entity);
104
+ const label = LabelForRelatedLink(link, entity);
105
+ try {
106
+ const result = await read({
107
+ EntityName: entity.Name,
108
+ Fields: [pkField, nameField],
109
+ ExtraFilter: filter,
110
+ MaxRows: 1,
111
+ });
112
+ if (result?.Success === false) {
113
+ return null;
114
+ }
115
+ const row = result?.Success ? result.Results?.[0] : undefined;
116
+ if (result?.Success && !row) {
117
+ return null;
118
+ }
119
+ if (!row) {
120
+ return unreadableChip(link, entity, label, pkField);
121
+ }
122
+ const recordID = String(row[pkField] ?? link.RecordID ?? '');
123
+ if (!isPresent(recordID)) {
124
+ return null;
125
+ }
126
+ return chip(link, entity, label, pkField, recordID, String(row[nameField] ?? ''));
127
+ }
128
+ catch {
129
+ return unreadableChip(link, entity, label, pkField);
130
+ }
131
+ }
132
+ /**
133
+ * The chip for a record we could not read but can still open — only possible when the link carried
134
+ * the id itself. A reverse link has nothing left to open, so it renders nothing.
135
+ */
136
+ function unreadableChip(link, entity, label, pkField) {
137
+ return isPresent(link.RecordID) ? chip(link, entity, label, pkField, String(link.RecordID).trim(), '') : null;
138
+ }
139
+ function chip(link, entity, label, pkField, recordID, name) {
140
+ return {
141
+ Key: link.Key,
142
+ Label: label,
143
+ Name: name,
144
+ Icon: link.Icon ?? null,
145
+ EntityName: entity.Name,
146
+ PrimaryKeyField: pkField,
147
+ RecordID: recordID,
148
+ AriaLabel: name ? `Open ${label} ${name}` : `Open ${label}`,
149
+ };
150
+ }
151
+ /**
152
+ * The navigation event a chip click produces.
153
+ *
154
+ * Ctrl (Windows/Linux) and Cmd (macOS) both mean "new tab", which is the idiom MJ uses everywhere a
155
+ * record link is clicked.
156
+ *
157
+ * `OpenInNewTab` is OMITTED rather than set to `false` on a plain click, and that is the whole of
158
+ * what makes shift-click work. `NavigationService.shouldForceNewTab` returns `options.forceNewTab`
159
+ * whenever it is `!== undefined` and only otherwise consults its global shift-key state, and
160
+ * Explorer passes `forceNewTab: event.OpenInNewTab` straight through. An explicit `false` therefore
161
+ * does not mean "no opinion" — it means "same tab", and it suppresses the shift detection outright.
162
+ *
163
+ * `CompositeKey.FromKeyValuePair` rather than `FromID`: the latter assumes the target's primary key
164
+ * is literally called `ID`, which is true of these apps today and is not a thing a shared component
165
+ * gets to assume.
166
+ */
167
+ export function RelatedChipNavigation(chip, event) {
168
+ const navigation = {
169
+ Kind: 'record',
170
+ EntityName: chip.EntityName,
171
+ PrimaryKey: CompositeKey.FromKeyValuePair(chip.PrimaryKeyField, chip.RecordID),
172
+ };
173
+ if (event.ctrlKey || event.metaKey) {
174
+ navigation.OpenInNewTab = true;
175
+ }
176
+ return navigation;
177
+ }
178
+ //# sourceMappingURL=related-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"related-links.js","sourceRoot":"","sources":["../../../../src/lib/components/related-chips/related-links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=directory-headline.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-headline.test.d.ts","sourceRoot":"","sources":["../../../../src/lib/data/__tests__/directory-headline.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { BuildDirectoryHeadline, DIRECTORY_HEADLINE_UNREADABLE } from '../directory-stats';
3
+ /**
4
+ * These pin the one rule the directory dashboard cannot get wrong: a count nobody could read is NOT
5
+ * zero. `LoadDirectoryDashboardSummary` returns `null` when the query fails or comes back empty, and
6
+ * the headline it produces must reach the tiles as nulls — which render an em dash — with the row's
7
+ * error line set, never as four zeros claiming an empty party file.
8
+ */
9
+ function queue(count, label = `queue-${count}`) {
10
+ return { Label: label, Count: count, Icon: 'fa-solid fa-flag', Tone: 'warning', PageId: 'people' };
11
+ }
12
+ function summary(partial = {}) {
13
+ return {
14
+ ActivePeopleCount: 120,
15
+ TotalPeopleCount: 120,
16
+ ActiveOrganizationCount: 30,
17
+ TotalOrganizationCount: 30,
18
+ RelationshipCount: 88,
19
+ Queues: [],
20
+ ...partial,
21
+ };
22
+ }
23
+ describe('BuildDirectoryHeadline', () => {
24
+ describe('a failed read', () => {
25
+ it('leaves every count null rather than zero — zero is a claim the directory is empty', () => {
26
+ const headline = BuildDirectoryHeadline(null);
27
+ expect(headline.ActivePeopleCount).toBeNull();
28
+ expect(headline.ActiveOrganizationCount).toBeNull();
29
+ expect(headline.RelationshipCount).toBeNull();
30
+ expect(headline.GapCount).toBeNull();
31
+ });
32
+ it('says so once, on the row', () => {
33
+ expect(BuildDirectoryHeadline(null).Error).toBe(DIRECTORY_HEADLINE_UNREADABLE);
34
+ });
35
+ it('flags the read as failed, so no section reports itself empty', () => {
36
+ expect(BuildDirectoryHeadline(null).ReadFailed).toBe(true);
37
+ });
38
+ it('drops the footnotes, which have no count left to qualify', () => {
39
+ const headline = BuildDirectoryHeadline(null);
40
+ expect(headline.PeopleDetail).toBeNull();
41
+ expect(headline.OrganizationDetail).toBeNull();
42
+ });
43
+ it('treats undefined the same as null, the shape an unset property arrives as', () => {
44
+ expect(BuildDirectoryHeadline(undefined).ActivePeopleCount).toBeNull();
45
+ expect(BuildDirectoryHeadline(undefined).Error).toBe(DIRECTORY_HEADLINE_UNREADABLE);
46
+ });
47
+ });
48
+ describe('a successful read', () => {
49
+ it('carries the counts through and reports no error', () => {
50
+ const headline = BuildDirectoryHeadline(summary());
51
+ expect(headline.ActivePeopleCount).toBe(120);
52
+ expect(headline.ActiveOrganizationCount).toBe(30);
53
+ expect(headline.RelationshipCount).toBe(88);
54
+ expect(headline.Error).toBeNull();
55
+ expect(headline.ReadFailed).toBe(false);
56
+ });
57
+ it('leaves ReadFailed false for a genuinely empty directory, so the sections still read empty', () => {
58
+ const headline = BuildDirectoryHeadline(summary({ ActivePeopleCount: 0, TotalPeopleCount: 0, ActiveOrganizationCount: 0, TotalOrganizationCount: 0, RelationshipCount: 0 }));
59
+ expect(headline.ReadFailed).toBe(false);
60
+ });
61
+ it('keeps a real zero as zero — nothing on file is a legitimate answer, unlike an unread count', () => {
62
+ const headline = BuildDirectoryHeadline(summary({ ActivePeopleCount: 0, TotalPeopleCount: 0, RelationshipCount: 0 }));
63
+ expect(headline.ActivePeopleCount).toBe(0);
64
+ expect(headline.RelationshipCount).toBe(0);
65
+ expect(headline.GapCount).toBe(0);
66
+ expect(headline.Error).toBeNull();
67
+ });
68
+ it('sums the queues into the gap count', () => {
69
+ const headline = BuildDirectoryHeadline(summary({ Queues: [queue(3), queue(4), queue(10)] }));
70
+ expect(headline.GapCount).toBe(17);
71
+ });
72
+ });
73
+ describe('the gap tone', () => {
74
+ it('warns on gaps that were actually counted', () => {
75
+ expect(BuildDirectoryHeadline(summary({ Queues: [queue(1)] })).GapTone).toBe('warn');
76
+ });
77
+ it('stays quiet when the count read as zero', () => {
78
+ expect(BuildDirectoryHeadline(summary({ Queues: [] })).GapTone).toBe('none');
79
+ });
80
+ it('stays quiet on an unread count — "could not check" is not "something to fix"', () => {
81
+ expect(BuildDirectoryHeadline(null).GapTone).toBe('none');
82
+ });
83
+ });
84
+ describe('the footnotes', () => {
85
+ it('reads "everyone on file" when active equals total', () => {
86
+ const headline = BuildDirectoryHeadline(summary({ ActivePeopleCount: 120, TotalPeopleCount: 120 }));
87
+ expect(headline.PeopleDetail).toBe('Everyone currently on file');
88
+ expect(headline.OrganizationDetail).toBe('Active organizations');
89
+ });
90
+ it('names the total when inactive records exist', () => {
91
+ const headline = BuildDirectoryHeadline(summary({
92
+ ActivePeopleCount: 120,
93
+ TotalPeopleCount: 145,
94
+ ActiveOrganizationCount: 30,
95
+ TotalOrganizationCount: 41,
96
+ }));
97
+ expect(headline.PeopleDetail).toBe('145 total, including inactive');
98
+ expect(headline.OrganizationDetail).toBe('41 total, including inactive');
99
+ });
100
+ });
101
+ });
102
+ //# sourceMappingURL=directory-headline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-headline.test.js","sourceRoot":"","sources":["../../../../src/lib/data/__tests__/directory-headline.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { DirectoryAttentionItem, DirectoryBarRow, DirectoryDayBar, DirectoryOrganizationRow, DirectoryPersonRow, DirectoryQueue, DirectoryRelationshipRow } from './directory-types';
1
+ import type { DirectoryAttentionItem, DirectoryBarRow, DirectoryDayBar, DirectoryHeadline, DirectoryOrganizationRow, DirectoryPersonRow, DirectoryQueue, DirectoryRelationshipRow } from './directory-types';
2
2
  export declare function PersonEmail(person: DirectoryPersonRow): string | null;
3
3
  export declare function PersonPhone(person: DirectoryPersonRow): string | null;
4
4
  export declare function LocalDayKey(value: Date | string): string;
@@ -28,4 +28,26 @@ export declare function EscapeFilterValue(value: string): string;
28
28
  * literal character instead of widening the match.
29
29
  */
30
30
  export declare function EscapeLikeValue(value: string): string;
31
+ /**
32
+ * The summary fields {@link BuildDirectoryHeadline} reads. Declared structurally so this module stays
33
+ * free of the query layer — `DirectoryDashboardSummary` in `directory-queries.ts` satisfies it.
34
+ */
35
+ export interface DirectorySummaryCounts {
36
+ ActivePeopleCount: number;
37
+ TotalPeopleCount: number;
38
+ ActiveOrganizationCount: number;
39
+ TotalOrganizationCount: number;
40
+ RelationshipCount: number;
41
+ Queues: readonly DirectoryQueue[];
42
+ }
43
+ /** What the row says when the summary query did not return. Muted, not red — see `StatRowComponent`. */
44
+ export declare const DIRECTORY_HEADLINE_UNREADABLE = "The directory counts could not be read just now.";
45
+ /**
46
+ * Turn one summary read into the four headline tiles.
47
+ *
48
+ * A `null` summary is the failed read, and every count comes back `null` so each tile shows an em
49
+ * dash and the row carries the sentence. It is deliberately all-or-nothing: the counts come from a
50
+ * single query, so there is no state in which some of them are known.
51
+ */
52
+ export declare function BuildDirectoryHeadline(summary: DirectorySummaryCounts | null | undefined): DirectoryHeadline;
31
53
  //# sourceMappingURL=directory-stats.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"directory-stats.d.ts","sourceRoot":"","sources":["../../../src/lib/data/directory-stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAErE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAErE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAOxD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAExF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAEzG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAE9F;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAErG;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAE9G;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAEjH;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS;IAAE,cAAc,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,EAAE,EAAE,IAAI,SAAI,GAAG,eAAe,EAAE,CAc1G;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,eAAe,EAAE,CASlF;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,cAAc,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,SAAI,GAAG,CAAC,EAAE,CAI9G;AAED,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAC1C,cAAc,EAAE,CAoClB;AAED,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAC1C,sBAAsB,EAAE,CA6B1B;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CAIvE;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD"}
1
+ {"version":3,"file":"directory-stats.d.ts","sourceRoot":"","sources":["../../../src/lib/data/directory-stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EAC3B,MAAM,mBAAmB,CAAC;AAE3B,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAErE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAErE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAOxD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAExF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAEzG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAE9F;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAErG;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAE9G;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAAG,wBAAwB,EAAE,CAEjH;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS;IAAE,cAAc,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,EAAE,EAAE,IAAI,SAAI,GAAG,eAAe,EAAE,CAc1G;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,eAAe,EAAE,CASlF;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,cAAc,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,SAAI,GAAG,CAAC,EAAE,CAI9G;AAED,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAC1C,cAAc,EAAE,CAoClB;AAED,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,IAAI,EAAE,SAAS,wBAAwB,EAAE,GAC1C,sBAAsB,EAAE,CA6B1B;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,CAIvE;AAED,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;CACrC;AAED,wGAAwG;AACxG,eAAO,MAAM,6BAA6B,qDAAqD,CAAC;AAEhG;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,GAAG,SAAS,GAAG,iBAAiB,CAgC5G"}
@@ -146,4 +146,44 @@ export function EscapeLikeValue(value) {
146
146
  .replace(/%/g, '[%]')
147
147
  .replace(/_/g, '[_]');
148
148
  }
149
+ /** What the row says when the summary query did not return. Muted, not red — see `StatRowComponent`. */
150
+ export const DIRECTORY_HEADLINE_UNREADABLE = 'The directory counts could not be read just now.';
151
+ /**
152
+ * Turn one summary read into the four headline tiles.
153
+ *
154
+ * A `null` summary is the failed read, and every count comes back `null` so each tile shows an em
155
+ * dash and the row carries the sentence. It is deliberately all-or-nothing: the counts come from a
156
+ * single query, so there is no state in which some of them are known.
157
+ */
158
+ export function BuildDirectoryHeadline(summary) {
159
+ if (!summary) {
160
+ return {
161
+ ReadFailed: true,
162
+ ActivePeopleCount: null,
163
+ ActiveOrganizationCount: null,
164
+ RelationshipCount: null,
165
+ GapCount: null,
166
+ GapTone: 'none',
167
+ PeopleDetail: null,
168
+ OrganizationDetail: null,
169
+ Error: DIRECTORY_HEADLINE_UNREADABLE,
170
+ };
171
+ }
172
+ const gapCount = summary.Queues.reduce((sum, queue) => sum + queue.Count, 0);
173
+ return {
174
+ ReadFailed: false,
175
+ ActivePeopleCount: summary.ActivePeopleCount,
176
+ ActiveOrganizationCount: summary.ActiveOrganizationCount,
177
+ RelationshipCount: summary.RelationshipCount,
178
+ GapCount: gapCount,
179
+ GapTone: gapCount > 0 ? 'warn' : 'none',
180
+ PeopleDetail: summary.TotalPeopleCount === summary.ActivePeopleCount
181
+ ? 'Everyone currently on file'
182
+ : `${summary.TotalPeopleCount} total, including inactive`,
183
+ OrganizationDetail: summary.TotalOrganizationCount === summary.ActiveOrganizationCount
184
+ ? 'Active organizations'
185
+ : `${summary.TotalOrganizationCount} total, including inactive`,
186
+ Error: null,
187
+ };
188
+ }
149
189
  //# sourceMappingURL=directory-stats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"directory-stats.js","sourceRoot":"","sources":["../../../src/lib/data/directory-stats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"directory-stats.js","sourceRoot":"","sources":["../../../src/lib/data/directory-stats.ts"],"names":[],"mappings":"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"}
@@ -30,4 +30,38 @@ export interface DirectoryAttentionItem {
30
30
  Headline: string;
31
31
  Detail: string;
32
32
  }
33
+ /**
34
+ * The four headline counts of the directory dashboard, in the shape `bizapps-stat-tile` takes them.
35
+ *
36
+ * The counts are `number | null` rather than `number` on purpose. They all come from one query, so
37
+ * they are one atomic read: either every number is true or none of them is. `null` is the tile's
38
+ * "could not be read" value and renders an em dash; `0` is a real answer and renders "0". Defaulting
39
+ * an unread count to `0` tells the reader the directory is empty when it is only unreadable, which is
40
+ * the one thing a dashboard must not say.
41
+ */
42
+ export interface DirectoryHeadline {
43
+ /**
44
+ * True when the summary query did not return. Every section fed by that one read consults this
45
+ * before it reports itself empty: a list that is empty because nothing was read is not "nothing
46
+ * to do", and a green check over an unread directory is the same lie as a zero count.
47
+ */
48
+ ReadFailed: boolean;
49
+ ActivePeopleCount: number | null;
50
+ ActiveOrganizationCount: number | null;
51
+ RelationshipCount: number | null;
52
+ GapCount: number | null;
53
+ /**
54
+ * How the gap count should read. `warn` only on a gap count that was actually read and is above
55
+ * zero: an unknown count is an em dash, and colouring it amber would turn "we could not check"
56
+ * into "there is something to fix". Matches `StatTileTone`, kept as a literal union so the data
57
+ * layer does not depend on the component layer.
58
+ */
59
+ GapTone: 'none' | 'warn';
60
+ /** Footnote under the people count, or `null` when there is no count to qualify. */
61
+ PeopleDetail: string | null;
62
+ /** Footnote under the organization count, or `null` when there is no count to qualify. */
63
+ OrganizationDetail: string | null;
64
+ /** One sentence for `bizapps-stat-row`'s error line, or `null` when everything read. */
65
+ Error: string | null;
66
+ }
33
67
  //# sourceMappingURL=directory-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"directory-types.d.ts","sourceRoot":"","sources":["../../../src/lib/data/directory-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iCAAiC,EAAE,2BAA2B,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEtJ,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACjC,2BAA2B,EACzB,IAAI,GACJ,aAAa,GACb,WAAW,GACX,UAAU,GACV,OAAO,GACP,cAAc,GACd,OAAO,GACP,cAAc,GACd,QAAQ,GACR,OAAO,GACP,yBAAyB,GACzB,uBAAuB,GACvB,oBAAoB,GACpB,gBAAgB,CACrB,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACvC,iCAAiC,EAC/B,IAAI,GACJ,MAAM,GACN,WAAW,GACX,QAAQ,GACR,kBAAkB,GAClB,oBAAoB,GACpB,SAAS,GACT,OAAO,GACP,OAAO,GACP,QAAQ,GACR,oBAAoB,GACpB,gBAAgB,CACrB,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACvC,iCAAiC,EAC/B,IAAI,GACJ,kBAAkB,GAClB,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,kBAAkB,GAClB,UAAU,GACV,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,oBAAoB,GACpB,kBAAkB,GAClB,gBAAgB,CACrB,CAAC;AAEF,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"directory-types.d.ts","sourceRoot":"","sources":["../../../src/lib/data/directory-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iCAAiC,EAAE,2BAA2B,EAAE,iCAAiC,EAAE,MAAM,8BAA8B,CAAC;AAEtJ,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACjC,2BAA2B,EACzB,IAAI,GACJ,aAAa,GACb,WAAW,GACX,UAAU,GACV,OAAO,GACP,cAAc,GACd,OAAO,GACP,cAAc,GACd,QAAQ,GACR,OAAO,GACP,yBAAyB,GACzB,uBAAuB,GACvB,oBAAoB,GACpB,gBAAgB,CACrB,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACvC,iCAAiC,EAC/B,IAAI,GACJ,MAAM,GACN,WAAW,GACX,QAAQ,GACR,kBAAkB,GAClB,oBAAoB,GACpB,SAAS,GACT,OAAO,GACP,OAAO,GACP,QAAQ,GACR,oBAAoB,GACpB,gBAAgB,CACrB,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACvC,iCAAiC,EAC/B,IAAI,GACJ,kBAAkB,GAClB,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,kBAAkB,GAClB,UAAU,GACV,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,oBAAoB,GACpB,kBAAkB,GAClB,gBAAgB,CACrB,CAAC;AAEF,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAC9B;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,oFAAoF;IACpF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0FAA0F;IAC1F,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,wFAAwF;IACxF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB"}