@antelopejs/dms 0.3.8 → 0.4.0
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 +26 -0
- package/dist/implementations/dms/guards.d.ts +1 -1
- package/dist/implementations/dms-base/table-view.d.ts +1 -1
- package/dist/pages/settings/users/category.d.ts +1 -1
- package/dist/pages/settings/users/members.d.ts +2 -2
- package/dist/pages/settings/users/notifications.d.ts +2 -2
- package/dist/test/attachment-host/native.d.ts +2 -2
- package/dist/validation/auth.schema.d.ts +18 -18
- package/dist/validation/onboarding/register-admin.schema.d.ts +3 -3
- package/package.json +7 -18
- package/skills/dms/REFERENCE.md +2 -3
- package/skills/dms/SKILL.md +1 -1
- package/skills/dms-module/REFERENCE.md +4 -5
- package/skills/dms-module/SKILL.md +1 -1
- package/frontend-vue/tests/theming-browser.mjs +0 -130
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.4.0
|
|
4
|
+
|
|
5
|
+
[compare changes](https://github.com/AntelopeJS/dms/compare/v0.3.8...v0.4.0)
|
|
6
|
+
|
|
7
|
+
### 💅 Refactors
|
|
8
|
+
|
|
9
|
+
- **build:** Merge tsconfig.build.json into tsconfig.json ([#39](https://github.com/AntelopeJS/dms/pull/39))
|
|
10
|
+
- **package:** ⚠️ Drop moduleResolution node support and pack-based checks ([#41](https://github.com/AntelopeJS/dms/pull/41))
|
|
11
|
+
|
|
12
|
+
### 🏡 Chore
|
|
13
|
+
|
|
14
|
+
- **release:** @antelopejs/interface-dms v0.2.0 ([98ad6f4](https://github.com/AntelopeJS/dms/commit/98ad6f4))
|
|
15
|
+
|
|
16
|
+
### 🤖 CI
|
|
17
|
+
|
|
18
|
+
- **release:** Release next from a dedicated branch and restore requireCommits ([#38](https://github.com/AntelopeJS/dms/pull/38))
|
|
19
|
+
- **release:** Reference the shared release workflows through v1 ([#40](https://github.com/AntelopeJS/dms/pull/40))
|
|
20
|
+
|
|
21
|
+
#### ⚠️ Breaking Changes
|
|
22
|
+
|
|
23
|
+
- **package:** ⚠️ Drop moduleResolution node support and pack-based checks ([#41](https://github.com/AntelopeJS/dms/pull/41))
|
|
24
|
+
|
|
25
|
+
### ❤️ Contributors
|
|
26
|
+
|
|
27
|
+
- Antony Rizzitelli <rizzitelli.antony@pm.me>
|
|
28
|
+
|
|
3
29
|
## v0.3.8
|
|
4
30
|
|
|
5
31
|
[compare changes](https://github.com/AntelopeJS/dms/compare/v0.3.7...v0.3.8)
|
|
@@ -3,5 +3,5 @@ import { Action, type ComponentTargetInput } from "@antelopejs/interface-dms/com
|
|
|
3
3
|
import type { TenantGuardOptions } from "@antelopejs/interface-dms/guards";
|
|
4
4
|
import type { TenantTokenInput } from "@antelopejs/interface-dms/auth";
|
|
5
5
|
export declare namespace internal {
|
|
6
|
-
const AuthUserWithPermissionValidator: (target: ComponentTargetInput | ControllerClass | Action, data: TenantTokenInput, options?: TenantGuardOptions) => Promise<false | import("@antelopejs/interface-dms/
|
|
6
|
+
const AuthUserWithPermissionValidator: (target: ComponentTargetInput | ControllerClass | Action, data: TenantTokenInput, options?: TenantGuardOptions) => Promise<false | import("@antelopejs/interface-dms/auth/db").User>;
|
|
7
7
|
}
|
|
@@ -22,7 +22,7 @@ export declare function startExport(controller: DataControllerThis, ctx: Request
|
|
|
22
22
|
format: string;
|
|
23
23
|
extension: string;
|
|
24
24
|
}>;
|
|
25
|
-
export declare function getExportStatus(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<import("@antelopejs/interface-dms/
|
|
25
|
+
export declare function getExportStatus(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<import("@antelopejs/interface-dms/base").ExportJobStatus>;
|
|
26
26
|
export declare function downloadExport(controller: DataControllerThis, ctx: RequestContext, exportId: string, user?: User): Promise<void>;
|
|
27
27
|
interface RuleValidationResult {
|
|
28
28
|
eligibleIds: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const userCategory: import("@antelopejs/interface-dms
|
|
1
|
+
export declare const userCategory: import("@antelopejs/interface-dms").CategoryInfo;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type RequestContext } from "@antelopejs/interface-api";
|
|
2
2
|
import type { Action } from "@antelopejs/interface-dms/component";
|
|
3
3
|
import { type User, UserModel } from "@antelopejs/interface-dms/auth/db";
|
|
4
|
-
export declare const membersTable: import("@antelopejs/interface-dms
|
|
4
|
+
export declare const membersTable: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
|
|
5
5
|
export declare const membersTableAddAction: Action;
|
|
6
6
|
declare const MembersSettingsController_base: {
|
|
7
7
|
new (...args: any[]): {};
|
|
@@ -9,7 +9,7 @@ declare const MembersSettingsController_base: {
|
|
|
9
9
|
location: string;
|
|
10
10
|
};
|
|
11
11
|
export declare class MembersSettingsController extends MembersSettingsController_base {
|
|
12
|
-
static table: import("@antelopejs/interface-dms
|
|
12
|
+
static table: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
|
|
13
13
|
invite(ctx: RequestContext, _user: User, userModel: UserModel, body: unknown): Promise<{
|
|
14
14
|
redirectPath: string;
|
|
15
15
|
}>;
|
|
@@ -15,8 +15,8 @@ export declare class NotificationsApiController extends NotificationsApiControll
|
|
|
15
15
|
getPreferences(preferencesModel: UserNotificationPreferencesModel): Promise<Record<string, boolean>>;
|
|
16
16
|
updatePreferences(body: unknown, preferencesModel: UserNotificationPreferencesModel): Promise<Record<string, boolean>>;
|
|
17
17
|
getCategories(): Promise<{
|
|
18
|
-
categories: import("@antelopejs/interface-dms/
|
|
19
|
-
subjects: import("@antelopejs/interface-dms/
|
|
18
|
+
categories: import("@antelopejs/interface-dms/notifications/types").NotificationCategoryInfo[];
|
|
19
|
+
subjects: import("@antelopejs/interface-dms/notifications/types").NotificationSubjectInfo[];
|
|
20
20
|
}>;
|
|
21
21
|
getNotifications(notificationsModel: UserNotificationsModel, limitParam?: string, offsetParam?: string): Promise<import("../../../db").UserNotification[]>;
|
|
22
22
|
getUnreadCount(notificationsModel: UserNotificationsModel): Promise<{
|
|
@@ -5,10 +5,10 @@ declare const NativeFilePage_base: {
|
|
|
5
5
|
location: string;
|
|
6
6
|
};
|
|
7
7
|
export declare class NativeFilePage extends NativeFilePage_base {
|
|
8
|
-
static content: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base
|
|
8
|
+
static content: import("@antelopejs/interface-dms").ComponentBuilder<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>;
|
|
9
9
|
}
|
|
10
10
|
declare const NativeAttachmentFormController_base: import("@antelopejs/interface-api").ControllerClass<object>;
|
|
11
11
|
export declare class NativeAttachmentFormController extends NativeAttachmentFormController_base {
|
|
12
|
-
get(_user: User): Promise<import("@antelopejs/interface-dms").ComponentInfoSerialized<import("@antelopejs/interface-dms/base
|
|
12
|
+
get(_user: User): Promise<import("@antelopejs/interface-dms").ComponentInfoSerialized<import("@antelopejs/interface-dms/base").TableViewOptionsSerialized>>;
|
|
13
13
|
}
|
|
14
14
|
export {};
|
|
@@ -7,29 +7,29 @@ export declare const authSchema: {
|
|
|
7
7
|
lang: z.ZodString;
|
|
8
8
|
token: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
name: string;
|
|
11
|
-
lang: string;
|
|
12
|
-
email: string;
|
|
13
10
|
token: string;
|
|
14
|
-
password: string;
|
|
15
|
-
}, {
|
|
16
11
|
name: string;
|
|
17
|
-
|
|
12
|
+
password: string;
|
|
18
13
|
email: string;
|
|
14
|
+
lang: string;
|
|
15
|
+
}, {
|
|
19
16
|
token: string;
|
|
17
|
+
name: string;
|
|
20
18
|
password: string;
|
|
19
|
+
email: string;
|
|
20
|
+
lang: string;
|
|
21
21
|
}>;
|
|
22
22
|
login: z.ZodObject<{
|
|
23
23
|
email: z.ZodString;
|
|
24
24
|
password: z.ZodString;
|
|
25
25
|
keep_login: z.ZodOptional<z.ZodBoolean>;
|
|
26
26
|
}, "strip", z.ZodTypeAny, {
|
|
27
|
-
email: string;
|
|
28
27
|
password: string;
|
|
28
|
+
email: string;
|
|
29
29
|
keep_login?: boolean | undefined;
|
|
30
30
|
}, {
|
|
31
|
-
email: string;
|
|
32
31
|
password: string;
|
|
32
|
+
email: string;
|
|
33
33
|
keep_login?: boolean | undefined;
|
|
34
34
|
}>;
|
|
35
35
|
oauthCallback: z.ZodObject<{
|
|
@@ -42,14 +42,14 @@ export declare const authSchema: {
|
|
|
42
42
|
code: string;
|
|
43
43
|
state: string;
|
|
44
44
|
state_cookie: string;
|
|
45
|
-
language?: string | undefined;
|
|
46
45
|
invite?: string | undefined;
|
|
46
|
+
language?: string | undefined;
|
|
47
47
|
}, {
|
|
48
48
|
code: string;
|
|
49
49
|
state: string;
|
|
50
50
|
state_cookie: string;
|
|
51
|
-
language?: string | undefined;
|
|
52
51
|
invite?: string | undefined;
|
|
52
|
+
language?: string | undefined;
|
|
53
53
|
}>;
|
|
54
54
|
refresh: z.ZodObject<{
|
|
55
55
|
token: z.ZodString;
|
|
@@ -83,37 +83,37 @@ export declare const authSchema: {
|
|
|
83
83
|
token: z.ZodString;
|
|
84
84
|
email: z.ZodString;
|
|
85
85
|
}, "strip", z.ZodTypeAny, {
|
|
86
|
-
email: string;
|
|
87
86
|
token: string;
|
|
88
|
-
}, {
|
|
89
87
|
email: string;
|
|
88
|
+
}, {
|
|
90
89
|
token: string;
|
|
90
|
+
email: string;
|
|
91
91
|
}>;
|
|
92
92
|
reset: z.ZodObject<{
|
|
93
93
|
token: z.ZodString;
|
|
94
94
|
email: z.ZodString;
|
|
95
95
|
password: z.ZodString;
|
|
96
96
|
}, "strip", z.ZodTypeAny, {
|
|
97
|
-
email: string;
|
|
98
97
|
token: string;
|
|
99
98
|
password: string;
|
|
100
|
-
}, {
|
|
101
99
|
email: string;
|
|
100
|
+
}, {
|
|
102
101
|
token: string;
|
|
103
102
|
password: string;
|
|
103
|
+
email: string;
|
|
104
104
|
}>;
|
|
105
105
|
verify2FA: z.ZodObject<{
|
|
106
106
|
token: z.ZodString;
|
|
107
107
|
code: z.ZodString;
|
|
108
108
|
method: z.ZodEnum<["totp", "email", "backup"]>;
|
|
109
109
|
}, "strip", z.ZodTypeAny, {
|
|
110
|
-
code: string;
|
|
111
110
|
method: "email" | "totp" | "backup";
|
|
112
111
|
token: string;
|
|
113
|
-
}, {
|
|
114
112
|
code: string;
|
|
113
|
+
}, {
|
|
115
114
|
method: "email" | "totp" | "backup";
|
|
116
115
|
token: string;
|
|
116
|
+
code: string;
|
|
117
117
|
}>;
|
|
118
118
|
request2FAEmail: z.ZodObject<{
|
|
119
119
|
token: z.ZodString;
|
|
@@ -133,11 +133,11 @@ export declare const authSchema: {
|
|
|
133
133
|
method: z.ZodEnum<["totp", "email"]>;
|
|
134
134
|
code: z.ZodString;
|
|
135
135
|
}, "strip", z.ZodTypeAny, {
|
|
136
|
-
code: string;
|
|
137
136
|
method: "email" | "totp";
|
|
138
|
-
}, {
|
|
139
137
|
code: string;
|
|
138
|
+
}, {
|
|
140
139
|
method: "email" | "totp";
|
|
140
|
+
code: string;
|
|
141
141
|
}>;
|
|
142
142
|
regenerateBackup: z.ZodObject<{
|
|
143
143
|
code: z.ZodString;
|
|
@@ -5,18 +5,18 @@ export declare const onboardingRegisterAdminSchema: z.ZodEffects<z.ZodObject<{
|
|
|
5
5
|
password: z.ZodString;
|
|
6
6
|
}, "strip", z.ZodTypeAny, {
|
|
7
7
|
name: string;
|
|
8
|
-
email: string;
|
|
9
8
|
password: string;
|
|
9
|
+
email: string;
|
|
10
10
|
}, {
|
|
11
11
|
name: string;
|
|
12
|
-
email: string;
|
|
13
12
|
password: string;
|
|
13
|
+
email: string;
|
|
14
14
|
}>, {
|
|
15
15
|
email: string;
|
|
16
16
|
name: string;
|
|
17
17
|
password: string;
|
|
18
18
|
}, {
|
|
19
19
|
name: string;
|
|
20
|
-
email: string;
|
|
21
20
|
password: string;
|
|
21
|
+
email: string;
|
|
22
22
|
}>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/dms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/AntelopeJS/dms.git"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
+
"!dist/.tsbuildinfo",
|
|
12
13
|
"frontend-vue",
|
|
13
14
|
"skills",
|
|
14
15
|
"package.json",
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
"release-it-changelogen": "^0.1.0",
|
|
74
75
|
"rimraf": "^6.1.3",
|
|
75
76
|
"tsc-alias": "^1.9.1",
|
|
76
|
-
"typescript": "^
|
|
77
|
+
"typescript": "^6.0.3"
|
|
77
78
|
},
|
|
78
79
|
"exports": {
|
|
79
80
|
".": {
|
|
@@ -83,13 +84,6 @@
|
|
|
83
84
|
"./package.json": "./package.json",
|
|
84
85
|
"./interfaces/*": null
|
|
85
86
|
},
|
|
86
|
-
"typesVersions": {
|
|
87
|
-
"*": {
|
|
88
|
-
"pages": [
|
|
89
|
-
"dist/pages/index.d.ts"
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
87
|
"publishConfig": {
|
|
94
88
|
"access": "public",
|
|
95
89
|
"provenance": true,
|
|
@@ -108,22 +102,17 @@
|
|
|
108
102
|
}
|
|
109
103
|
},
|
|
110
104
|
"scripts": {
|
|
111
|
-
"build": "pnpm --filter @antelopejs/interface-dms build && rimraf dist && tsc
|
|
105
|
+
"build": "pnpm --filter @antelopejs/interface-dms build && rimraf dist && tsc && tsc-alias",
|
|
112
106
|
"format": "oxfmt . && pnpm --dir frontend-vue format",
|
|
113
107
|
"dev": "ajs project run --inspect -w -p playground",
|
|
114
108
|
"frontend:dev": "pnpm --dir playground frontend:dev",
|
|
115
109
|
"lint:fix": "oxlint --fix --max-warnings=1000000 && oxfmt . && pnpm --dir frontend-vue lint:fix",
|
|
116
110
|
"lint": "oxlint && oxfmt --check . && pnpm --dir frontend-vue lint",
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"check:inertia-contracts": "node scripts/check-inertia-contracts.mjs",
|
|
120
|
-
"check:inertia-modules": "node scripts/check-inertia-modules.mjs",
|
|
121
|
-
"typecheck": "pnpm --filter @antelopejs/interface-dms build && tsc -p tsconfig.json",
|
|
122
|
-
"check:package": "node scripts/check-package.mjs",
|
|
123
|
-
"test": "pnpm run build && ajs module test . && pnpm run check:package",
|
|
111
|
+
"typecheck": "pnpm --filter @antelopejs/interface-dms build && tsc --noEmit",
|
|
112
|
+
"test": "pnpm run build && ajs module test .",
|
|
124
113
|
"test:unit": "pnpm run build && DMS_TEST_DIR=dist/test/unit ajs module test .",
|
|
125
114
|
"test:integration": "pnpm run build && DMS_TEST_DIR=dist/test/integration ajs module test .",
|
|
126
|
-
"test:watch": "tsc -
|
|
115
|
+
"test:watch": "tsc -w & tsc-alias -w",
|
|
127
116
|
"release": "pnpm --filter @antelopejs/interface-dms build && pnpm --dir frontend-vue install --frozen-lockfile && release-it",
|
|
128
117
|
"knip": "knip --dependencies",
|
|
129
118
|
"knip:all": "knip"
|
package/skills/dms/REFERENCE.md
CHANGED
|
@@ -15,8 +15,7 @@ List a section to see its files:
|
|
|
15
15
|
| `docs/04.components/` | Component catalog: charts/widgets, layout, forms, tables, tree, DataTypes, DataController, file storage |
|
|
16
16
|
| `docs/05.extending-the-dashboard/` | Dashboard chrome, theming, custom DataTypes (frontend side), table-view displays, component events, period filtering |
|
|
17
17
|
| `docs/06.frontend-composables/` | Composables a custom frontend module's Vue calls: auth'd requests, realtime, page context, UI toolkit |
|
|
18
|
-
| `docs/07.
|
|
19
|
-
| `docs/08.interfaces/` | The contract reference for `@antelopejs/interface-dms`, one folder per domain: `core`, `auth`, `base`, `notifications`, `html-render` |
|
|
18
|
+
| `docs/07.interfaces/` | The contract reference for `@antelopejs/interface-dms`, one folder per domain: `core`, `auth`, `base`, `notifications`, `html-render` |
|
|
20
19
|
|
|
21
20
|
## Exact interface surfaces: don't memorize, look them up
|
|
22
21
|
|
|
@@ -37,7 +36,7 @@ Three ways to read a contract:
|
|
|
37
36
|
node "<antelopejs-plugin>/scripts/resolve-interface.mjs" show <scope>/interface-<name>
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
2. **The prose reference** — `docs/
|
|
39
|
+
2. **The prose reference** — `docs/07.interfaces/`, one folder per domain, with the whole subpath
|
|
41
40
|
map in its `index.md`.
|
|
42
41
|
|
|
43
42
|
3. **The sources shipped with this skill** — this workspace carries the interface package; read
|
package/skills/dms/SKILL.md
CHANGED
|
@@ -75,7 +75,7 @@ chatbox.
|
|
|
75
75
|
## Docs & exact interface surfaces (read for depth)
|
|
76
76
|
|
|
77
77
|
Long-form reference docs live in this package's `docs/` directory (shipped with the package; also
|
|
78
|
-
at the repo root), in
|
|
78
|
+
at the repo root), in seven numbered sections — the last, `docs/07.interfaces/`, is the contract
|
|
79
79
|
reference for `@antelopejs/interface-dms` domain by domain. DataTypes, component builder options, and auth
|
|
80
80
|
decorators are **versioned interface contracts** — look them up rather than hand-recalling; treat
|
|
81
81
|
skill examples as patterns, not gospel. See [REFERENCE.md](REFERENCE.md) for the docs map and the
|
|
@@ -55,10 +55,9 @@ AntelopeJS — see the **antelopejs** plugin's author/consume skills. The DMS-sp
|
|
|
55
55
|
`src/implementations/<name>/index.ts` in the module, **wire** with `ImplementInterface` in
|
|
56
56
|
`construct` (the lifecycle entry in [SKILL.md](SKILL.md)). Keep `/** @internal */` on the
|
|
57
57
|
`internal` namespace — the convention marking the registration surface as non-consumer API.
|
|
58
|
-
- **Expose** each directory index as an explicit `exports` entry
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
`import { … } from "@antelopejs/interface-<name>"`.
|
|
58
|
+
- **Expose** each directory index as an explicit `exports` entry; consumers resolve it with
|
|
59
|
+
`moduleResolution: bundler`, `node16` or `nodenext`. Consumers add the interface package to
|
|
60
|
+
`dependencies` and `import { … } from "@antelopejs/interface-<name>"`.
|
|
62
61
|
- Anything consumer-facing lives in the interface package; never re-export internal modules —
|
|
63
62
|
if a helper needs internal infrastructure, use the hook-setter indirection pattern the
|
|
64
63
|
existing modules use rather than exposing the internals. Runtime behaviour stays in the
|
|
@@ -76,7 +75,7 @@ AntelopeJS — see the **antelopejs** plugin's author/consume skills. The DMS-sp
|
|
|
76
75
|
3. **Scaffold the layout above**: `src/index.ts`, `src/pages/`, `src/routes/` (if it serves data),
|
|
77
76
|
`packages/interface-<name>/` + `src/implementations/<name>/` (only if it exposes one),
|
|
78
77
|
`frontend-vue/` (components registered from the root `dms.frontend.ts`), and the manifest
|
|
79
|
-
(`antelopeJs` block, plus the interface package's `exports
|
|
78
|
+
(`antelopeJs` block, plus the interface package's `exports`).
|
|
80
79
|
4. **Wire the basics**: `RegisterModule({ id, title, icon, … })`, one `@RegisterPage()` page,
|
|
81
80
|
the `AddFrontendModule` call. Add the `$dms_<name>.*` keys to **every** locale file under
|
|
82
81
|
`frontend-vue/i18n/locales/`.
|
|
@@ -25,7 +25,7 @@ defining the module's own interface, and the scaffolding checklist.
|
|
|
25
25
|
## The `package.json` manifest
|
|
26
26
|
|
|
27
27
|
The `antelopeJs` block is what makes it a DMS module ([REFERENCE.md](REFERENCE.md) has the full
|
|
28
|
-
manifest, including the `exports
|
|
28
|
+
manifest, including the `exports` entries for an interface subpath).
|
|
29
29
|
`implements` lists only the interfaces the module *provides* — the official modules keep it `[]`
|
|
30
30
|
when they provide none (`dms-lang`, `dms-saas`); consumed interfaces are plain `dependencies`
|
|
31
31
|
(no manifest field). Typical dependencies: `@antelopejs/dms` plus
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
|
-
import { mkdirSync } from "node:fs";
|
|
4
|
-
import { resolve } from "node:path";
|
|
5
|
-
|
|
6
|
-
const [url, theme = "custom", screenshots] = process.argv.slice(2);
|
|
7
|
-
if (!url)
|
|
8
|
-
throw new Error(
|
|
9
|
-
"Usage: node tests/theming-browser.mjs URL [custom|default] [screenshots]",
|
|
10
|
-
);
|
|
11
|
-
const session = "dms-theming-test";
|
|
12
|
-
const transitionWait = "500";
|
|
13
|
-
const browser = (...args) =>
|
|
14
|
-
execFileSync("agent-browser", ["--session", session, ...args], {
|
|
15
|
-
encoding: "utf8",
|
|
16
|
-
}).trim();
|
|
17
|
-
const evaluate = (expression) => JSON.parse(browser("eval", expression));
|
|
18
|
-
|
|
19
|
-
function inspectTheme() {
|
|
20
|
-
const root = getComputedStyle(document.documentElement);
|
|
21
|
-
const probe = document.createElement("span");
|
|
22
|
-
document.body.append(probe);
|
|
23
|
-
const colors = ["--ui-primary", "--ui-color-primary-600", "--ui-success"].map(
|
|
24
|
-
(token) => {
|
|
25
|
-
probe.style.backgroundColor = `var(${token})`;
|
|
26
|
-
return getComputedStyle(probe).backgroundColor;
|
|
27
|
-
},
|
|
28
|
-
);
|
|
29
|
-
probe.remove();
|
|
30
|
-
const background = (selector) =>
|
|
31
|
-
getComputedStyle(document.querySelector(selector)).backgroundColor;
|
|
32
|
-
const images = [...document.querySelectorAll("main img")].filter(
|
|
33
|
-
(image) => image.getClientRects().length,
|
|
34
|
-
);
|
|
35
|
-
return {
|
|
36
|
-
radius: root.getPropertyValue("--ui-radius").trim(),
|
|
37
|
-
font: root.getPropertyValue("--font-sans"),
|
|
38
|
-
accent: root.getPropertyValue("--dms-accent").trim(),
|
|
39
|
-
accentPalette: ["500", "400"].map((shade) =>
|
|
40
|
-
root.getPropertyValue(`--ui-color-primary-${shade}`).trim(),
|
|
41
|
-
),
|
|
42
|
-
config: document.querySelector("#config").textContent,
|
|
43
|
-
colors,
|
|
44
|
-
button: background("#primary"),
|
|
45
|
-
primary: background("#primary-switch"),
|
|
46
|
-
success: background("#success-switch"),
|
|
47
|
-
surface: background(".dms-card"),
|
|
48
|
-
logosLoaded:
|
|
49
|
-
images.length === 2 &&
|
|
50
|
-
images.every((image) => image.complete && image.naturalWidth > 0),
|
|
51
|
-
logos: images.map((image) => new URL(image.src).pathname),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function checkLogos(result, mode) {
|
|
56
|
-
assert.ok(result.logosLoaded, "logos loaded");
|
|
57
|
-
const logoRoot = theme === "custom" ? "/brand" : "/images/antelope-logo";
|
|
58
|
-
assert.deepEqual(result.logos, [
|
|
59
|
-
`${logoRoot}/${mode}.svg`,
|
|
60
|
-
`${logoRoot}/icon.svg`,
|
|
61
|
-
]);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function checkTheme(mode) {
|
|
65
|
-
const result = evaluate(`(${inspectTheme.toString()})()`);
|
|
66
|
-
const isCustom = theme === "custom";
|
|
67
|
-
assert.ok(result.radius.endsWith("rem"), "radius unit");
|
|
68
|
-
assert.equal(
|
|
69
|
-
Number.parseFloat(result.radius),
|
|
70
|
-
isCustom ? 0.5 : 0.25,
|
|
71
|
-
"radius",
|
|
72
|
-
);
|
|
73
|
-
assert.ok(result.font.includes(isCustom ? "Georgia" : "Geist"), "font");
|
|
74
|
-
assert.ok(
|
|
75
|
-
result.config.includes(isCustom ? "example" : "dms"),
|
|
76
|
-
"layer precedence",
|
|
77
|
-
);
|
|
78
|
-
assert.equal(result.button, result.colors[0], "primary action");
|
|
79
|
-
assert.equal(result.primary, result.colors[1], "primary switch shade");
|
|
80
|
-
assert.equal(
|
|
81
|
-
result.success,
|
|
82
|
-
result.colors[2],
|
|
83
|
-
"success switch semantic color",
|
|
84
|
-
);
|
|
85
|
-
const darkSurface = isCustom ? "rgb(36, 21, 54)" : "rgb(16, 17, 25)";
|
|
86
|
-
assert.equal(
|
|
87
|
-
result.surface,
|
|
88
|
-
mode === "dark" ? darkSurface : "rgb(255, 255, 255)",
|
|
89
|
-
);
|
|
90
|
-
assert.equal(
|
|
91
|
-
result.accent,
|
|
92
|
-
result.accentPalette[Number(mode === "dark")],
|
|
93
|
-
"glow accent",
|
|
94
|
-
);
|
|
95
|
-
checkLogos(result, mode);
|
|
96
|
-
console.log(`${theme}/${mode}: tokens, switches and logos passed`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function checkMode(mode) {
|
|
100
|
-
const modeCondition = `document.documentElement.classList.contains('dark') === ${mode === "dark"}`;
|
|
101
|
-
if (!evaluate(modeCondition)) browser("click", "#mode");
|
|
102
|
-
browser("wait", "--fn", modeCondition);
|
|
103
|
-
browser("wait", transitionWait);
|
|
104
|
-
checkTheme(mode);
|
|
105
|
-
browser("click", "#primary-switch");
|
|
106
|
-
browser(
|
|
107
|
-
"wait",
|
|
108
|
-
"--fn",
|
|
109
|
-
'document.querySelector("#primary-switch").getAttribute("aria-checked") === "false"',
|
|
110
|
-
);
|
|
111
|
-
browser("click", "#primary-switch");
|
|
112
|
-
browser("wait", transitionWait);
|
|
113
|
-
checkTheme(mode);
|
|
114
|
-
if (!screenshots) return;
|
|
115
|
-
mkdirSync(screenshots, { recursive: true });
|
|
116
|
-
browser("screenshot", resolve(screenshots, `${theme}-${mode}.png`));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
browser("open", url);
|
|
121
|
-
browser("set", "viewport", "1280", "900", "2");
|
|
122
|
-
browser(
|
|
123
|
-
"wait",
|
|
124
|
-
"--fn",
|
|
125
|
-
'document.querySelector("main")?.dataset.ready === "true"',
|
|
126
|
-
);
|
|
127
|
-
for (const mode of ["light", "dark"]) checkMode(mode);
|
|
128
|
-
} finally {
|
|
129
|
-
browser("close");
|
|
130
|
-
}
|