@antelopejs/dms 0.7.11 → 0.7.12
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/CHANGELOG.md +17 -0
- package/dist/test/unit/interfaces/dms-base/block-parity-options.test.js +7 -0
- package/dist/test/unit/interfaces/dms-base/block-parity-options.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js +10 -0
- package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js.map +1 -1
- package/frontend-vue/layers/dms-core/app/build/composables/page/usePageRecordLabel.ts +7 -29
- package/frontend-vue/layers/dms-core/app/composables/page/usePageRecordLabel.ts +53 -0
- package/frontend-vue/layers/dms-core/app/composables/user/useRegionalFormat.ts +73 -20
- package/frontend-vue/layers/dms-core/app/utils/formatter.ts +37 -1
- package/frontend-vue/layers/dms-core/app/utils/regional.ts +20 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +1 -1
- package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +34 -10
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +69 -17
- package/frontend-vue/layers/dms-ui/app/build/composables/chart/apexTheme.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/form/enclosingForm.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/global/searchShortcuts.ts +7 -16
- package/frontend-vue/layers/dms-ui/app/build/composables/live/liveNotes.ts +54 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page/blockAnchors.ts +50 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +78 -35
- package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +60 -0
- package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +11 -0
- package/frontend-vue/layers/dms-ui/app/components/activity/ActivityItem.vue +17 -9
- package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +58 -7
- package/frontend-vue/layers/dms-ui/app/components/blocks/CodeBlock.vue +5 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/EmptyStateBlock.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +7 -20
- package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +3 -0
- package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +5 -1
- package/frontend-vue/layers/dms-ui/app/components/code-snippet/CodeSnippet.vue +51 -13
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +38 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +58 -3
- package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +19 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +9 -1
- package/frontend-vue/layers/dms-ui/app/composables/chart/types.ts +3 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/validation.ts +10 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/useEnclosingForm.ts +61 -0
- package/frontend-vue/layers/dms-ui/app/composables/global/searchShortcuts.ts +24 -0
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLiveRefresh.ts +103 -0
- package/frontend-vue/layers/dms-ui/app/composables/tab/types/composable.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/composables/tab/types/item.ts +8 -1
- package/frontend-vue/layers/dms-ui/app/composables/tab/useTab.ts +35 -23
- package/frontend-vue/layers/dms-ui/app/types/input-number.ts +18 -0
- package/frontend-vue/layers/dms-ui/app/types/live.ts +6 -0
- package/frontend-vue/layers/dms-ui/app/utils/scrollToBlock.ts +23 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +9 -2
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +9 -2
- package/frontend-vue/tests/activity-feed-fold.test.ts +119 -0
- package/frontend-vue/tests/chart-legend.test.ts +133 -0
- package/frontend-vue/tests/code-block.test.ts +28 -0
- package/frontend-vue/tests/field-suffix-count.test.ts +1 -0
- package/frontend-vue/tests/form-enclosing-form.test.ts +141 -0
- package/frontend-vue/tests/header-actions.test.ts +1 -1
- package/frontend-vue/tests/input-number-adjust.test.ts +176 -0
- package/frontend-vue/tests/live-hold-banner.test.ts +66 -8
- package/frontend-vue/tests/module-routing.test.ts +139 -0
- package/frontend-vue/tests/page-live-refresh.test.ts +169 -0
- package/frontend-vue/tests/page-record-label.test.ts +53 -0
- package/frontend-vue/tests/regional-format.test.ts +69 -2
- package/frontend-vue/tests/scroll-to-block.test.ts +142 -0
- package/frontend-vue/tests/settings-search-shortcuts.test.ts +17 -0
- package/frontend-vue/tests/tab-url-slot.test.ts +150 -0
- package/frontend-vue/tests/table-live-hold.test.ts +90 -0
- package/package.json +2 -2
- package/skills/dms/SKILL.md +28 -4
- package/skills/dms-module/SKILL.md +2 -1
|
@@ -292,3 +292,93 @@ it("holds the table while its first row is scrolled out of view", async () => {
|
|
|
292
292
|
expect(refresh).toHaveBeenCalledTimes(2);
|
|
293
293
|
element.remove();
|
|
294
294
|
});
|
|
295
|
+
|
|
296
|
+
it("holds the table alone while searching or sorted, saying why", async () => {
|
|
297
|
+
const isSearching = ref(false);
|
|
298
|
+
const isSorted = ref(false);
|
|
299
|
+
const isRowOpen = ref(false);
|
|
300
|
+
const { refresh, hold } = mountTable({
|
|
301
|
+
liveHold: { whileSearching: true, whileSorted: true, whileRowOpen: true },
|
|
302
|
+
signals: {
|
|
303
|
+
isSearching: () => isSearching.value,
|
|
304
|
+
isSorted: () => isSorted.value,
|
|
305
|
+
isRowOpen: () => isRowOpen.value,
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
expect(hold.reason.value).toBe(null);
|
|
309
|
+
|
|
310
|
+
isSorted.value = true;
|
|
311
|
+
await nextTick();
|
|
312
|
+
publish();
|
|
313
|
+
expect(refresh).not.toHaveBeenCalled();
|
|
314
|
+
expect(hold.reason.value).toBe("sorted");
|
|
315
|
+
|
|
316
|
+
isSearching.value = true;
|
|
317
|
+
await nextTick();
|
|
318
|
+
expect(hold.reason.value).toBe("searching");
|
|
319
|
+
|
|
320
|
+
isRowOpen.value = true;
|
|
321
|
+
await nextTick();
|
|
322
|
+
expect(hold.reason.value).toBe("rowOpen");
|
|
323
|
+
|
|
324
|
+
// Paused, the page's toggle says why: the table names no reason.
|
|
325
|
+
live.pause();
|
|
326
|
+
await nextTick();
|
|
327
|
+
expect(hold.isHolding.value).toBe(true);
|
|
328
|
+
expect(hold.reason.value).toBe(null);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("holds for no search nor sort the options leave off", async () => {
|
|
332
|
+
const { refresh, hold } = mountTable({
|
|
333
|
+
liveHold: { whileRowOpen: true },
|
|
334
|
+
signals: { isSearching: () => true, isSorted: () => true },
|
|
335
|
+
});
|
|
336
|
+
publish();
|
|
337
|
+
expect(refresh).toHaveBeenCalledTimes(1);
|
|
338
|
+
expect(hold.reason.value).toBe(null);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("tells the hold about the table's search and sort, and the banner why", () => {
|
|
342
|
+
expect(tableViewSource).toContain(
|
|
343
|
+
"isSearching: () => !!effectiveGlobalFilter.value,",
|
|
344
|
+
);
|
|
345
|
+
expect(tableViewSource).toContain(
|
|
346
|
+
"isSorted: () => !isSameSorting(effectiveSorting.value, defaultSortState),",
|
|
347
|
+
);
|
|
348
|
+
expect(tableViewSource).toMatch(
|
|
349
|
+
/v-if="liveHold\.newCount\.value > 0 \|\| liveHold\.reason\.value"/,
|
|
350
|
+
);
|
|
351
|
+
expect(tableViewSource).toContain(':reason="liveHold.reason.value"');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("hands the strip the paused page's breakdown and the table's missedLabel", async () => {
|
|
355
|
+
const isRowOpen = ref(false);
|
|
356
|
+
const { hold } = mountTable({
|
|
357
|
+
liveHold: { whileRowOpen: true, missedLabel: "$api.live.new_requests" },
|
|
358
|
+
signals: { isRowOpen: () => isRowOpen.value },
|
|
359
|
+
});
|
|
360
|
+
expect(hold.missedLabel).toBe("$api.live.new_requests");
|
|
361
|
+
const detail = { text: "$api.live.in_5xx", params: { count: 1 } };
|
|
362
|
+
|
|
363
|
+
// Held by an open row, the page live: the page has no breakdown to give.
|
|
364
|
+
isRowOpen.value = true;
|
|
365
|
+
await nextTick();
|
|
366
|
+
publish();
|
|
367
|
+
live.setMissedDetail(detail);
|
|
368
|
+
expect(hold.missedDetail.value).toBe(null);
|
|
369
|
+
|
|
370
|
+
live.pause();
|
|
371
|
+
await nextTick();
|
|
372
|
+
publish();
|
|
373
|
+
live.setMissedDetail(detail);
|
|
374
|
+
expect(hold.missedDetail.value).toEqual(detail);
|
|
375
|
+
|
|
376
|
+
live.resume();
|
|
377
|
+
await nextTick();
|
|
378
|
+
expect(hold.missedDetail.value).toBe(null);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it("passes the strip its wording and breakdown", () => {
|
|
382
|
+
expect(tableViewSource).toContain(':missed-label="liveHold.missedLabel"');
|
|
383
|
+
expect(tableViewSource).toContain(':detail="liveHold.missedDetail.value"');
|
|
384
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.12",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/AntelopeJS/dms.git"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@antelopejs/interface-data-api": ">=0.2.0 <1.0.0",
|
|
38
38
|
"@antelopejs/interface-database": ">=0.1.8 <1.0.0",
|
|
39
39
|
"@antelopejs/interface-database-decorators": ">=0.1.7 <1.0.0",
|
|
40
|
-
"@antelopejs/interface-dms": ">=0.5.
|
|
40
|
+
"@antelopejs/interface-dms": ">=0.5.7 <0.6.0",
|
|
41
41
|
"@antelopejs/interface-email": ">=0.0.5 <1.0.0",
|
|
42
42
|
"@antelopejs/interface-file-storage": ">=0.1.3 <1.0.0",
|
|
43
43
|
"archiver": "^7.0.1",
|
package/skills/dms/SKILL.md
CHANGED
|
@@ -42,12 +42,21 @@ For the framework underneath (the core, `ajs` CLI, interfaces as versioned contr
|
|
|
42
42
|
(`slowRateAfter: { period: "7d", maxRate: 60 }` for long periods, `rememberKey: "<module>"` to share the
|
|
43
43
|
choice between pages; `maxRate` is also the polling interval while the stream is down) and places a
|
|
44
44
|
`LiveToggle()` (Live / Pause, L key; `variant: "pill"`, `missedLabel` for "N new requests").
|
|
45
|
-
`liveHold: true` keeps a table's rows while paused; `liveHold: { whileRowOpen, whileScrolled
|
|
46
|
-
holds the table alone
|
|
45
|
+
`liveHold: true` keeps a table's rows while paused; `liveHold: { whileRowOpen, whileScrolled,
|
|
46
|
+
whileSearching, whileSorted }` also holds the table alone, its strip saying why ("Table on hold ·
|
|
47
|
+
search active"); `liveHold.missedLabel` words its "N new", and paused, it adds the
|
|
48
|
+
`setMissedDetail()` breakdown ("12 new requests · 2 in 5xx"). Paused, an event counts as its `payload.ids` rows or its `payload.count`, so a
|
|
47
49
|
module may batch publishes with `{ count }`. A hidden tab and `?live=0` pause the page too.
|
|
48
50
|
A custom component follows that state with `usePageLive()`, holds the page with `hold(reason)` /
|
|
49
|
-
`release()` and adds a breakdown with `setMissedDetail()`;
|
|
51
|
+
`release()` and adds a breakdown with `setMissedDetail()`; a custom component that reads its own data
|
|
52
|
+
on a topic calls `usePageLiveRefresh(refresh, { realtimeTopic, idleRefresh })`, gated exactly like a
|
|
53
|
+
built-in block (never a throttle of its own); `refreshPageBlocks()` (user actions) always
|
|
50
54
|
reads, `refreshLivePageBlocks()` (timers, feeds) is held while paused.
|
|
55
|
+
A custom component on a record page names its record at the end of the breadcrumb with
|
|
56
|
+
`usePageRecordLabel().setLabel(useDmsRoute().path, label)` (auto-imported; never the `build/` path).
|
|
57
|
+
A custom component formats through `useRegionalFormat()` (`formatNumber` & co. return `string` for a
|
|
58
|
+
number); `useRegionalFormat({ locale: "format" })` writes in `formatLocale`, the locale of the DMS's
|
|
59
|
+
texts (`en` → `en-GB`) — never a hand-rolled `en` → `en-GB` mapping.
|
|
51
60
|
A status the backend computes (health, outage) is a `Banner({ fetchUrl })`: the route answers
|
|
52
61
|
a `BannerContent` (its buttons may run `api` / modal / quick-action targets with `confirm`)
|
|
53
62
|
or `null` for no banner — the block then draws nothing.
|
|
@@ -66,6 +75,8 @@ For the framework underneath (the core, `ajs` CLI, interfaces as versioned contr
|
|
|
66
75
|
duration, an error message), and `DurationDisplay({ format: "ms" })` writes "2,149 ms" on every row;
|
|
67
76
|
and a `PillsDisplay` item may be `{ label, tone?, variant: "soft" | "outline" }`, styled per row.
|
|
68
77
|
A `StatGroup` detail and a `NavCardGrid` card title take up to two lines before their ellipsis.
|
|
78
|
+
An `ActivityFeed` whose entries must be read whole sets `wrap: true` (no ellipsis; leave `fillHeight`
|
|
79
|
+
off so the card grows) and `visibleItems: N` for a "Show N more" fold.
|
|
69
80
|
A unit after a number field is `NumberType({ suffix: "$…days" })`, a character counter on a
|
|
70
81
|
text field `StringType({ maxLength, showCount: true })` — no custom `inputComponent` for either.
|
|
71
82
|
A `TableView` over a shared controller hides a column on one page with
|
|
@@ -73,8 +84,21 @@ For the framework underneath (the core, `ajs` CLI, interfaces as versioned contr
|
|
|
73
84
|
just to hide it.
|
|
74
85
|
A long sectioned `Form` groups its navigation with `FormSection.navGroup` ("Billing", "Legal"),
|
|
75
86
|
in the side list and in the `sectionNav: "jump"` chips alike (a form whose side column holds a preview).
|
|
87
|
+
A module's own `inputComponent` submits its form, adds a validator and focuses a field with
|
|
88
|
+
`useEnclosingForm()` (never `closest("form")` / `requestSubmit()`), and a link ending in `#<fieldId>`
|
|
89
|
+
opens the form on that field, focused. `DmsInputNumber` emits `adjust` (`{ typed, value, reason:
|
|
90
|
+
"min" | "max" | "step" }`) when it keeps another value than the one typed, and redraws the kept
|
|
91
|
+
value itself: a note "1020 → 1,000" listens to it — never a forced remount (`:key`).
|
|
76
92
|
`TopListCard({ actions })` puts link buttons in its head ("Catalogue →"), and `Tab({ fit: true })`
|
|
77
|
-
keeps a pill tab list to its tabs' width
|
|
93
|
+
keeps a pill tab list to its tabs' width; with `persistState` the URL names the open tab by its slot
|
|
94
|
+
(`?tab=tester`, an index still read), and a tab `badge` takes a `$` key or a `ComposedText`. A `ChartCard` plotting several series names them with
|
|
95
|
+
`showSeriesLegend: true` (placed by the chart's `legendPosition: "top" | "bottom"`) — never a raw
|
|
96
|
+
Apex `legend` in `rawOptions`.
|
|
97
|
+
A custom component brings a block of its page into view with `scrollToBlock("tabs.statistics")`
|
|
98
|
+
(the block's key path; `false` when it is not on screen) — never a DOM query of its own.
|
|
99
|
+
Code in a custom component is a `DmsCodeSnippet` (`language`, `title`, `maxLines` or a CSS
|
|
100
|
+
`maxHeight`, `wrap: true | "anywhere"`; without title and language its copy button floats in the
|
|
101
|
+
corner) — never a `<pre>` and copy button of the module's own.
|
|
78
102
|
A `KeyValueList` row takes `copy: true` (a copy button for its shown value) or `copyValue`
|
|
79
103
|
(the text to copy instead, e.g. a full URL behind a short label).
|
|
80
104
|
A table ordered by hand (`reorder: { field }`) moves its rows on the grid and its cards on
|
|
@@ -93,7 +93,8 @@ Three constraints are enforced at registration: a page's `category` must **desce
|
|
|
93
93
|
module root** (nest under what `RegisterModule` returned, or rely on `defaultCategory`),
|
|
94
94
|
module pages cannot use the Settings category, and the module must exist before a page names
|
|
95
95
|
it. Pages resolve at `/modules/<moduleId>/<urlSlug>`; entering the module lands on
|
|
96
|
-
`landingPage` if set, else the first page by `order
|
|
96
|
+
`landingPage` if set, else the first page by `order` — `/modules/<id>` itself redirects there (server
|
|
97
|
+
redirect, query and hash kept), so never register a hidden page to forward it. Access is **owner-only by design**: the
|
|
97
98
|
Modules group is visible to the platform owner alone (the `*` holder), and the
|
|
98
99
|
`modules.<moduleId>.…` permission ids are module-scoped — never grantable through Roles. On a
|
|
99
100
|
SaaS deployment that means you, the maker, not your customers; a screen for end users belongs
|