@antelopejs/interface-dms 0.7.2 → 0.7.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/CHANGELOG.md +30 -0
- package/dist/base/block-registry/index.d.ts +1 -0
- package/dist/base/block-registry/index.js +1 -0
- package/dist/base/block-registry/index.js.map +1 -1
- package/dist/base/block-registry/presentation.d.ts +21 -0
- package/dist/base/block-registry/presentation.js +108 -0
- package/dist/base/block-registry/presentation.js.map +1 -0
- package/dist/base/placeholder.js +2 -2
- package/dist/base/placeholder.js.map +1 -1
- package/docs/1.core/2.pages-and-modules.md +2 -0
- package/docs/1.core/5.tenancy.md +2 -0
- package/docs/3.base/1.introduction.md +1 -1
- package/docs/3.base/6.layout.md +7 -1
- package/docs/4.notifications/1.introduction.md +2 -0
- package/docs/4.notifications/2.categories-and-subjects.md +2 -0
- package/docs/4.notifications/3.sending.md +2 -0
- package/docs/5.html-render/1.introduction.md +14 -0
- package/docs/5.html-render/2.built-in-emails.md +50 -0
- package/docs/images/emails-admin-invite.png +0 -0
- package/docs/images/emails-change-notice.png +0 -0
- package/docs/images/emails-change-verification.png +0 -0
- package/docs/images/emails-digest-logo-dark.png +0 -0
- package/docs/images/emails-digest-logo-light.png +0 -0
- package/docs/images/emails-digest.png +0 -0
- package/docs/images/emails-export-partial.png +0 -0
- package/docs/images/emails-export-ready.png +0 -0
- package/docs/images/emails-reset-password.png +0 -0
- package/docs/images/emails-two-factor.png +0 -0
- package/docs/images/emails-user-validation.png +0 -0
- package/docs/index.md +9 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.7.3
|
|
4
|
+
|
|
5
|
+
[compare changes](https://github.com/AntelopeJS/dms/compare/interface-v0.7.2...v0.7.3)
|
|
6
|
+
|
|
7
|
+
### 🚀 Enhancements
|
|
8
|
+
|
|
9
|
+
- **preview:** Share simple options and document real outcomes ([#339](https://github.com/AntelopeJS/dms/pull/339))
|
|
10
|
+
|
|
11
|
+
### 🩹 Fixes
|
|
12
|
+
|
|
13
|
+
- **docs:** Use a sandbox-compatible temporary build database ([#326](https://github.com/AntelopeJS/dms/pull/326))
|
|
14
|
+
- Install DMS frontend with the root workspace ([#322](https://github.com/AntelopeJS/dms/pull/322))
|
|
15
|
+
- **modules:** Top-align card content and place readouts below descriptions ([#328](https://github.com/AntelopeJS/dms/pull/328))
|
|
16
|
+
- **modules:** Reuse registered names in the store ([#330](https://github.com/AntelopeJS/dms/pull/330))
|
|
17
|
+
- **playground:** Use the workspace CLI and compatible core interface ([#331](https://github.com/AntelopeJS/dms/pull/331))
|
|
18
|
+
|
|
19
|
+
### 📖 Documentation
|
|
20
|
+
|
|
21
|
+
- Create the DMS demo through the CLI in quickstart ([#327](https://github.com/AntelopeJS/dms/pull/327))
|
|
22
|
+
|
|
23
|
+
### 🏡 Chore
|
|
24
|
+
|
|
25
|
+
- **release:** @antelopejs/dms v0.9.3 ([1aaf5404](https://github.com/AntelopeJS/dms/commit/1aaf5404))
|
|
26
|
+
- **docs:** Capture temporary MongoDB startup diagnostics ([#325](https://github.com/AntelopeJS/dms/pull/325))
|
|
27
|
+
- **playground:** Refresh compatible dependencies ([#329](https://github.com/AntelopeJS/dms/pull/329))
|
|
28
|
+
|
|
29
|
+
### ❤️ Contributors
|
|
30
|
+
|
|
31
|
+
- Antony Rizzitelli <rizzitelli.antony@pm.me>
|
|
32
|
+
|
|
3
33
|
## v0.7.2
|
|
4
34
|
|
|
5
35
|
[compare changes](https://github.com/AntelopeJS/dms/compare/interface-v0.7.1...v0.7.2)
|
|
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./helpers"), exports);
|
|
18
|
+
__exportStar(require("./presentation"), exports);
|
|
18
19
|
__exportStar(require("./registry"), exports);
|
|
19
20
|
__exportStar(require("./types"), exports);
|
|
20
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/base/block-registry/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,6CAA2B;AAC3B,0CAAwB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/base/block-registry/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,iDAA+B;AAC/B,6CAA2B;AAC3B,0CAAwB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockOptionUi, BlockTypeDescriptor } from "./types";
|
|
2
|
+
/** The hints needed to decide whether an editor offers an option in simple mode. */
|
|
3
|
+
export interface SimpleBlockOption {
|
|
4
|
+
ui?: Pick<BlockOptionUi, "hidden" | "advanced" | "derivedFrom"> & {
|
|
5
|
+
group?: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
/** Shared simple-mode policy; data binding remains available in the builder. */
|
|
9
|
+
export declare function IsSimpleBlockOption(option: SimpleBlockOption): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Dotted paths a standalone preview can edit without replacing data or opaque
|
|
12
|
+
* values. Objects are descended into, never offered as JSON. Only enum arrays
|
|
13
|
+
* in presentation/behavior groups and closed-key scalar records are editable
|
|
14
|
+
* collections; rows, slots and other structural collections remain fixed.
|
|
15
|
+
* Scalar unions have typed controls; a rich union with an explicit scalar
|
|
16
|
+
* widget (e.g. translated text or chart color) offers that scalar only.
|
|
17
|
+
*
|
|
18
|
+
* Fixed factory options exclude their entire top-level subtree. The returned
|
|
19
|
+
* paths reference `config`; consumers must not keep another copy of the schema.
|
|
20
|
+
*/
|
|
21
|
+
export declare function BlockPresentationPaths(descriptor: Pick<BlockTypeDescriptor, "config" | "fixedOptions">): string[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IsSimpleBlockOption = IsSimpleBlockOption;
|
|
4
|
+
exports.BlockPresentationPaths = BlockPresentationPaths;
|
|
5
|
+
/** Shared simple-mode policy; data binding remains available in the builder. */
|
|
6
|
+
function IsSimpleBlockOption(option) {
|
|
7
|
+
const ui = option.ui;
|
|
8
|
+
return (!ui?.hidden && !ui?.advanced && !ui?.derivedFrom && ui?.group !== "advanced");
|
|
9
|
+
}
|
|
10
|
+
const PRESENTATION_WIDGETS = new Set([
|
|
11
|
+
"text",
|
|
12
|
+
"textarea",
|
|
13
|
+
"number",
|
|
14
|
+
"range",
|
|
15
|
+
"switch",
|
|
16
|
+
"select",
|
|
17
|
+
"segmented",
|
|
18
|
+
"icon",
|
|
19
|
+
"color",
|
|
20
|
+
"url",
|
|
21
|
+
]);
|
|
22
|
+
function isPresentation(option) {
|
|
23
|
+
return (IsSimpleBlockOption(option) &&
|
|
24
|
+
option.ui?.group !== "data" &&
|
|
25
|
+
!option.truncated &&
|
|
26
|
+
(!option.ui?.widget || PRESENTATION_WIDGETS.has(option.ui.widget)));
|
|
27
|
+
}
|
|
28
|
+
// A scalar widget can replace a union's structured value, so a restricted
|
|
29
|
+
// descendant in any branch forbids offering that parent too.
|
|
30
|
+
function hasRestrictedHints(option) {
|
|
31
|
+
if (!IsSimpleBlockOption(option) ||
|
|
32
|
+
option.ui?.group === "data" ||
|
|
33
|
+
(option.ui?.widget && !PRESENTATION_WIDGETS.has(option.ui.widget)))
|
|
34
|
+
return true;
|
|
35
|
+
const children = [
|
|
36
|
+
...Object.values(option.properties ?? {}),
|
|
37
|
+
...[option.items, option.values, option.keys].filter((child) => !!child),
|
|
38
|
+
...(option.oneOf ?? []),
|
|
39
|
+
...(option.allOf ?? []),
|
|
40
|
+
...(option.prefixItems ?? []),
|
|
41
|
+
];
|
|
42
|
+
return children.some(hasRestrictedHints);
|
|
43
|
+
}
|
|
44
|
+
function isScalar(option) {
|
|
45
|
+
if (option.truncated || option.allOf || option.prefixItems)
|
|
46
|
+
return false;
|
|
47
|
+
return (["string", "number", "boolean"].includes(option.type) ||
|
|
48
|
+
(option.type === "union" &&
|
|
49
|
+
!!option.oneOf?.length &&
|
|
50
|
+
option.oneOf.every(isScalar)));
|
|
51
|
+
}
|
|
52
|
+
function hasValueEditor(option) {
|
|
53
|
+
if (hasRestrictedHints(option))
|
|
54
|
+
return false;
|
|
55
|
+
if (isScalar(option))
|
|
56
|
+
return true;
|
|
57
|
+
if (option.type === "array") {
|
|
58
|
+
// Content collections can carry demonstration rows even when enum-valued.
|
|
59
|
+
return (["appearance", "behavior", "layout", "features"].includes(option.ui?.group ?? "") &&
|
|
60
|
+
!!option.items?.enum?.length &&
|
|
61
|
+
isScalar(option.items));
|
|
62
|
+
}
|
|
63
|
+
if (option.type === "record") {
|
|
64
|
+
return (!!option.keys?.enum?.length && !!option.values && isScalar(option.values));
|
|
65
|
+
}
|
|
66
|
+
// Rich text and palettes can still use the scalar widget their schema declares.
|
|
67
|
+
return (option.type === "union" &&
|
|
68
|
+
!!option.ui?.widget &&
|
|
69
|
+
!!option.oneOf?.some(isScalar));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Dotted paths a standalone preview can edit without replacing data or opaque
|
|
73
|
+
* values. Objects are descended into, never offered as JSON. Only enum arrays
|
|
74
|
+
* in presentation/behavior groups and closed-key scalar records are editable
|
|
75
|
+
* collections; rows, slots and other structural collections remain fixed.
|
|
76
|
+
* Scalar unions have typed controls; a rich union with an explicit scalar
|
|
77
|
+
* widget (e.g. translated text or chart color) offers that scalar only.
|
|
78
|
+
*
|
|
79
|
+
* Fixed factory options exclude their entire top-level subtree. The returned
|
|
80
|
+
* paths reference `config`; consumers must not keep another copy of the schema.
|
|
81
|
+
*/
|
|
82
|
+
function BlockPresentationPaths(descriptor) {
|
|
83
|
+
const paths = [];
|
|
84
|
+
const walk = (config, prefix) => {
|
|
85
|
+
for (const [key, option] of Object.entries(config)) {
|
|
86
|
+
// Dots and prototype keys cannot be represented safely by path editors.
|
|
87
|
+
if (key.includes(".") ||
|
|
88
|
+
["__proto__", "constructor", "prototype"].includes(key))
|
|
89
|
+
continue;
|
|
90
|
+
if (!prefix && Object.hasOwn(descriptor.fixedOptions ?? {}, key))
|
|
91
|
+
continue;
|
|
92
|
+
if (!isPresentation(option))
|
|
93
|
+
continue;
|
|
94
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
95
|
+
if (option.allOf || option.prefixItems)
|
|
96
|
+
continue;
|
|
97
|
+
if (option.type === "object" && option.properties) {
|
|
98
|
+
walk(option.properties, path);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (hasValueEditor(option))
|
|
102
|
+
paths.push(path);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
walk(descriptor.config, "");
|
|
106
|
+
return paths;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../../src/base/block-registry/presentation.ts"],"names":[],"mappings":"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"}
|
package/dist/base/placeholder.js
CHANGED
|
@@ -15,11 +15,11 @@ exports.PlaceholderSchema = zod_1.z.object({
|
|
|
15
15
|
height: (0, block_registry_1.ui)(zod_1.z
|
|
16
16
|
.string()
|
|
17
17
|
.optional()
|
|
18
|
-
.describe("How tall the box is, such as 200px; left empty, it fills its place."), { label: "Height", group: "appearance" }),
|
|
18
|
+
.describe("How tall the box is, such as 200px; left empty, it fills its place."), { label: "Height", group: "appearance", advanced: true }),
|
|
19
19
|
width: (0, block_registry_1.ui)(zod_1.z
|
|
20
20
|
.string()
|
|
21
21
|
.optional()
|
|
22
|
-
.describe("How wide the box is, such as 300px; left empty, it fills its column."), { label: "Width", group: "appearance" }),
|
|
22
|
+
.describe("How wide the box is, such as 300px; left empty, it fills its column."), { label: "Width", group: "appearance", advanced: true }),
|
|
23
23
|
});
|
|
24
24
|
/**
|
|
25
25
|
* Placeholder - Development Placeholder Component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"placeholder.js","sourceRoot":"","sources":["../../src/base/placeholder.ts"],"names":[],"mappings":";;;AAiEA,kCASC;AA1ED,4CAAgD;AAChD,6BAAwB;AACxB,qDAA+E;AAE/E,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAwBrD,yCAAyC;AAC5B,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,IAAA,mBAAE,EAAC,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE;QACtE,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,SAAS;KACjB,CAAC;IACF,MAAM,EAAE,IAAA,mBAAE,EACR,OAAC;SACE,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,qEAAqE,CACtE,EACH,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"placeholder.js","sourceRoot":"","sources":["../../src/base/placeholder.ts"],"names":[],"mappings":";;;AAiEA,kCASC;AA1ED,4CAAgD;AAChD,6BAAwB;AACxB,qDAA+E;AAE/E,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAwBrD,yCAAyC;AAC5B,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,IAAA,mBAAE,EAAC,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE;QACtE,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,SAAS;KACjB,CAAC;IACF,MAAM,EAAE,IAAA,mBAAE,EACR,OAAC;SACE,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,qEAAqE,CACtE,EACH,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CACzD;IACD,KAAK,EAAE,IAAA,mBAAE,EACP,OAAC;SACE,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,sEAAsE,CACvE,EACH,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CACxD;CACF,CAA+C,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CACzB,OAA4B;IAE5B,OAAO,IAAI,4BAAgB,CAAqB,0BAA0B,CAAC;SACxE,OAAO,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;SACvB,IAAI,CAAC;QACJ,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,gBAAgB;KACvB,CAAC,CAAC;AACP,CAAC;AAED,IAAA,kCAAiB,EAAC;IAChB,IAAI,EAAE,aAAa;IACnB,aAAa,EAAE,0BAA0B;IACzC,MAAM,EAAE,yBAAiB;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,kDAAkD;QAC/D,KAAK,EAAE,QAAQ;KAChB;CACF,CAAC,CAAC"}
|
|
@@ -9,6 +9,8 @@ description: "Pages are controller classes registered into a navigation tree of
|
|
|
9
9
|
|
|
10
10
|
A page is a controller class. `PageController(id, options, layout?)` builds a base class bound to a URL, `@RegisterPage()` records it, and the components declared as static fields on the class become the page's serialized layout. Categories group pages into the sidebar tree, and modules group a whole set of pages and categories under their own root.
|
|
11
11
|
|
|
12
|
+
Building your first screen? Follow [Pages & components](/docs/building/pages-and-components) first. This reference covers registration, identifiers, and lifecycle rules. The guide also shows [page-extension placement](/docs/building/pages-and-components#extending-another-modules-page) in the running playground.
|
|
13
|
+
|
|
12
14
|
Everything on this page lives in `@antelopejs/interface-dms/page`.
|
|
13
15
|
|
|
14
16
|
Registration happens at import time: the `@RegisterPage()` decorator runs when the file is loaded, so the order in which you import page files determines the order in which pages, categories and their permissions are registered.
|
package/docs/1.core/5.tenancy.md
CHANGED
|
@@ -9,6 +9,8 @@ description: "The DMS serves several tenants from one backend."
|
|
|
9
9
|
|
|
10
10
|
The DMS serves several tenants from one backend. Tenant-owned tables live in a per-tenant schema, and a model handle is bound to one tenant when you obtain it: `GetModel(TenantMemberModel, tenantId)` reads and writes that tenant's rows only. No query filters rows by tenant, and no table carries a `tenantId` column — the isolation is in the handle.
|
|
11
11
|
|
|
12
|
+
For a first implementation, follow [Multi-tenant data](/docs/auth-and-tenancy/multi-tenant): register the table in the tenant schema, protect the route, and inject a tenant-bound model. Use this reference for the schema constants and lifecycle contracts. **Resolving a tenant id is not an authorization check**; `getRequestTenantId` must run behind authentication.
|
|
13
|
+
|
|
12
14
|
The tenancy surface spans several subpaths:
|
|
13
15
|
|
|
14
16
|
| Subpath | Contains |
|
|
@@ -60,7 +60,7 @@ Within `types`, four modules are outside that subpath's barrel and are imported
|
|
|
60
60
|
- **Forms from typed fields** — A field names a `DataType`, and the type supplies both the input component and the Zod schema; `Form` compiles the field list into one schema and ships its JSON Schema form with the component.
|
|
61
61
|
- **Tables from data controllers** — `TableView` reads a controller's data-api metadata and its `@Column` declarations to build the columns, the `new` / `edit` / `view` forms, and the permission-carrying actions in one call.
|
|
62
62
|
- **Server-enforced row rules and guards** — Row-action rules are a small algebra evaluated on both sides, and guards run inside the mutating routes, so what the row menu offers is what the server accepts.
|
|
63
|
-
- **A chart and widget set with a shared period scope** —
|
|
63
|
+
- **A chart and widget set with a shared period scope** — Thirteen chart types plus KPI, chart and top-list cards; one `PeriodSelector` id ties them to the same range and comparison.
|
|
64
64
|
- **Layout without a frontend build** — Grids, stacks, tabs and page layouts arrange components, and `CustomComponent` names a Vue component when the vocabulary runs out.
|
|
65
65
|
- **An extensible data-type registry** — `@RegisterDataType` and `@RegisterDataCompareMode` add your own types and filter operators to the catalogue the forms, columns and filters draw from.
|
|
66
66
|
- **Shared prop vocabulary** — Colours, sizes, HTTP methods, action targets, readonly behaviour and watch actions are declared once in `types` and reused by every component.
|
package/docs/3.base/6.layout.md
CHANGED
|
@@ -9,6 +9,13 @@ description: "Grid, stacks, tabs, guard, placeholder and the page layouts that h
|
|
|
9
9
|
|
|
10
10
|
Layout components hold other components. They come in two kinds.
|
|
11
11
|
|
|
12
|
+
| What you want to change | Use |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| The frame around a page: dashboard, settings, or no navigation | A page layout (`DefaultLayout`, `SettingsLayout`, `EmptyLayout`). |
|
|
15
|
+
| The arrangement of blocks inside the page | A container builder (`Grid`, stacks, or tabs). |
|
|
16
|
+
|
|
17
|
+
See the [settings-page screenshot](/docs/building/settings-pages) for the frame and the [container previews](/docs/components/layout-and-containers) for the blocks inside it. The reference below gives their exact contracts.
|
|
18
|
+
|
|
12
19
|
**Containers** are builders: `Grid`, `GridRow`, `HStack`, `VStack`, `Spacer`, `Tab`, `Guard` and `Placeholder` return a `ComponentBuilder`, and you nest components inside them with `.child(id, component)`. They are assigned to a static field of a page class like any other component.
|
|
13
20
|
|
|
14
21
|
**Page layouts** are not builders: `DefaultLayout`, `FormPageLayout`, `SettingsLayout` and `EmptyLayout` return a plain `ComponentInfo` and are passed as the third argument of `PageController` — or as the `layout` option of a page or category, the default of everything declared under it — to say how the page's chrome is drawn.
|
|
@@ -428,4 +435,3 @@ Since the return value is an ordinary builder, `.options()`, `.child()`, `.meta(
|
|
|
428
435
|
`CustomComponent` is also how a table view's `formContainer.pages.*.customPage` option is used: you register your own page carrying a custom component at the slug the table view would otherwise generate — declare that slug as the entry's `urlSlug`, which is taken relative to the page as it stands — see [Tables](/docs/interfaces/base/tables).
|
|
429
436
|
|
|
430
437
|
## Next Steps
|
|
431
|
-
|
|
@@ -13,6 +13,8 @@ The taxonomy is two levels deep. A **category** groups related notifications, a
|
|
|
13
13
|
|
|
14
14
|
Both levels are declared at import time: `NotificationCategory()` first, then the `NotificationSubject()` calls that sit under it. Sending is a fluent chain: `Notification()` opens a builder, the setters fill in the icon, title, description and subject, and `.build()` returns an immutable `SendableNotification` you dispatch to one user, a list of users, the holders of a set of roles, or everyone.
|
|
15
15
|
|
|
16
|
+
See the [notification bell before and after reading](/docs/auth-and-tenancy/authentication#read-notifications) and the [category and subject preferences](/docs/auth-and-tenancy/authentication#notification-preferences) for real dashboard examples. The demonstration sends to one disposable account and checks a second session of that account; it does not broadcast or send email.
|
|
17
|
+
|
|
16
18
|
## Key Features
|
|
17
19
|
|
|
18
20
|
- **Two-level taxonomy** — Categories group subjects, and subjects classify notifications; the `categoryId:subjectId` pair is the key a user's preferences are stored under.
|
|
@@ -13,6 +13,8 @@ You declare categories and subjects by calling `NotificationCategory()` and `Not
|
|
|
13
13
|
|
|
14
14
|
Declarations are values, not decorators: they run when the module that contains them is imported. Declare them at the top level of a module that is imported during startup, so the taxonomy is complete before the first notification is sent.
|
|
15
15
|
|
|
16
|
+
The [notification preferences walkthrough](/docs/auth-and-tenancy/authentication#notification-preferences) shows the System category expanded, its locked General subject, and the Playground category and subject switched off. The Email column is marked Soon: these controls currently manage in-app delivery, not transactional authentication emails.
|
|
17
|
+
|
|
16
18
|
## Declaring a Category
|
|
17
19
|
|
|
18
20
|
`NotificationCategory(id, category)` registers a category and returns the resulting `NotificationCategoryInfo`.
|
|
@@ -9,6 +9,8 @@ description: "Build a notification, then send it to users, roles or everyone, wi
|
|
|
9
9
|
|
|
10
10
|
Sending happens in two steps. `Notification()` starts a builder you fill field by field; `.build()` closes it and gives you a `SendableNotification`, which carries the dispatch methods.
|
|
11
11
|
|
|
12
|
+
For the visible result, see the [single-recipient notification and second-session update](/docs/auth-and-tenancy/authentication#read-notifications). The walkthrough distinguishes delivery from read state and shows [a disabled subject preventing a new delivery](/docs/auth-and-tenancy/authentication#notification-preferences).
|
|
13
|
+
|
|
12
14
|
```typescript
|
|
13
15
|
import {
|
|
14
16
|
GeneralSubject,
|
|
@@ -332,6 +332,20 @@ The `head` slot adds elements to the document head (a `<title>`, a viewport `<me
|
|
|
332
332
|
|
|
333
333
|
The logo is `branding.logo.email.light` from the app config, or `branding.logo.default.light` without an email logo, made absolute against `public.dms.clientBaseUrl` when it starts with `/`. A recipient's mail client fetches it from the internet, and Gmail and Outlook refuse SVG: with `publicLogoOnly`, the layout leaves the logo out when it is an SVG, is not an `http(s)` URL, or is served from a host a mail client cannot reach (`localhost`, `*.local`, `*.internal`, a loopback, private or link-local address), rather than drawing a broken image. Set a PNG logo and a public `clientBaseUrl` for it to show. A `branding.logo.email.dark` goes through the same rules and, when it differs from the light one, is offered to the mail clients in dark mode: the logo is then drawn as `<picture><source media="(prefers-color-scheme: dark)" srcset="…"><img …></picture>`, and a client that ignores the source draws the light image. The same check is exported as `emailLogoUrl(logoPath, clientBaseUrl)` from `#dms-layout/app/emails/components/index`, for a template that draws its own header.
|
|
334
334
|
|
|
335
|
+
### A rendered custom digest
|
|
336
|
+
|
|
337
|
+
The playground's `EmailPlaygroundDigest` reuses this layout with a preheader, `divider="false"` and `public-logo-only`. Here is its actual rendered HTML in English, with fictitious activity for Alex Morgan. With the default SVG logo, the header image is intentionally absent.
|
|
338
|
+
|
|
339
|
+

|
|
340
|
+
|
|
341
|
+
The same template below uses two demonstration PNG logos supplied through the app config. The light-mode capture selects the teal logo; the dark-mode capture selects the navy logo. The reserved demo hostname is mapped to a local image server for these captures, so they do not establish that a recipient can fetch the logo from the internet.
|
|
342
|
+
|
|
343
|
+

|
|
344
|
+
|
|
345
|
+

|
|
346
|
+
|
|
347
|
+
Dark mode changes the selected logo, not the card: `EmailLayout` keeps its white card and pale background in both browser modes. Without a dark logo source, the unbranded examples look identical in both modes. These captures use the real frontend render endpoint and show the returned HTML directly, not the playground's code viewer. No email is sent. Mail clients may strip `<picture>`, block remote images or transform colors; test delivery and appearance in your target clients separately.
|
|
348
|
+
|
|
335
349
|
## Sending Rendered HTML as Email
|
|
336
350
|
|
|
337
351
|
Rendering and sending are separate steps. Render with `GenerateHtml`, then hand the string to the standard AntelopeJS email interface, which needs an implementing module (such as `@antelopejs/nodemailer`) loaded in your project configuration.
|
|
@@ -39,6 +39,56 @@ What the backend passes to each template. A template that replaces a built-in on
|
|
|
39
39
|
|
|
40
40
|
`userName` is the user's name, or their email address when they have none. `expiresInHours` is the lifetime as a number, for the template to word in the recipient's language; `expiresIn` is the same lifetime already worded in English (`24 hours`), kept for templates written before `expiresInHours`.
|
|
41
41
|
|
|
42
|
+
## Rendered examples
|
|
43
|
+
|
|
44
|
+
These captures show HTML returned by the DMS frontend's real render endpoint, opened directly in Chromium, rather than the playground's HTML code viewer. All names, codes, addresses and links are fictitious; no email is sent. The default SVG logo is intentionally omitted by `publicLogoOnly`.
|
|
45
|
+
|
|
46
|
+
### EmailUserValidation
|
|
47
|
+
|
|
48
|
+
The signup email asks Alex to verify their address with a six-digit code, valid for 24 hours.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
### EmailResetPassword
|
|
53
|
+
|
|
54
|
+
The password-reset email uses a separate code and the configured recovery lifetime: two hours in this example.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
### EmailTwoFactor
|
|
59
|
+
|
|
60
|
+
The second-factor email provides a sign-in code. Its footer tells the recipient to ignore the message if they did not attempt to sign in.
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
### EmailAdminInvite
|
|
65
|
+
|
|
66
|
+
The invitation names the inviter, workspace and platform when they are known. Its button uses a fictitious destination here.
|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
### EmailChangeVerification
|
|
71
|
+
|
|
72
|
+
The new address receives the code that confirms the sign-in email change.
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
### EmailChangeNotice
|
|
77
|
+
|
|
78
|
+
The current address receives a notice, not the confirmation code. It tells the recipient what to do if they did not request the change.
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
### EmailExportReady
|
|
83
|
+
|
|
84
|
+
A complete export provides a download button and an expiry. A partial export also names the sources that could not be included.
|
|
85
|
+
|
|
86
|
+

|
|
87
|
+
|
|
88
|
+

|
|
89
|
+
|
|
90
|
+
These are browser previews, not Gmail, Outlook or Apple Mail compatibility tests. See [Email Layout](/docs/interfaces/html-render/introduction#email-layout) for the custom digest, logo variants and the limits of dark-mode support.
|
|
91
|
+
|
|
42
92
|
## Language
|
|
43
93
|
|
|
44
94
|
Each email is written in the recipient's language: the account's `language`, or for an invitation the language it was sent in. English and French are supported; any other language falls back to English.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/index.md
CHANGED
|
@@ -19,6 +19,15 @@ The DMS ships one public AntelopeJS interface package, `@antelopejs/interface-dm
|
|
|
19
19
|
|
|
20
20
|
This section is the contract reference: the exact symbol names, options and return types, grouped by domain. The DMS guide covers the same ground task by task, organised around what you are building.
|
|
21
21
|
|
|
22
|
+
If you are learning the DMS, start with the [Quickstart](/docs/getting-started/quickstart) and [Pages & components](/docs/building/pages-and-components). Return here when you need an import path, a signature, or the exact behavior of an option; you do not need to read every domain before building a page.
|
|
23
|
+
|
|
24
|
+
| Task | Guide with examples | Contract reference |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Build a page and choose its layout | [Pages & components](/docs/building/pages-and-components) | [Pages and modules](/docs/interfaces/core/pages-and-modules), [Layout](/docs/interfaces/base/layout) |
|
|
27
|
+
| Add workspace settings | [Settings pages](/docs/building/settings-pages) | [Page access](/docs/interfaces/core/pages-and-modules#page-access) |
|
|
28
|
+
| Protect a route and scope its data | [Auth & tenancy](/docs/auth-and-tenancy/overview) | [Authentication](/docs/interfaces/auth/authentication), [Tenancy](/docs/interfaces/core/tenancy) |
|
|
29
|
+
| Extend another module's screen | [Page extensions](/docs/building/pages-and-components#extending-another-modules-page) | [Extend a page](/docs/interfaces/core/pages-and-modules#extend-a-page-from-another-module) |
|
|
30
|
+
|
|
22
31
|
Separately published extension interfaces have their own [module interface references](/docs/modules#interface-references), including Builder. This page covers `@antelopejs/interface-dms` itself.
|
|
23
32
|
|
|
24
33
|
## One installed copy
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-dms",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Public AntelopeJS interfaces of the DMS: pages, components, permissions, tenancy, auth, notifications and HTML rendering.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "rimraf dist && tsc",
|
|
35
35
|
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "pnpm run build && node --test tests/*.test.cjs",
|
|
36
37
|
"lint": "oxlint && oxfmt --check .",
|
|
37
38
|
"lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt .",
|
|
38
39
|
"format": "oxfmt .",
|