@myrmidon/cadmus-thesaurus-store 0.0.1

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.
@@ -0,0 +1,395 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnInit, OnDestroy, Type } from '@angular/core';
3
+ import { FormControl, FormGroup, FormBuilder } from '@angular/forms';
4
+ import { Observable } from 'rxjs';
5
+ import { TreeNodeFilter, PagedTreeNode, PagedTreeStoreService, EditablePagedTreeStoreServiceBase, TreeNode, ChangeOperation, PagedTreeStore, PageChangeRequest } from '@myrmidon/paged-data-browsers';
6
+ import { DataPage } from '@myrmidon/ngx-tools';
7
+ import { ThesaurusEntry } from '@myrmidon/cadmus-core';
8
+ import { CdkDragDrop } from '@angular/cdk/drag-drop';
9
+ import { MatDialogConfig, MatDialogRef } from '@angular/material/dialog';
10
+
11
+ /**
12
+ * The filter for thesaurus entry nodes. The only filtered property is
13
+ * the node's label.
14
+ */
15
+ interface ThesaurusEntryNodeFilter extends TreeNodeFilter {
16
+ label?: string;
17
+ }
18
+ /**
19
+ * The tree node for thesaurus entries in a paging tree node.
20
+ */
21
+ interface ThesaurusEntryPagedTreeNode extends PagedTreeNode<ThesaurusEntryNodeFilter> {
22
+ key: string;
23
+ value: string;
24
+ }
25
+ /**
26
+ * A label rendering function which removes from a label
27
+ * all the characters past the last colon, trimming the result.
28
+ * This is a typical rendering when dealing with hierarchical
29
+ * thesaurus entries, e.g. "furniture: table: color", where
30
+ * we can shorten the label to just "color", as "furniture"
31
+ * and "table" are its ancestors.
32
+ */
33
+ declare function renderLabelFromLastColon(label: string): string;
34
+ /**
35
+ * A static paged tree store service for thesaurus entries.
36
+ * This builds tree nodes from all the thesaurus entries from a specific
37
+ * thesaurus, assuming that entry IDs are hierarchical and
38
+ * separated by dots (.).
39
+ * Nodes are received all at once for a thesaurus, so this is essentially
40
+ * an adapter to the paged tree store service interface.
41
+ * The entries are a flat list where hierarchy is implied by the IDs:
42
+ * for instance, "animal.mammal.dog" is a child of "animal.mammal"
43
+ * which is a child of "animal". Numeric IDs are added to each node
44
+ * based on the order of entries to ensure stable IDs.
45
+ * The label of each node can be rendered as-is from the entry value,
46
+ * or a custom rendering function can be provided to the constructor.
47
+ */
48
+ declare class StaticThesaurusPagedTreeStoreService implements PagedTreeStoreService<ThesaurusEntryNodeFilter> {
49
+ private _renderLabel?;
50
+ private _nodes;
51
+ private _built;
52
+ private readonly _entries;
53
+ /**
54
+ * Constructor.
55
+ * @param entries The thesaurus entries.
56
+ * @param _renderLabel An optional function to render the label
57
+ * of each node.
58
+ */
59
+ constructor(entries: ThesaurusEntry[], _renderLabel?: ((label: string) => string) | undefined);
60
+ /**
61
+ * Ensure that nodes have been built from entries.
62
+ */
63
+ private ensureNodes;
64
+ /**
65
+ * Get the specified page of nodes.
66
+ * @param filter The filter.
67
+ * @param pageNumber The page number.
68
+ * @param pageSize The page size.
69
+ * @param hasMockRoot Whether the root node is a mock node. Not used here.
70
+ */
71
+ getNodes(filter: ThesaurusEntryNodeFilter, pageNumber: number, pageSize: number, hasMockRoot?: boolean): Observable<DataPage<ThesaurusEntryPagedTreeNode>>;
72
+ }
73
+
74
+ /**
75
+ * Editable version of the static thesaurus paged tree store service.
76
+ * This service allows editing operations on the flat ThesaurusEntry list
77
+ * while maintaining the tree structure implied by the hierarchical IDs.
78
+ */
79
+ declare class EditableStaticThesaurusPagedTreeStoreService extends EditablePagedTreeStoreServiceBase<ThesaurusEntryNodeFilter> {
80
+ private _entries;
81
+ private _staticService;
82
+ private _renderLabel?;
83
+ constructor(entries: ThesaurusEntry[], renderLabel?: (label: string) => string);
84
+ protected fetchNodes(filter: ThesaurusEntryNodeFilter, pageNumber: number, pageSize: number, hasMockRoot?: boolean): Observable<DataPage<TreeNode>>;
85
+ protected persistChanges(changes: ChangeOperation[]): Observable<Map<number, number>>;
86
+ /**
87
+ * Convert a TreeNode back to a ThesaurusEntry.
88
+ */
89
+ private nodeToEntry;
90
+ /**
91
+ * Remove an entry and all its descendants from the entries list.
92
+ */
93
+ private removeEntryAndDescendants;
94
+ /**
95
+ * Get current entries (for demonstration purposes).
96
+ */
97
+ getCurrentEntries(): ThesaurusEntry[];
98
+ }
99
+
100
+ /**
101
+ * An editable paged tree browser for thesaurus entries. Editing happens in memory
102
+ * and when complete, the changes can be committed to the underlying data store
103
+ * via the EditableStaticThesaurusPagedTreeStoreService.
104
+ */
105
+ declare class EditableThesaurusBrowserComponent implements OnInit, OnDestroy {
106
+ private _dialog;
107
+ private _snackBar;
108
+ private _dialogService;
109
+ private _sub?;
110
+ /**
111
+ * The editable service to use to load the nodes.
112
+ */
113
+ readonly service: _angular_core.InputSignal<EditableStaticThesaurusPagedTreeStoreService | undefined>;
114
+ /**
115
+ * True to show the tree root nodes filter.
116
+ */
117
+ readonly hasRootFilter: _angular_core.InputSignal<boolean>;
118
+ /**
119
+ * Emitted when a node is clicked.
120
+ */
121
+ readonly nodePick: _angular_core.OutputEmitterRef<ThesaurusEntryPagedTreeNode>;
122
+ /**
123
+ * Emitted when the changes state changes.
124
+ */
125
+ readonly changesStateChange: _angular_core.OutputEmitterRef<boolean>;
126
+ /**
127
+ * The store instance, built from the service.
128
+ */
129
+ readonly store: _angular_core.Signal<PagedTreeStore<ThesaurusEntryPagedTreeNode, ThesaurusEntryNodeFilter> | null>;
130
+ readonly loading: _angular_core.WritableSignal<boolean>;
131
+ readonly selectedNode: _angular_core.WritableSignal<ThesaurusEntryPagedTreeNode | null>;
132
+ debug: FormControl<boolean>;
133
+ hideLoc: FormControl<boolean>;
134
+ hideFilter: FormControl<boolean>;
135
+ filter$: Observable<Readonly<ThesaurusEntryNodeFilter>>;
136
+ nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>>;
137
+ label: FormControl<string | null>;
138
+ form: FormGroup<{
139
+ label: FormControl<string | null>;
140
+ }>;
141
+ ngOnInit(): void;
142
+ ngOnDestroy(): void;
143
+ reset(): void;
144
+ onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void;
145
+ onPageChangeRequest(request: PageChangeRequest): void;
146
+ onFilterChange(filter: ThesaurusEntryNodeFilter | null | undefined): void;
147
+ onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void;
148
+ expandAll(): void;
149
+ collapseAll(): void;
150
+ clear(): void;
151
+ onNodeClick(node: ThesaurusEntryPagedTreeNode): void;
152
+ findLabels(): void;
153
+ removeHilites(): void;
154
+ private editEntry;
155
+ addChild(): Promise<void>;
156
+ addSibling(): Promise<void>;
157
+ removeNode(): void;
158
+ editNode(): Promise<void>;
159
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditableThesaurusBrowserComponent, never>;
160
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EditableThesaurusBrowserComponent, "cadmus-editable-thesaurus-browser", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; "hasRootFilter": { "alias": "hasRootFilter"; "required": false; "isSignal": true; }; }, { "nodePick": "nodePick"; "changesStateChange": "changesStateChange"; }, never, never, true, never>;
161
+ }
162
+
163
+ /**
164
+ * The prefix added to custom entries' IDs.
165
+ */
166
+ declare const CUSTOM_ENTRY_PREFIX = "$";
167
+ /**
168
+ * A picker component for thesaurus entries.
169
+ * This component allows picking one or more entries from a given thesaurus.
170
+ * In its collapsed state, it shows the picked entries as chips; when
171
+ * expanded, it shows the thesaurus tree to pick from. Custom entries
172
+ * (not in the thesaurus) can be optionally allowed.
173
+ */
174
+ declare class ThesaurusEntriesPickerComponent {
175
+ /**
176
+ * The thesaurus entries to pick from (required).
177
+ */
178
+ readonly availableEntries: _angular_core.InputSignal<ThesaurusEntry[]>;
179
+ /**
180
+ * The picked entries.
181
+ */
182
+ readonly entries: _angular_core.ModelSignal<ThesaurusEntry[]>;
183
+ /**
184
+ * True to show the entries with labels shortened according to
185
+ * their hierarchy.
186
+ */
187
+ readonly hierarchicLabels: _angular_core.InputSignal<boolean>;
188
+ /**
189
+ * True to automatically sort the picked entries (disables drag-and-drop).
190
+ * When false, entries can be manually reordered via drag-and-drop.
191
+ */
192
+ readonly autoSort: _angular_core.InputSignal<boolean>;
193
+ /**
194
+ * True to allow custom values (not in the entries list).
195
+ */
196
+ readonly allowCustom: _angular_core.InputSignal<boolean>;
197
+ /**
198
+ * The minimum number of entries to pick.
199
+ */
200
+ readonly minEntries: _angular_core.InputSignal<number>;
201
+ /**
202
+ * The maximum number of entries to pick (0=unlimited).
203
+ */
204
+ readonly maxEntries: _angular_core.InputSignal<number>;
205
+ /**
206
+ * True when the picker is expanded (showing the entries list).
207
+ */
208
+ readonly expanded: _angular_core.ModelSignal<boolean>;
209
+ /**
210
+ * The message to show when there are no picked entries.
211
+ */
212
+ readonly emptyMessage: _angular_core.InputSignal<string>;
213
+ /**
214
+ * The number of remaining entries that can be picked (0=unlimited).
215
+ * This is displayed only if maxEntries > 1.
216
+ */
217
+ readonly remaining: _angular_core.Signal<number>;
218
+ id: FormControl<string>;
219
+ value: FormControl<string>;
220
+ form: FormGroup;
221
+ constructor(formBuilder: FormBuilder);
222
+ renderLabel: (label: string) => string;
223
+ private sortEntries;
224
+ onEntryChange(entry: ThesaurusEntry): void;
225
+ addCustomEntry(): void;
226
+ removeEntry(entry: ThesaurusEntry): void;
227
+ clear(): void;
228
+ onDrop(event: CdkDragDrop<ThesaurusEntry[]>): void;
229
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThesaurusEntriesPickerComponent, never>;
230
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThesaurusEntriesPickerComponent, "cadmus-thesaurus-entries-picker", never, { "availableEntries": { "alias": "availableEntries"; "required": true; "isSignal": true; }; "entries": { "alias": "entries"; "required": false; "isSignal": true; }; "hierarchicLabels": { "alias": "hierarchicLabels"; "required": false; "isSignal": true; }; "autoSort": { "alias": "autoSort"; "required": false; "isSignal": true; }; "allowCustom": { "alias": "allowCustom"; "required": false; "isSignal": true; }; "minEntries": { "alias": "minEntries"; "required": false; "isSignal": true; }; "maxEntries": { "alias": "maxEntries"; "required": false; "isSignal": true; }; "expanded": { "alias": "expanded"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; }, { "entries": "entriesChange"; "expanded": "expandedChange"; }, never, never, true, never>;
231
+ }
232
+
233
+ /**
234
+ * An edited thesaurus entry.
235
+ */
236
+ interface EditedThesEntry {
237
+ id: string;
238
+ value: string;
239
+ /**
240
+ * True if this entry belongs to a hierarchical thesaurus. When this is true,
241
+ * and parentId is set, the parentId field will be used as the prefix for the
242
+ * id field when creating a new entry.
243
+ */
244
+ hierarchical?: boolean;
245
+ /**
246
+ * The ID of the parent entry, if any.
247
+ */
248
+ parentId?: string;
249
+ /**
250
+ * If true, the id field is read-only. This is used when editing an existing
251
+ * entry so you cannot change its ID.
252
+ */
253
+ idLocked?: boolean;
254
+ /**
255
+ * Function used to check if the given ID exists. This is used when
256
+ * creating a new entry to ensure it does not duplicate an existing ID.
257
+ * @param id The ID to check.
258
+ * @returns True if exists.
259
+ */
260
+ idExists?: (id: string) => boolean;
261
+ }
262
+ interface PayloadMatDialogConfig<T> extends MatDialogConfig {
263
+ payload?: T;
264
+ }
265
+ /**
266
+ * A dialog component to edit a thesaurus entry.
267
+ */
268
+ declare class ThesEntryEditorComponent {
269
+ dialogRef: MatDialogRef<ThesEntryEditorComponent>;
270
+ data: PayloadMatDialogConfig<EditedThesEntry>;
271
+ readonly entry: _angular_core.ModelSignal<EditedThesEntry | undefined>;
272
+ wrapped: boolean;
273
+ id: FormControl<string>;
274
+ value: FormControl<string>;
275
+ form: FormGroup;
276
+ constructor(dialogRef: MatDialogRef<ThesEntryEditorComponent>, data: PayloadMatDialogConfig<EditedThesEntry>, formBuilder: FormBuilder);
277
+ cancel(): void;
278
+ save(): void;
279
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThesEntryEditorComponent, [{ optional: true; }, { optional: true; }, null]>;
280
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThesEntryEditorComponent, "cadmus-thesaurus-entry-editor", never, { "entry": { "alias": "entry"; "required": false; "isSignal": true; }; }, { "entry": "entryChange"; }, never, never, true, never>;
281
+ }
282
+
283
+ /**
284
+ * A readonly paged tree browser for thesaurus entries. This is a lower-level component
285
+ * used as an adapter between the generic paged tree browser and the thesaurus entries
286
+ * data model.
287
+ */
288
+ declare class ThesaurusBrowserComponent implements OnInit, OnDestroy {
289
+ private _dialog;
290
+ private _sub?;
291
+ /**
292
+ * The service to use to load the nodes.
293
+ */
294
+ readonly service: _angular_core.InputSignal<StaticThesaurusPagedTreeStoreService>;
295
+ /**
296
+ * Emitted when a node is clicked.
297
+ */
298
+ readonly nodePick: _angular_core.OutputEmitterRef<ThesaurusEntryPagedTreeNode>;
299
+ /**
300
+ * The store instance, built from the service.
301
+ */
302
+ readonly store: _angular_core.Signal<PagedTreeStore<ThesaurusEntryPagedTreeNode, ThesaurusEntryNodeFilter>>;
303
+ readonly loading: _angular_core.WritableSignal<boolean>;
304
+ debug: FormControl<boolean>;
305
+ hideLoc: FormControl<boolean>;
306
+ hideFilter: FormControl<boolean>;
307
+ filter$: Observable<Readonly<ThesaurusEntryNodeFilter>>;
308
+ nodes$: Observable<Readonly<ThesaurusEntryPagedTreeNode[]>>;
309
+ label: FormControl<string | null>;
310
+ form: FormGroup<{
311
+ label: FormControl<string | null>;
312
+ }>;
313
+ constructor();
314
+ ngOnInit(): void;
315
+ ngOnDestroy(): void;
316
+ reset(): void;
317
+ onToggleExpanded(node: ThesaurusEntryPagedTreeNode): void;
318
+ onPageChangeRequest(request: PageChangeRequest): void;
319
+ onFilterChange(filter: ThesaurusEntryNodeFilter | null | undefined): void;
320
+ onEditFilterRequest(node: ThesaurusEntryPagedTreeNode): void;
321
+ expandAll(): void;
322
+ collapseAll(): void;
323
+ clear(): void;
324
+ onNodeClick(node: ThesaurusEntryPagedTreeNode): void;
325
+ findLabels(): void;
326
+ removeHilites(): void;
327
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThesaurusBrowserComponent, never>;
328
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThesaurusBrowserComponent, "cadmus-thesaurus-browser", never, { "service": { "alias": "service"; "required": false; "isSignal": true; }; }, { "nodePick": "nodePick"; }, never, never, true, never>;
329
+ }
330
+
331
+ /**
332
+ * A filter to be used for thesaurus paged tree browsers.
333
+ */
334
+ declare class ThesaurusPagedTreeFilterComponent implements OnInit {
335
+ readonly dialogRef: MatDialogRef<ThesaurusPagedTreeFilterComponent, any> | null;
336
+ readonly data: any;
337
+ /**
338
+ * The filter.
339
+ */
340
+ readonly filter: _angular_core.ModelSignal<ThesaurusEntryNodeFilter | null | undefined>;
341
+ readonly wrapped: _angular_core.WritableSignal<boolean>;
342
+ label: FormControl<string | null>;
343
+ form: FormGroup;
344
+ constructor();
345
+ ngOnInit(): void;
346
+ private updateForm;
347
+ private getFilter;
348
+ reset(): void;
349
+ apply(): void;
350
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThesaurusPagedTreeFilterComponent, never>;
351
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThesaurusPagedTreeFilterComponent, "cadmus-thesaurus-paged-tree-filter", never, { "filter": { "alias": "filter"; "required": false; "isSignal": true; }; }, { "filter": "filterChange"; }, never, never, true, never>;
352
+ }
353
+
354
+ /**
355
+ * Thesaurus tree component.
356
+ * This component displays a set of hierarchical thesaurus entries
357
+ * in a tree, provided that each entry marks its hierarchy with
358
+ * dots. For instance, say you have the hierarchy "furniture" -
359
+ * "type" - "color". You might have an entry whose ID is
360
+ * "furniture.table.red", with a sibling "furniture.table.green",
361
+ * and a parent "furniture.table". This parent is there only to
362
+ * provide a label to the parent node, but only leaf nodes can be
363
+ * picked by the user. Whenever one is picked, the entryChange
364
+ * event is emitted.
365
+ */
366
+ declare class ThesaurusTreeComponent {
367
+ /**
368
+ * The thesaurus entries.
369
+ */
370
+ readonly entries: _angular_core.InputSignal<ThesaurusEntry[] | undefined>;
371
+ /**
372
+ * The optional node label rendering function. Note that even if you
373
+ * specify a label renderer function, the entryChange event always
374
+ * emits the original label.
375
+ */
376
+ readonly renderLabel: _angular_core.InputSignal<(label: string) => string>;
377
+ /**
378
+ * Fired when a thesaurus entry is selected.
379
+ */
380
+ readonly entryChange: _angular_core.OutputEmitterRef<ThesaurusEntry>;
381
+ /**
382
+ * The tree store service, dependent on the current entries and renderLabel.
383
+ */
384
+ readonly service: _angular_core.Signal<StaticThesaurusPagedTreeStoreService>;
385
+ /**
386
+ * The filter component class to use.
387
+ */
388
+ readonly filterComponent: Type<ThesaurusPagedTreeFilterComponent>;
389
+ onNodePick(node: ThesaurusEntryPagedTreeNode): void;
390
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThesaurusTreeComponent, never>;
391
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThesaurusTreeComponent, "cadmus-thesaurus-tree", never, { "entries": { "alias": "entries"; "required": false; "isSignal": true; }; "renderLabel": { "alias": "renderLabel"; "required": false; "isSignal": true; }; }, { "entryChange": "entryChange"; }, never, never, true, never>;
392
+ }
393
+
394
+ export { CUSTOM_ENTRY_PREFIX, EditableStaticThesaurusPagedTreeStoreService, EditableThesaurusBrowserComponent, StaticThesaurusPagedTreeStoreService, ThesEntryEditorComponent, ThesaurusBrowserComponent, ThesaurusEntriesPickerComponent, ThesaurusPagedTreeFilterComponent, ThesaurusTreeComponent, renderLabelFromLastColon };
395
+ export type { EditedThesEntry, PayloadMatDialogConfig, ThesaurusEntryNodeFilter, ThesaurusEntryPagedTreeNode };