@itrocks/list 0.8.0 → 0.13.3
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 +99 -1
- package/build.js +21 -8
- package/cjs/access.d.ts +10 -0
- package/cjs/access.js +12 -0
- package/cjs/access.js.map +1 -0
- package/cjs/columns.d.ts +18 -10
- package/cjs/columns.js +57 -23
- package/cjs/columns.js.map +1 -1
- package/cjs/feed.js +1 -1
- package/cjs/feed.js.map +1 -1
- package/cjs/filter.js +24 -5
- package/cjs/filter.js.map +1 -1
- package/cjs/list.d.ts +4 -1
- package/cjs/list.html +9 -9
- package/cjs/list.js +54 -7
- package/cjs/list.js.map +1 -1
- package/cjs/multiple-output.d.ts +4 -0
- package/cjs/multiple-output.js +16 -0
- package/cjs/multiple-output.js.map +1 -0
- package/cjs/projection.d.ts +28 -0
- package/cjs/projection.js +91 -0
- package/cjs/projection.js.map +1 -0
- package/cjs/selector-state.d.ts +22 -0
- package/cjs/selector-state.js +109 -0
- package/cjs/selector-state.js.map +1 -0
- package/cjs/sort.js +8 -3
- package/cjs/sort.js.map +1 -1
- package/column-add.svg +1 -0
- package/config.yaml +1 -0
- package/list.css +83 -5
- package/package.json +23 -2
- package/property-select.d.ts +54 -0
- package/property-select.js +245 -0
- package/selector-state.d.ts +14 -0
- package/selector-state.js +38 -0
package/README.md
CHANGED
|
@@ -124,7 +124,7 @@ Both `html()` and `json()` accept an optional application scope as a `SearchType
|
|
|
124
124
|
the scope from trusted application state rather than passing request data through directly.
|
|
125
125
|
|
|
126
126
|
For `html()`, the scope is merged after user filters, so it takes precedence if both define
|
|
127
|
-
the same property. The resulting search is passed to both `dataSource().
|
|
127
|
+
the same property. The resulting search is passed to both `dataSource().select()` and
|
|
128
128
|
`dataSource().count()` without replacing list loading, sorting, pagination, metadata,
|
|
129
129
|
templates or the configured data source.
|
|
130
130
|
|
|
@@ -136,3 +136,101 @@ For `json()`, the scope is passed directly to `dataSource().search()`.
|
|
|
136
136
|
- Filterable / searchable tables built on top of
|
|
137
137
|
[@itrocks/table](https://github.com/itrocks-ts/table).
|
|
138
138
|
- JSON list endpoints consumed by SPA or mobile applications.
|
|
139
|
+
|
|
140
|
+
## Projected HTML columns
|
|
141
|
+
|
|
142
|
+
HTML lists, feed pages and visible-column requests use the configured `DataSource.select()` implementation. The JSON
|
|
143
|
+
action retains the full-entity `search()` contract. Mandatory scope overrides user filters and applies to projection,
|
|
144
|
+
visible-id reloads and count. Singular columns require a capable projection adapter. Direct collection columns load
|
|
145
|
+
their values through the configured entity reader for the projected visible row ids.
|
|
146
|
+
|
|
147
|
+
Columns are canonical root-relative paths. The list uses public reflection to resolve metadata and supplies each
|
|
148
|
+
projected value to the existing HTML transformer of its final property. Singular object columns request their finite
|
|
149
|
+
representative scalar closure, including nested representative relations. Singular rendering performs no lazy read.
|
|
150
|
+
Absent relationships render empty cells; ignored scalar conversions render `Unavailable`;
|
|
151
|
+
missing representative fields fail explicitly. Plural paths through a relationship and paths with unknown multiplicity
|
|
152
|
+
are refused before SQL.
|
|
153
|
+
|
|
154
|
+
Direct collections display representative values separated by commas. A collection decorated with
|
|
155
|
+
[`@Component()`](https://github.com/itrocks-ts/composition) uses its structured table output. The optional
|
|
156
|
+
`@MultipleOutput('commas' | 'lines')` property decorator from `@itrocks/list/multiple-output` overrides this default.
|
|
157
|
+
`'lines'` displays ordinary collections as a list and keeps component collections as a table. `'commas'` displays
|
|
158
|
+
representative values on one line, including for components. `multipleOutputOf(type, property)` returns the effective
|
|
159
|
+
mode and inherits explicit property metadata. For example:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import { MultipleOutput } from '@itrocks/list/multiple-output'
|
|
163
|
+
|
|
164
|
+
class Movie {
|
|
165
|
+
@MultipleOutput('lines')
|
|
166
|
+
genres!: Genre[]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`@itrocks/list/projection` exports `ListColumn`, `representationFields` and `listRepresentationDependsOn`. Custom output
|
|
171
|
+
transformations must declare every input through the `fields(type, ancestors, property?)` resolver when their inputs
|
|
172
|
+
differ from `representativeOf(type)`. Return relative paths, or `undefined` to use the standard metadata. An object
|
|
173
|
+
property/type transformer other than public `storeOutput` is refused before querying unless the resolver declares its
|
|
174
|
+
fields. This check also applies to nested representative relations. A custom global representative callback must provide
|
|
175
|
+
a resolver as part of its composition; arbitrary callback internals are not inferred. Cyclic representative expansion is
|
|
176
|
+
rejected. The hook does not change SQL construction or object reconstruction. Object heading sort expands to
|
|
177
|
+
representative scalar paths followed by object identity; storage adds the root tie-breaker.
|
|
178
|
+
|
|
179
|
+
`listDependsOn({ access })` accepts an asynchronous request-scoped adapter returning `{ root?, authorise(path) }`. The
|
|
180
|
+
framework binds configured metadata roots and checks selected paths, representative fields, filters and ordering.
|
|
181
|
+
Without a configured root the ordinary list remains available, with no selector command. Never retain request state in
|
|
182
|
+
the dependency hook. The configured data source remains responsible for storage and mandatory record scope.
|
|
183
|
+
|
|
184
|
+
`GET /<business-route>/list?column=<path>&rowIds=<comma-separated-identifiers>` uses the HTML action and returns a JSON
|
|
185
|
+
column descriptor with rendered cells keyed by root id. It intersects visible ids with the current filters and mandatory
|
|
186
|
+
scope, makes one projection and performs no count. Invalid selections return 400. Full entity JSON remains available
|
|
187
|
+
through `/list/json`. Column configuration saves use the established `columns` parameter and return 204.
|
|
188
|
+
|
|
189
|
+
The browser entry `@itrocks/list/property-select.js` exports `ListPropertySelect`, with explicit metadata, table
|
|
190
|
+
addition, column persistence and narrow pane ports. The framework mounts it only on compatible lists and disposes it on
|
|
191
|
+
navigation. It reserves pending paths, confirms accepted additions, reveals/highlights duplicates without moving focus,
|
|
192
|
+
and checks row identity before insertion. Failed selection leaves the context intact. It loads only currently visible
|
|
193
|
+
row ids; changing the row view while loading rejects the obsolete response with a retry message. Click requests await
|
|
194
|
+
their data before committing a new column. Desktop drags create immediate placeholder columns through the public
|
|
195
|
+
table external transaction. The header contains each
|
|
196
|
+
label and its filter together, so it uses the table addition plugin's single-header contract.
|
|
197
|
+
|
|
198
|
+
`npm test` runs the server contracts; `test/property-select.test.mjs` covers projection, representation, scope, path
|
|
199
|
+
configuration, filters and ordering. Real framework/browser proof is tracked by the property-select L2-LIST delivery.
|
|
200
|
+
|
|
201
|
+
## Selector session state
|
|
202
|
+
|
|
203
|
+
The public `@itrocks/list/selector-state` entry exports `SessionStateStore`, `SelectorStateAction`, `selectorStateKey`
|
|
204
|
+
and the composition hook `listStateDependsOn({ transaction })`. The injected function runs an operation against the
|
|
205
|
+
request's authoritative session snapshot and resolves only after durable save. No session is retained by the binding.
|
|
206
|
+
`SessionStateStore` implements the selector's read/write/remove port with revision checks and removal tombstones in
|
|
207
|
+
`session.propertySelect`, separate from `session.list`. The framework supplies the HTTP adapter transaction.
|
|
208
|
+
|
|
209
|
+
`selectorStateKey(request)` uses the router-resolved route, identifying ids and list action. Query and format arguments
|
|
210
|
+
do not affect it. The rendered article supplies this opaque key to the browser. `GET`, `PUT` and `DELETE` at
|
|
211
|
+
`/property-select/state/json` authorise the target list on every request; conflicts return 409 and ended sessions 410.
|
|
212
|
+
Writes echo the opaque `X-Property-Select-Session` token returned by a read. It cannot identify or authenticate a user;
|
|
213
|
+
it prevents a mounted selector from writing its old state into a new session.
|
|
214
|
+
|
|
215
|
+
The public browser `@itrocks/list/selector-state.js` exports `HttpStateStore`, using same-origin credentials and
|
|
216
|
+
no-store requests. `ListSelectorOptions.advice` supplies configured destinations. List column changes refresh used
|
|
217
|
+
paths; only a confirmed new addition feeds the selector's recents. The browser displays recoverable persistence errors.
|
|
218
|
+
|
|
219
|
+
## External column transport
|
|
220
|
+
|
|
221
|
+
The list consumer supplies immediate cells, authorises admission and loads the current visible ids through the same
|
|
222
|
+
projection/rendering route used for click additions. `validate=1` on a `column` request checks representation and
|
|
223
|
+
permission without selecting records; it prevents unsupported object and nested plural paths from being confirmed
|
|
224
|
+
on drop.
|
|
225
|
+
Admission is independent of the optional values request. A slow or failed values request leaves valid drops accepted;
|
|
226
|
+
failed cells expose `Retry values` without another addition or recent entry.
|
|
227
|
+
|
|
228
|
+
Pending paths and the active drag are reserved before asynchronous work. Used paths retain their committed order
|
|
229
|
+
throughout the drag, and configuration saves exclude provisional cells. New accepted drops feed recents; moves and
|
|
230
|
+
cancellations do not. Row-view changes and view disposal cancel transport. The desktop pane stays open, and capture is
|
|
231
|
+
owned by the selector's surviving source controller. The consumer imports no home implementation, SQL or hydration code.
|
|
232
|
+
|
|
233
|
+
The consumer requests `pane.suspend({ mobileOnly: true })` only when a source gesture has been recognised. The pane
|
|
234
|
+
host owns its responsive breakpoint. The token is restored after acceptance and column persistence, or after
|
|
235
|
+
cancellation/rejection; it never focuses the search field. View disposal removes the registration and invalidates late
|
|
236
|
+
restoration. Custom pane adapters may implement the same optional suspension argument without importing `home`.
|
package/build.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { build } from '@itrocks/build/build.js';
|
|
2
|
-
import {
|
|
2
|
+
import { TableColumnAdd } from '@itrocks/table/column-add.js';
|
|
3
3
|
import { TableColumnReorderFreeze } from '@itrocks/table/column-reorder-freeze.js';
|
|
4
|
+
import { TableColumnReorder } from '@itrocks/table/column-reorder.js';
|
|
4
5
|
import { TableFeed } from '@itrocks/table/feed.js';
|
|
5
6
|
import { TableFreeze } from '@itrocks/table/freeze.js';
|
|
6
7
|
import { TableFreezeInheritBackground } from '@itrocks/table/freeze/inherit-background.js';
|
|
@@ -9,13 +10,20 @@ import { TableLink } from '@itrocks/table/link.js';
|
|
|
9
10
|
import { tableByElement } from '@itrocks/table/table.js';
|
|
10
11
|
import { xTargetCall } from '@itrocks/xtarget/xtarget.js';
|
|
11
12
|
build('article[data-action="list"] > form > table.objects', table => {
|
|
13
|
+
let saving = Promise.resolve();
|
|
12
14
|
const saveColumns = () => {
|
|
13
|
-
const columns = table.tHead?.rows[0].querySelectorAll(':scope > th[data-property]');
|
|
15
|
+
const columns = table.tHead?.rows[0].querySelectorAll(':scope > th[data-property]:not(.column-add-provisional)');
|
|
14
16
|
const form = table.closest('form');
|
|
15
17
|
if (!columns || !form)
|
|
16
|
-
return;
|
|
18
|
+
return Promise.resolve();
|
|
17
19
|
const properties = Array.from(columns, column => encodeURIComponent(column.dataset.property ?? ''));
|
|
18
|
-
|
|
20
|
+
const url = form.action + '?columns=' + properties.join(',');
|
|
21
|
+
saving = saving.catch(() => { }).then(async () => {
|
|
22
|
+
const response = await fetch(url, { keepalive: true });
|
|
23
|
+
if (!response.ok)
|
|
24
|
+
throw new Error('Unable to save columns');
|
|
25
|
+
});
|
|
26
|
+
return saving;
|
|
19
27
|
};
|
|
20
28
|
const tableColumnReorder = new TableColumnReorder({
|
|
21
29
|
isReorderable: header => header.dataset.property !== undefined,
|
|
@@ -30,12 +38,16 @@ build('article[data-action="list"] > form > table.objects', table => {
|
|
|
30
38
|
return { element: input, value: input.value };
|
|
31
39
|
}
|
|
32
40
|
});
|
|
33
|
-
|
|
41
|
+
const addition = new TableColumnAdd({ identify: header => header.dataset.property });
|
|
42
|
+
const instance = tableByElement(table, {
|
|
34
43
|
plugins: [
|
|
35
|
-
tableColumnReorder, TableColumnReorderFreeze, TableFeed, TableFreeze, TableFreezeInheritBackground,
|
|
44
|
+
tableColumnReorder, addition, TableColumnReorderFreeze, TableFeed, TableFreeze, TableFreezeInheritBackground,
|
|
36
45
|
TableFreezeInheritBorder, tableLink
|
|
37
46
|
]
|
|
38
47
|
});
|
|
48
|
+
table.dispatchEvent(new CustomEvent('itrocks:list-ready', {
|
|
49
|
+
bubbles: true, detail: { addition, instance, saveColumns }
|
|
50
|
+
}));
|
|
39
51
|
table.addEventListener('click', event => {
|
|
40
52
|
const element = event.target;
|
|
41
53
|
if ((element instanceof HTMLInputElement) || !(element instanceof HTMLElement))
|
|
@@ -51,10 +63,11 @@ build('article[data-action="list"] > form > table.objects', table => {
|
|
|
51
63
|
});
|
|
52
64
|
table.tHead?.addEventListener('click', event => {
|
|
53
65
|
const element = event.target;
|
|
54
|
-
if (!(element instanceof HTMLElement))
|
|
66
|
+
if (!(element instanceof HTMLElement) || element.closest('input, button'))
|
|
55
67
|
return;
|
|
56
68
|
const cell = element.closest('table, th');
|
|
57
|
-
if (!(cell instanceof HTMLTableCellElement) || !cell.dataset.property
|
|
69
|
+
if (!(cell instanceof HTMLTableCellElement) || !cell.dataset.property
|
|
70
|
+
|| cell.dataset.sortable === 'false')
|
|
58
71
|
return;
|
|
59
72
|
const form = cell.closest('form');
|
|
60
73
|
if (!form)
|
package/cjs/access.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Request } from '@itrocks/action-request';
|
|
2
|
+
export type ListAccess = {
|
|
3
|
+
authorise(path: string): Promise<void>;
|
|
4
|
+
root?: string;
|
|
5
|
+
};
|
|
6
|
+
export type ListDependencies = {
|
|
7
|
+
access: (request: Request) => Promise<ListAccess>;
|
|
8
|
+
};
|
|
9
|
+
export declare function listDependsOn(overrides: Partial<ListDependencies>): void;
|
|
10
|
+
export declare function listAccess(request: Request): Promise<ListAccess>;
|
package/cjs/access.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listDependsOn = listDependsOn;
|
|
4
|
+
exports.listAccess = listAccess;
|
|
5
|
+
const dependencies = { access: async () => ({ authorise: async () => { } }) };
|
|
6
|
+
function listDependsOn(overrides) {
|
|
7
|
+
Object.assign(dependencies, overrides);
|
|
8
|
+
}
|
|
9
|
+
function listAccess(request) {
|
|
10
|
+
return dependencies.access(request);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":";;AAUA,sCAGC;AAED,gCAGC;AAVD,MAAM,YAAY,GAAqB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AAE9F,SAAgB,aAAa,CAAC,SAAoC;IAEjE,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;AACvC,CAAC;AAED,SAAgB,UAAU,CAAC,OAAgB;IAE1C,OAAO,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC"}
|
package/cjs/columns.d.ts
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
import { Type } from '@itrocks/class-type';
|
|
2
|
-
import { ReflectProperty } from '@itrocks/reflect';
|
|
3
2
|
import { Request } from '@itrocks/request-response';
|
|
4
3
|
import { Option } from '@itrocks/storage';
|
|
4
|
+
import { ProjectionResult } from '@itrocks/storage';
|
|
5
|
+
import { SearchType } from '@itrocks/storage';
|
|
5
6
|
import { Parameter } from './parameter';
|
|
6
|
-
|
|
7
|
+
import { ListColumn } from './projection';
|
|
8
|
+
export declare class Columns<T extends object> extends Parameter implements Iterable<ListColumn> {
|
|
7
9
|
private configured;
|
|
8
|
-
properties:
|
|
9
|
-
[Symbol.iterator](): ArrayIterator<
|
|
10
|
+
properties: ListColumn[];
|
|
11
|
+
[Symbol.iterator](): ArrayIterator<ListColumn>;
|
|
10
12
|
getParams(request: Request, type: Type<T>): void;
|
|
11
13
|
get length(): number;
|
|
12
|
-
map(callback: (value:
|
|
13
|
-
|
|
14
|
+
map<R>(callback: (value: ListColumn) => R): R[];
|
|
15
|
+
projected(result: ProjectionResult): Promise<{
|
|
16
|
+
id: import("@itrocks/storage").Identifier;
|
|
17
|
+
properties: {
|
|
18
|
+
outputOptionalContainer: string;
|
|
19
|
+
}[];
|
|
20
|
+
}[]>;
|
|
14
21
|
readOptions(options?: Option[]): Option[];
|
|
15
|
-
remove(
|
|
16
|
-
serialize():
|
|
17
|
-
unserialize(data:
|
|
18
|
-
unshift(property:
|
|
22
|
+
remove(name: string): void;
|
|
23
|
+
serialize(): string[];
|
|
24
|
+
unserialize(data: string[], type: Type<T>): void;
|
|
25
|
+
unshift(property: ListColumn): number;
|
|
19
26
|
}
|
|
27
|
+
export declare function projectColumns<T extends object>(type: Type<T>, columns: readonly ListColumn[], search: SearchType<T>, options: Option[]): Promise<ProjectionResult<T>>;
|
package/cjs/columns.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Columns = void 0;
|
|
4
|
+
exports.projectColumns = projectColumns;
|
|
4
5
|
const list_properties_1 = require("@itrocks/list-properties");
|
|
5
|
-
const
|
|
6
|
+
const storage_1 = require("@itrocks/storage");
|
|
7
|
+
const storage_2 = require("@itrocks/storage");
|
|
6
8
|
const parameter_1 = require("./parameter");
|
|
9
|
+
const projection_1 = require("./projection");
|
|
7
10
|
class Columns extends parameter_1.Parameter {
|
|
8
11
|
configured = false;
|
|
9
|
-
properties =
|
|
12
|
+
properties = [];
|
|
10
13
|
[Symbol.iterator]() {
|
|
11
14
|
return this.properties[Symbol.iterator]();
|
|
12
15
|
}
|
|
13
16
|
getParams(request, type) {
|
|
14
17
|
const data = request.data.columns;
|
|
15
18
|
if (data !== undefined) {
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const properties = reordered.filter((property) => !!property);
|
|
21
|
-
if ((properties.length === propertyNames.length)
|
|
22
|
-
&& (new Set(properties).size === propertyNames.length)) {
|
|
23
|
-
this.configured = true;
|
|
19
|
+
const names = (Array.isArray(data) ? data : [data]).flatMap(property => (typeof property === 'string') ? (property ? property.split(',') : []) : property);
|
|
20
|
+
if (names.every((name) => typeof name === 'string') && new Set(names).size === names.length) {
|
|
21
|
+
try {
|
|
22
|
+
const properties = names.map(name => new projection_1.ListColumn(type, name));
|
|
24
23
|
this.properties = properties;
|
|
24
|
+
this.configured = true;
|
|
25
25
|
}
|
|
26
|
+
catch { /* Invalid saved requests preserve the previous configuration. */ }
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
|
-
if (!this.configured && !this.length)
|
|
29
|
-
this.properties = new list_properties_1.ListReflectClass(type).listProperties();
|
|
30
|
-
}
|
|
29
|
+
if (!this.configured && !this.length)
|
|
30
|
+
this.properties = new list_properties_1.ListReflectClass(type).listProperties().map(property => new projection_1.ListColumn(type, String(property.name)));
|
|
31
31
|
this.configured = true;
|
|
32
32
|
}
|
|
33
33
|
get length() {
|
|
@@ -36,30 +36,64 @@ class Columns extends parameter_1.Parameter {
|
|
|
36
36
|
map(callback) {
|
|
37
37
|
return this.properties.map(callback);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
async projected(result) {
|
|
40
|
+
if (result.columns.some((column, index) => column.path !== this.properties[index]?.name)
|
|
41
|
+
|| result.columns.length !== this.length)
|
|
42
|
+
throw new Error('Projection columns do not match the list');
|
|
43
|
+
return Promise.all(result.rows.map(async (row) => ({
|
|
44
|
+
id: row.rootId,
|
|
45
|
+
properties: await Promise.all(row.cells.map(async (cell, index) => ({
|
|
46
|
+
outputOptionalContainer: await this.properties[index].output(cell)
|
|
47
|
+
})))
|
|
48
|
+
})));
|
|
41
49
|
}
|
|
42
50
|
readOptions(options = new Array) {
|
|
43
51
|
return options;
|
|
44
52
|
}
|
|
45
|
-
remove(
|
|
46
|
-
|
|
47
|
-
if (property.name !== propertyName)
|
|
48
|
-
continue;
|
|
49
|
-
this.properties.splice(this.properties.indexOf(property), 1);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
53
|
+
remove(name) {
|
|
54
|
+
this.properties = this.properties.filter(property => property.name !== name);
|
|
52
55
|
}
|
|
53
56
|
serialize() {
|
|
54
57
|
return this.properties.map(property => property.name);
|
|
55
58
|
}
|
|
56
59
|
unserialize(data, type) {
|
|
60
|
+
this.properties = data.flatMap(name => {
|
|
61
|
+
try {
|
|
62
|
+
return [new projection_1.ListColumn(type, name)];
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
});
|
|
57
68
|
this.configured = true;
|
|
58
|
-
this.properties = data.map(property => new reflect_1.ReflectProperty(type, property));
|
|
59
69
|
}
|
|
60
70
|
unshift(property) {
|
|
61
71
|
return this.properties.unshift(property);
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
exports.Columns = Columns;
|
|
75
|
+
async function projectColumns(type, columns, search, options) {
|
|
76
|
+
const singular = columns.filter(column => !column.multiple);
|
|
77
|
+
const result = await (0, storage_1.dataSource)().select(type, singular.map(column => column.selection()), search, options);
|
|
78
|
+
if (!columns.some(column => column.multiple) || !result.rows.length)
|
|
79
|
+
return result;
|
|
80
|
+
const ids = result.rows.map(row => row.rootId);
|
|
81
|
+
const objects = await (0, storage_1.dataSource)().search(type, search, [new storage_2.Identifiers(ids)]);
|
|
82
|
+
const byId = new Map(objects.map(object => [String(object.id), object]));
|
|
83
|
+
return {
|
|
84
|
+
rootType: type,
|
|
85
|
+
columns: columns.map(column => ({ path: column.name, kind: column.multiple ? 'scalar' :
|
|
86
|
+
result.columns[singular.indexOf(column)].kind })),
|
|
87
|
+
rows: await Promise.all(result.rows.map(async (row) => {
|
|
88
|
+
const object = byId.get(String(row.rootId));
|
|
89
|
+
const cells = await Promise.all(columns.map(async (column) => {
|
|
90
|
+
if (!column.multiple)
|
|
91
|
+
return row.cells[singular.indexOf(column)];
|
|
92
|
+
const value = object ? await object[column.name] : [];
|
|
93
|
+
return { kind: 'value', value: value ?? [] };
|
|
94
|
+
}));
|
|
95
|
+
return { rootId: row.rootId, cells };
|
|
96
|
+
}))
|
|
97
|
+
};
|
|
98
|
+
}
|
|
65
99
|
//# sourceMappingURL=columns.js.map
|
package/cjs/columns.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"columns.js","sourceRoot":"","sources":["../src/columns.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"columns.js","sourceRoot":"","sources":["../src/columns.ts"],"names":[],"mappings":"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"}
|
package/cjs/feed.js
CHANGED
|
@@ -17,7 +17,7 @@ class Feed extends parameter_1.Parameter {
|
|
|
17
17
|
this.limit = xhrInfo.targetHeight
|
|
18
18
|
? Math.ceil(xhrInfo.targetHeight / this.lineHeight)
|
|
19
19
|
: (xhrInfo.visibleRows ?? Feed.DEFAULT_LIMIT);
|
|
20
|
-
this.offset = +request.data.offset;
|
|
20
|
+
this.offset = +(request.data.offset ?? Feed.DEFAULT_OFFSET);
|
|
21
21
|
}
|
|
22
22
|
readOptions(options = new Array) {
|
|
23
23
|
options.push(new storage_1.Limit(this.limit, this.offset));
|
package/cjs/feed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feed.js","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":";;;AACA,8CAA4C;AAE5C,2CAAuC;AAEvC,MAAa,IAAK,SAAQ,qBAAS;IAGlC,MAAM,CAAC,aAAa,GAAS,EAAE,CAAA;IAC/B,MAAM,CAAC,mBAAmB,GAAG,EAAE,CAAA;IAC/B,MAAM,CAAC,cAAc,GAAQ,CAAC,CAAA;IAE9B,KAAK,GAAQ,IAAI,CAAC,aAAa,CAAA;IAC/B,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAA;IACrC,MAAM,GAAO,IAAI,CAAC,cAAc,CAAA;IAChC,QAAQ,GAAK,SAAS,GAAG,YAAY,CAAA;IAErC,SAAS,CAAC,OAAgB;QAEzB,MAAM,MAAM,GAAI,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAChD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,YAAY;YAChC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC;YACpD,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"feed.js","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":";;;AACA,8CAA4C;AAE5C,2CAAuC;AAEvC,MAAa,IAAK,SAAQ,qBAAS;IAGlC,MAAM,CAAC,aAAa,GAAS,EAAE,CAAA;IAC/B,MAAM,CAAC,mBAAmB,GAAG,EAAE,CAAA;IAC/B,MAAM,CAAC,cAAc,GAAQ,CAAC,CAAA;IAE9B,KAAK,GAAQ,IAAI,CAAC,aAAa,CAAA;IAC/B,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAA;IACrC,MAAM,GAAO,IAAI,CAAC,cAAc,CAAA;IAChC,QAAQ,GAAK,SAAS,GAAG,YAAY,CAAA;IAErC,SAAS,CAAC,OAAgB;QAEzB,MAAM,MAAM,GAAI,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAChD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,YAAY;YAChC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC;YACpD,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,aAAa,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,cAAc,CAAC,CAAA;IAC5D,CAAC;IAED,WAAW,CAAC,UAAU,IAAI,KAAa;QAEtC,OAAO,CAAC,IAAI,CAAC,IAAI,eAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QAChD,OAAO,OAAO,CAAA;IACf,CAAC;;AA1BF,oBA4BC"}
|
package/cjs/filter.js
CHANGED
|
@@ -13,11 +13,30 @@ class Filter extends parameter_1.Parameter {
|
|
|
13
13
|
for (const property of this.columns.map(property => property.name)) {
|
|
14
14
|
this.search[property] ??= '';
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
if ('reset' in request.data)
|
|
17
|
+
this.search = Object.fromEntries(Object.keys(this.search).map(path => [path, '']));
|
|
18
|
+
const apply = (value, prefix = '') => {
|
|
19
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
20
|
+
return;
|
|
21
|
+
for (const [name, child] of Object.entries(value)) {
|
|
22
|
+
let decoded;
|
|
23
|
+
try {
|
|
24
|
+
decoded = decodeURIComponent(name);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const path = prefix ? `${prefix}.${decoded}` : decoded;
|
|
30
|
+
if (typeof child === 'string' && Object.hasOwn(this.search, path))
|
|
31
|
+
this.search[path] = child;
|
|
32
|
+
else
|
|
33
|
+
apply(child, path);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
apply(request.data.search);
|
|
37
|
+
for (const [name, value] of Object.entries(request.data))
|
|
38
|
+
if (name.startsWith('search.') && typeof value === 'string')
|
|
39
|
+
apply({ [name.slice(7)]: value });
|
|
21
40
|
}
|
|
22
41
|
readOptions(options = new Array) {
|
|
23
42
|
return options;
|
package/cjs/filter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":";;;AAIA,2CAAuC;AAIvC,MAAa,MAAyB,SAAQ,qBAAS;IAKnC;IAFnB,MAAM,GAAW,EAAE,CAAA;IAEnB,YAAmB,OAAmB;QAErC,KAAK,EAAE,CAAA;QAFW,YAAO,GAAP,OAAO,CAAY;IAGtC,CAAC;IAED,SAAS,CAAC,OAAgB;QAEzB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QAC7B,CAAC;QACD,
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"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"}
|
package/cjs/list.d.ts
CHANGED
|
@@ -5,11 +5,14 @@ import { Columns } from './columns';
|
|
|
5
5
|
import { Feed } from './feed';
|
|
6
6
|
import { Filter } from './filter';
|
|
7
7
|
import { Sort } from './sort';
|
|
8
|
+
export { listDependsOn } from './access';
|
|
9
|
+
export type { ListAccess, ListDependencies } from './access';
|
|
8
10
|
export declare class List<T extends object = object> extends Action<T> {
|
|
9
11
|
columns: Columns<object>;
|
|
10
12
|
feed: Feed;
|
|
11
13
|
filter: Filter<object>;
|
|
12
14
|
sort: Sort<object>;
|
|
13
|
-
html(request: Request<T>, scope?: SearchType<T>): Promise<import("@itrocks/core-responses").HtmlResponse>;
|
|
15
|
+
html(request: Request<T>, scope?: SearchType<T>): Promise<import("@itrocks/core-responses").JsonResponse | import("@itrocks/core-responses").HtmlResponse>;
|
|
14
16
|
json(request: Request<T>, scope?: SearchType<T>): Promise<import("@itrocks/core-responses").JsonResponse>;
|
|
15
17
|
}
|
|
18
|
+
export default List;
|
package/cjs/list.html
CHANGED
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
<!--BEGIN-->
|
|
15
15
|
|
|
16
16
|
<!--#main-->
|
|
17
|
-
<article data-action="list" data-class="{type.name}" data-route="{type.@route}"
|
|
17
|
+
<article data-action="list" data-class="{type.name}" data-route="{type.@route}" data-property-root="{?root}"
|
|
18
|
+
data-selector-key="{?selectorKey}">
|
|
18
19
|
<header>
|
|
19
20
|
<h2>{type.@output.ucFirst} list</h2>
|
|
21
|
+
<button class="add-column" hidden type="button" aria-label="Add column">+</button>
|
|
20
22
|
<section class="summary">{count} elements</section>
|
|
21
23
|
<ul class="general actions">
|
|
22
24
|
<!--generalActions-->
|
|
@@ -28,15 +30,13 @@
|
|
|
28
30
|
<table class="objects" data-feed-fields="search.*" data-link="{type.@route}">
|
|
29
31
|
<thead>
|
|
30
32
|
<tr class="properties">
|
|
31
|
-
<th class="select" data-freeze><input name="select" type="checkbox" value="all"
|
|
33
|
+
<th class="select" data-freeze><input name="select" type="checkbox" value="all">
|
|
34
|
+
<input name="reset" title="reset search filters" type="submit" value="reset"></th>
|
|
32
35
|
<!--columns-->
|
|
33
|
-
<th data-property="{name}" data-reverse="{?reverse}" data-sort="{?sort}"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<th><input name="reset" title="reset search filters" type="submit" value="reset"></th>
|
|
38
|
-
<!--columns-->
|
|
39
|
-
<th><input name="search.{name.toField}" value="{?.search.{name.toField}}"></th>
|
|
36
|
+
<th data-property="{name}" data-reverse="{?reverse}" data-sort="{?sort}"
|
|
37
|
+
data-sortable="{sortable}">{label}
|
|
38
|
+
<input aria-label="Filter {label}" data-property-filter="{name}" name="search.{field}" value="{search}">
|
|
39
|
+
</th>
|
|
40
40
|
<!--end-->
|
|
41
41
|
</tr>
|
|
42
42
|
</thead>
|
package/cjs/list.js
CHANGED
|
@@ -34,19 +34,27 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
34
34
|
return useValue ? value : void 0;
|
|
35
35
|
};
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.List = void 0;
|
|
37
|
+
exports.List = exports.listDependsOn = void 0;
|
|
38
38
|
const action_1 = require("@itrocks/action");
|
|
39
39
|
const action_2 = require("@itrocks/action");
|
|
40
40
|
const action_3 = require("@itrocks/action");
|
|
41
41
|
const route_1 = require("@itrocks/route");
|
|
42
42
|
const route_2 = require("@itrocks/route");
|
|
43
43
|
const storage_1 = require("@itrocks/storage");
|
|
44
|
+
const storage_2 = require("@itrocks/storage");
|
|
45
|
+
const storage_3 = require("@itrocks/storage");
|
|
46
|
+
const access_1 = require("./access");
|
|
44
47
|
const columns_1 = require("./columns");
|
|
48
|
+
const columns_2 = require("./columns");
|
|
45
49
|
const feed_1 = require("./feed");
|
|
46
50
|
const filter_1 = require("./filter");
|
|
47
51
|
const persist_1 = require("./persist");
|
|
48
52
|
const persist_2 = require("./persist");
|
|
53
|
+
const projection_1 = require("./projection");
|
|
54
|
+
const selector_state_1 = require("./selector-state");
|
|
49
55
|
const sort_1 = require("./sort");
|
|
56
|
+
var access_2 = require("./access");
|
|
57
|
+
Object.defineProperty(exports, "listDependsOn", { enumerable: true, get: function () { return access_2.listDependsOn; } });
|
|
50
58
|
let List = (() => {
|
|
51
59
|
let _classDecorators = [(0, action_3.Need)('Store', 'new'), (0, route_1.Route)('/list')];
|
|
52
60
|
let _classDescriptor;
|
|
@@ -74,20 +82,56 @@ let List = (() => {
|
|
|
74
82
|
const type = request.type;
|
|
75
83
|
(0, persist_1.load)(this, request.request, type);
|
|
76
84
|
columns.getParams(request.request, type);
|
|
77
|
-
|
|
85
|
+
const access = await (0, access_1.listAccess)(request);
|
|
86
|
+
for (const column of columns) {
|
|
87
|
+
await access.authorise(column.name);
|
|
88
|
+
for (const field of column.fields ?? [])
|
|
89
|
+
await access.authorise(`${column.name}.${field}`);
|
|
90
|
+
}
|
|
91
|
+
if (request.request.data.columns !== undefined) {
|
|
78
92
|
(0, persist_2.save)(this, request.request, type);
|
|
79
93
|
return this.htmlResponse('', 204);
|
|
80
94
|
}
|
|
81
95
|
feed.getParams(request.request);
|
|
82
96
|
filter.getParams(request.request);
|
|
97
|
+
for (const column of columns)
|
|
98
|
+
column.search = filter.search[column.name] ?? '';
|
|
83
99
|
sort.getParams(request.request, type);
|
|
84
100
|
(0, persist_2.save)(this, request.request, type);
|
|
85
101
|
const options = feed.readOptions(filter.readOptions(sort.readOptions()));
|
|
86
102
|
const search = Object.assign(filter.searchObject(type), scope);
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
for (const path of Object.keys(search))
|
|
104
|
+
await access.authorise(path);
|
|
105
|
+
for (const path of Object.keys(sort.sorted ?? {}))
|
|
106
|
+
await access.authorise(path);
|
|
107
|
+
if (typeof request.request.data.column === 'string') {
|
|
108
|
+
try {
|
|
109
|
+
const path = request.request.data.column;
|
|
110
|
+
await access.authorise(path);
|
|
111
|
+
const column = new projection_1.ListColumn(type, path);
|
|
112
|
+
for (const field of column.fields ?? [])
|
|
113
|
+
await access.authorise(`${path}.${field}`);
|
|
114
|
+
if (request.request.data.validate === '1')
|
|
115
|
+
return this.jsonResponse({ label: column.label, path, sortable: column.sortable });
|
|
116
|
+
const ids = request.request.data.rowIds;
|
|
117
|
+
if (typeof ids !== 'string')
|
|
118
|
+
throw new Error('Visible row identities are required');
|
|
119
|
+
const result = await (0, columns_2.projectColumns)(type, [column], search, [new storage_2.Identifiers(ids ? ids.split(',') : [])]);
|
|
120
|
+
return this.jsonResponse({
|
|
121
|
+
label: column.label, path, sortable: column.sortable,
|
|
122
|
+
rows: await Promise.all(result.rows.map(async (row) => ({
|
|
123
|
+
id: row.rootId, html: await column.output(row.cells[0])
|
|
124
|
+
})))
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const message = error instanceof storage_3.SelectionError && error.code === 'multiple-values'
|
|
129
|
+
? 'This path has multiple values and cannot be displayed as a column.'
|
|
130
|
+
: error instanceof Error ? error.message : 'Column unavailable';
|
|
131
|
+
return this.jsonResponse({ error: message }, 400);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const objects = await columns.projected(await (0, columns_2.projectColumns)(type, [...columns], search, options));
|
|
91
135
|
if (feed.offset) {
|
|
92
136
|
return this.htmlTemplateResponse({ objects, type }, request, feed.template);
|
|
93
137
|
}
|
|
@@ -99,7 +143,8 @@ let List = (() => {
|
|
|
99
143
|
const actions = (action.need === 'object') ? selectionActions : generalActions;
|
|
100
144
|
actions.push(action);
|
|
101
145
|
}
|
|
102
|
-
return this.htmlTemplateResponse({ columns, count, generalActions, objects, search: filter.search,
|
|
146
|
+
return this.htmlTemplateResponse({ columns, count, generalActions, objects, root: access.root, search: filter.search,
|
|
147
|
+
selectionActions, selectorKey: (0, selector_state_1.selectorStateKey)(request), type }, request, __dirname + '/list.html');
|
|
103
148
|
}
|
|
104
149
|
async json(request, scope) {
|
|
105
150
|
const objects = await (0, storage_1.dataSource)().search(request.type, scope);
|
|
@@ -109,4 +154,6 @@ let List = (() => {
|
|
|
109
154
|
return List = _classThis;
|
|
110
155
|
})();
|
|
111
156
|
exports.List = List;
|
|
157
|
+
// Route resolution must select the action alongside its public dependency hooks.
|
|
158
|
+
exports.default = List;
|
|
112
159
|
//# sourceMappingURL=list.js.map
|