spiderly 19.11.3 → 19.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/docs/angular-customization/index.md +71 -11
- package/agent/docs/authorization/references/api-error-codes.generated.md +3 -0
- package/agent/docs/filtering-patterns/index.md +2 -0
- package/fesm2022/spiderly.mjs +142 -23
- package/fesm2022/spiderly.mjs.map +1 -1
- package/lib/components/spiderly-data-table/spiderly-data-table.component.d.ts +46 -4
- package/lib/controls/base-control.d.ts +11 -0
- package/lib/directives/spiderly-cell-template.directive.d.ts +47 -0
- package/lib/errors/api-error-codes.d.ts +3 -0
- package/lib/handlers/spiderly-error-handler.d.ts +14 -3
- package/lib/services/config.service.base.d.ts +6 -0
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { AfterViewInit, EventEmitter, OnDestroy, OnInit, TemplateRef } from '@angular/core';
|
|
1
|
+
import { AfterViewInit, EventEmitter, OnDestroy, OnInit, QueryList, TemplateRef } from '@angular/core';
|
|
2
2
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
3
3
|
import { TranslocoService } from '@jsverse/transloco';
|
|
4
4
|
import { SelectItem, SortMeta } from 'primeng/api';
|
|
5
5
|
import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
6
6
|
import { Table, TableFilterEvent, TableLazyLoadEvent } from 'primeng/table';
|
|
7
7
|
import { Observable } from 'rxjs';
|
|
8
|
+
import { CellTemplateContext, SpiderlyCellTemplateDirective } from '../../directives/spiderly-cell-template.directive';
|
|
8
9
|
import { Filter } from '../../entities/filter';
|
|
9
10
|
import { LazyLoadSelectedIdsResult } from '../../entities/lazy-load-selected-ids-result';
|
|
10
11
|
import { PaginatedResult } from '../../entities/paginated-result';
|
|
@@ -28,6 +29,11 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
|
|
|
28
29
|
* Rendered in the caption action area ahead of the built-in buttons.
|
|
29
30
|
*/
|
|
30
31
|
actionsTemplate: TemplateRef<any>;
|
|
32
|
+
/**
|
|
33
|
+
* Per-column cell templates projected via `<ng-template spiderlyCellTemplate="field">`.
|
|
34
|
+
* A column with no template keeps the built-in rendering.
|
|
35
|
+
*/
|
|
36
|
+
cellTemplates: QueryList<SpiderlyCellTemplateDirective>;
|
|
31
37
|
tableTitle: string;
|
|
32
38
|
tableIcon: string;
|
|
33
39
|
items: any[];
|
|
@@ -117,6 +123,15 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
|
|
|
117
123
|
rowNavigationPath: string;
|
|
118
124
|
constructor(router: Router, dialogService: DialogService, route: ActivatedRoute, messageService: SpiderlyMessageService, translocoService: TranslocoService, configService: ConfigServiceBase, locale: string);
|
|
119
125
|
ngAfterViewInit(): void;
|
|
126
|
+
/**
|
|
127
|
+
* The template that renders this column's cells, or null to use the built-in rendering.
|
|
128
|
+
* Actions columns have no `field`, so they never match one.
|
|
129
|
+
*
|
|
130
|
+
* Read straight off the QueryList, which is live — a consumer declaring its templates inside a
|
|
131
|
+
* `@for`/`@if` is served with no subscription and nothing to invalidate. The scan is over the
|
|
132
|
+
* TEMPLATED columns only (typically one or two), not over `cols`.
|
|
133
|
+
*/
|
|
134
|
+
getCellTemplate(col: Column): TemplateRef<CellTemplateContext> | null;
|
|
120
135
|
private setupRemovableSort;
|
|
121
136
|
ngOnInit(): void;
|
|
122
137
|
/**
|
|
@@ -179,13 +194,32 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
|
|
|
179
194
|
*/
|
|
180
195
|
private defaultMultiSortMeta;
|
|
181
196
|
private persistedMultiSortMeta;
|
|
197
|
+
/**
|
|
198
|
+
* Drops sort meta the backend has no sort case for. Persisted state outlives the rule that
|
|
199
|
+
* produced it — a sort stored before a column became non-sortable (or before the library
|
|
200
|
+
* started disabling `*CommaSeparated` headers) would otherwise ride every lazy load, and the
|
|
201
|
+
* generated `Build` answers an unknown sort field with a 400. There would be no way out from
|
|
202
|
+
* the UI either: the header that could clear it is exactly the one no longer clickable.
|
|
203
|
+
* Unknown fields (no matching column) are left alone — a consumer may sort on something it
|
|
204
|
+
* declares no column for.
|
|
205
|
+
*/
|
|
206
|
+
private keepSortableMeta;
|
|
182
207
|
private applyDefaultSortIfUnsorted;
|
|
183
208
|
lazyLoad(event: TableLazyLoadEvent): void;
|
|
184
209
|
clientLoad(): void;
|
|
185
210
|
private clientFilterCount;
|
|
186
211
|
filter(event: TableFilterEvent): void;
|
|
187
212
|
private loadFormArrayItems;
|
|
188
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Single source for whether a column header offers click-to-sort (drives both
|
|
215
|
+
* `pSortableColumnDisabled` and the sort icon). Beyond the consumer's explicit `sortable: false`,
|
|
216
|
+
* `*CommaSeparated` fields are auto-disabled: the backend's `PaginatedResultGenerator` never emits
|
|
217
|
+
* a sort case for collection columns (the same naming convention decides both), and since unknown
|
|
218
|
+
* sort fields are rejected with a 400, a clickable header here would be a guaranteed error toast.
|
|
219
|
+
*/
|
|
220
|
+
isColumnSortable(col: Column): boolean;
|
|
221
|
+
/** The column's declared {@link Column.minWidth}, or the default for its filter type. */
|
|
222
|
+
getColHeaderWidth(col: Column): string;
|
|
189
223
|
getColMatchModeOptions(filterType: string): SelectItem<any>[];
|
|
190
224
|
getColMatchMode(filterType: string): any;
|
|
191
225
|
isDropOrMulti(filterType: string): boolean;
|
|
@@ -218,7 +252,7 @@ export declare class SpiderlyDataTableComponent implements OnInit, AfterViewInit
|
|
|
218
252
|
rowUnselect(id: number): void;
|
|
219
253
|
getFormArrayControlByIndex(formControlName: string, index: number): SpiderlyFormControl;
|
|
220
254
|
static ɵfac: i0.ɵɵFactoryDeclaration<SpiderlyDataTableComponent, never>;
|
|
221
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "defaultSortField": { "alias": "defaultSortField"; "required": false; }; "defaultSortOrder": { "alias": "defaultSortOrder"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate"], never, true, never>;
|
|
255
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "defaultSortField": { "alias": "defaultSortField"; "required": false; }; "defaultSortOrder": { "alias": "defaultSortOrder"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate", "cellTemplates"], never, true, never>;
|
|
222
256
|
}
|
|
223
257
|
export declare class Action {
|
|
224
258
|
name?: string;
|
|
@@ -269,6 +303,13 @@ export declare class Column<T = any> {
|
|
|
269
303
|
* lose its anchor.
|
|
270
304
|
*/
|
|
271
305
|
lockVisible?: boolean;
|
|
306
|
+
/**
|
|
307
|
+
* CSS length overriding this column's default minimum width (e.g. `'8rem'`). The defaults are
|
|
308
|
+
* per filter type and sized for the HEADER — filter input plus match-mode dropdown — so they
|
|
309
|
+
* are generous for a column of short values. It is a MINIMUM, not a width: the table still
|
|
310
|
+
* distributes the leftover space.
|
|
311
|
+
*/
|
|
312
|
+
minWidth?: string;
|
|
272
313
|
/**
|
|
273
314
|
* Fired when this column's cell is clicked. Receives a {@link CellClickEvent} with the row id,
|
|
274
315
|
* the column field, the full row, the raw and formatted cell value, the clicked `<td>` element
|
|
@@ -279,7 +320,7 @@ export declare class Column<T = any> {
|
|
|
279
320
|
* Not applied to editable cells — those belong to their inline input.
|
|
280
321
|
*/
|
|
281
322
|
onCellClick?: (event: CellClickEvent) => void;
|
|
282
|
-
constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, onCellClick, }?: {
|
|
323
|
+
constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, minWidth, onCellClick, }?: {
|
|
283
324
|
name?: string;
|
|
284
325
|
field?: string & keyof T;
|
|
285
326
|
filterField?: string & keyof T;
|
|
@@ -295,6 +336,7 @@ export declare class Column<T = any> {
|
|
|
295
336
|
sortable?: boolean;
|
|
296
337
|
visible?: boolean;
|
|
297
338
|
lockVisible?: boolean;
|
|
339
|
+
minWidth?: string;
|
|
298
340
|
onCellClick?: (event: CellClickEvent) => void;
|
|
299
341
|
});
|
|
300
342
|
}
|
|
@@ -19,6 +19,17 @@ export declare class BaseControl {
|
|
|
19
19
|
constructor(translocoService: TranslocoService);
|
|
20
20
|
ngOnInit(): void;
|
|
21
21
|
ngAfterViewInit(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Every control's TEMPLATE renders without a control (`*ngIf="control"`, `control?.errors`,
|
|
24
|
+
* spiderly-file's no-control custom uploads), and this was the one shared read that did not —
|
|
25
|
+
* so an absent control took the whole page down through the label rather than rendering
|
|
26
|
+
* label-less: an unhandled TypeError per change-detection pass, which the global ErrorHandler
|
|
27
|
+
* turns into the generic error toast.
|
|
28
|
+
*
|
|
29
|
+
* That fixes the shared path only. `spiderly-autocomplete`, `spiderly-colorpicker` and
|
|
30
|
+
* `spiderly-checkbox` (with `initializeToFalse`) still dereference `control` in their own
|
|
31
|
+
* `ngOnInit`, so those three are not yet safe to hand an absent control.
|
|
32
|
+
*/
|
|
22
33
|
getTranslatedLabel(): string;
|
|
23
34
|
getValidationErrrorMessages(): any;
|
|
24
35
|
static ɵfac: i0.ɵɵFactoryDeclaration<BaseControl, never>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { TemplateRef } from '@angular/core';
|
|
2
|
+
import type { Column } from '../components/spiderly-data-table/spiderly-data-table.component';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Context handed to a cell template. Read the row with `let-row`, the rest by name
|
|
6
|
+
* (`let-value="value"`, `let-displayValue="displayValue"`, `let-col="col"`).
|
|
7
|
+
*
|
|
8
|
+
* `value` and `displayValue` mean here exactly what they mean on `CellClickEvent`, the other seam
|
|
9
|
+
* this component hands a cell to — raw and formatted respectively. One column can use both
|
|
10
|
+
* (a click handler and a template), so they must not disagree.
|
|
11
|
+
*/
|
|
12
|
+
export interface CellTemplateContext<T = any> {
|
|
13
|
+
/** The full row object the cell belongs to. */
|
|
14
|
+
$implicit: T;
|
|
15
|
+
/** The raw cell value, `row[col.field]`. */
|
|
16
|
+
value: any;
|
|
17
|
+
/**
|
|
18
|
+
* What the table would have rendered — the value formatted for the column's `filterType` and
|
|
19
|
+
* the app's `LOCALE_ID` (dates, numbers, Yes/No). A template that only adds something around
|
|
20
|
+
* the value never has to re-implement that formatting.
|
|
21
|
+
*/
|
|
22
|
+
displayValue: string;
|
|
23
|
+
/** The column being rendered. */
|
|
24
|
+
col: Column<T>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Renders the cells of ONE column of a `spiderly-data-table`, replacing the plain formatted
|
|
28
|
+
* value. Bind it to the column's `field`; columns with no matching template keep the built-in
|
|
29
|
+
* rendering, so a table opts in one column at a time.
|
|
30
|
+
*
|
|
31
|
+
* Consumer guide (context, what it does and does not replace, when to prefer it over
|
|
32
|
+
* `onCellClick`): the `angular-customization` doc, "Custom Cell Content".
|
|
33
|
+
*/
|
|
34
|
+
export declare class SpiderlyCellTemplateDirective<T = any> {
|
|
35
|
+
readonly template: TemplateRef<CellTemplateContext<T>>;
|
|
36
|
+
/** The `field` of the column whose cells this template renders. */
|
|
37
|
+
field: string;
|
|
38
|
+
constructor(template: TemplateRef<CellTemplateContext<T>>);
|
|
39
|
+
/**
|
|
40
|
+
* Without this the `let-` variables are `any` at every consumer, however well
|
|
41
|
+
* {@link CellTemplateContext} is declared — a directive's injected `TemplateRef<C>` never
|
|
42
|
+
* reaches the template that declares it. Same mechanism as `SpiderlyTemplateTypeDirective`.
|
|
43
|
+
*/
|
|
44
|
+
static ngTemplateContextGuard<T>(dir: SpiderlyCellTemplateDirective<T>, ctx: unknown): ctx is CellTemplateContext<T>;
|
|
45
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SpiderlyCellTemplateDirective<any>, never>;
|
|
46
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<SpiderlyCellTemplateDirective<any>, "ng-template[spiderlyCellTemplate]", never, { "field": { "alias": "spiderlyCellTemplate"; "required": false; }; }, {}, never, never, true, never>;
|
|
47
|
+
}
|
|
@@ -11,5 +11,8 @@ export declare const ApiErrorCodes: {
|
|
|
11
11
|
readonly EmailNotVerified: "email_not_verified";
|
|
12
12
|
readonly ExternalProviderNotConfigured: "external_provider_not_configured";
|
|
13
13
|
readonly ExternalEmailMissing: "external_email_missing";
|
|
14
|
+
readonly UnknownFilterField: "unknown_filter_field";
|
|
15
|
+
readonly UnknownSortField: "unknown_sort_field";
|
|
16
|
+
readonly InvalidMatchMode: "invalid_match_mode";
|
|
14
17
|
};
|
|
15
18
|
export type ApiErrorCode = (typeof ApiErrorCodes)[keyof typeof ApiErrorCodes];
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { TranslocoService } from '@jsverse/transloco';
|
|
2
2
|
import { ErrorHandler } from '@angular/core';
|
|
3
3
|
import { SpiderlyMessageService } from '../services/spiderly-message.service';
|
|
4
|
-
import { ConfigServiceBase } from '../services/config.service.base';
|
|
5
4
|
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* The app's global {@link ErrorHandler}: logs the error and shows the generic error toast. HTTP
|
|
7
|
+
* errors are skipped entirely — `unauthorizedInterceptor` owns them end to end and has already
|
|
8
|
+
* logged the failed request and shown the message matched to its status.
|
|
9
|
+
*
|
|
10
|
+
* Logging is unconditional, production included. The toast tells the user the team was notified,
|
|
11
|
+
* and unless the app wires an error tracker this line is the only place the error exists — so
|
|
12
|
+
* staying quiet in production left a deployed app with a red toast and nothing to open. The
|
|
13
|
+
* console is a developer surface; a user never sees it.
|
|
14
|
+
*
|
|
15
|
+
* An error tracker plugs in by providing an `ErrorHandler` that reports and then delegates here,
|
|
16
|
+
* which keeps this class's toast copy true (see the PACMS admin's `AdminErrorHandler`).
|
|
17
|
+
*/
|
|
6
18
|
export declare class SpiderlyErrorHandler implements ErrorHandler {
|
|
7
19
|
private messageService;
|
|
8
20
|
private translocoService;
|
|
9
|
-
|
|
10
|
-
constructor(messageService: SpiderlyMessageService, translocoService: TranslocoService, config: ConfigServiceBase);
|
|
21
|
+
constructor(messageService: SpiderlyMessageService, translocoService: TranslocoService);
|
|
11
22
|
handleError(error: any): void;
|
|
12
23
|
static ɵfac: i0.ɵɵFactoryDeclaration<SpiderlyErrorHandler, never>;
|
|
13
24
|
static ɵprov: i0.ɵɵInjectableDeclaration<SpiderlyErrorHandler>;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { HttpHeaders, HttpParams } from '@angular/common/http';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
export declare class ConfigServiceBase {
|
|
4
|
+
/**
|
|
5
|
+
* Consumer-facing only — nothing in the library reads it. The error handler and the HTTP
|
|
6
|
+
* interceptor used to gate their `console.error` on it, which left a deployed app's client
|
|
7
|
+
* errors with nowhere to go; both now log unconditionally. `spiderly init` still scaffolds the
|
|
8
|
+
* `override`, so apps keep branching on it.
|
|
9
|
+
*/
|
|
4
10
|
production: boolean;
|
|
5
11
|
apiUrl: string;
|
|
6
12
|
frontendUrl: string;
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -90,5 +90,6 @@ export * from './lib/services/helper-functions';
|
|
|
90
90
|
export * from './lib/services/spiderly-message.service';
|
|
91
91
|
export * from './lib/services/spiderly-transloco-loader';
|
|
92
92
|
export * from './lib/services/validator-abstract.service';
|
|
93
|
+
export * from './lib/directives/spiderly-cell-template.directive';
|
|
93
94
|
export * from './lib/directives/spiderly-data-table-actions.directive';
|
|
94
95
|
export * from './lib/directives/template-type.directive';
|