@synopackageland/templates 0.42.1 → 0.43.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 +15 -0
- package/README.md +30 -16
- package/package.json +2 -2
- package/templates/_shared/AGENTS.md +8 -2
- package/templates/_shared/package.json +1 -1
- package/templates/_shared/pnpm-workspace.yaml +1 -0
- package/templates/compose/dsm-package.yaml +1 -1
- package/templates/native-go/README.md +7 -1
- package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +1 -1
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/go.sum +2 -2
- package/templates/native-go/i18n/glossary.json +4 -4
- package/templates/native-go/i18n/messages/de.json +1 -1
- package/templates/native-go/i18n/messages/en.json +1 -1
- package/templates/native-go/i18n/messages/es.json +1 -1
- package/templates/native-go/i18n/messages/fr.json +1 -1
- package/templates/native-go/i18n/messages/it.json +1 -1
- package/templates/native-go/i18n/messages/ja.json +1 -1
- package/templates/native-go/i18n/messages/ko.json +1 -1
- package/templates/native-go/i18n/messages/zh-CN.json +1 -1
- package/templates/native-go/i18n/messages/zh-TW.json +1 -1
- package/templates/native-go/ui/app.css +2 -1
- package/templates/native-go/ui/app.js +8 -4
- package/templates/native-node/README.md +1 -1
- package/templates/native-node/dsm-package.yaml +1 -1
- package/templates/native-python/dsm-package.yaml +1 -1
- package/templates/native-rust/README.md +3 -0
- package/templates/native-rust/backend/Cargo.lock +8 -8
- package/templates/native-rust/backend/Cargo.toml +1 -1
- package/templates/{native-go-delegate → overlays/native-go-delegate}/frontend/test/capability-panels.test.ts +6 -3
- package/templates/overlays/native-go-jobs/frontend/test/background-shell.test.ts +37 -0
- package/templates/{native-go-vue → overlays/native-go-vue}/README.md +16 -6
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/DESIGN.md +7 -3
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/package.json +2 -2
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/App.vue +7 -4
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/de.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/en.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/es.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/fr.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/it.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/ja.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/ko.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/zh-CN.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n/zh-TW.json +4 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/apps.test.ts +49 -7
- package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/shell-i18n.test.ts +6 -4
- package/templates/{native-node-vue → overlays/native-node-vue}/README.md +12 -4
- package/templates/{native-python-vue → overlays/native-python-vue}/README.md +12 -4
- package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/Cargo.lock +8 -8
- package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/Cargo.toml +1 -1
- package/templates/{native-rust-vue → overlays/native-rust-vue}/README.md +12 -4
- package/templates/_shared/pnpm-lock.yaml +0 -1636
- package/templates/native-go-jobs/frontend/test/background-shell.test.ts +0 -19
- package/templates/native-go-vue/frontend/pnpm-lock.yaml +0 -2269
- package/templates/native-node/backend/pnpm-lock.yaml +0 -207
- /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/cmd/background-worker/main.go +0 -0
- /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate.go +0 -0
- /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate_on.go +0 -0
- /package/templates/{native-go-delegate → overlays/native-go-delegate}/backend/internal/app/delegate_routes_test.go +0 -0
- /package/templates/{native-go-delegate → overlays/native-go-delegate}/frontend/src/CapabilityPanels.vue +0 -0
- /package/templates/{native-go-jobs → overlays/native-go-jobs}/backend/internal/app/background_on.go +0 -0
- /package/templates/{native-go-jobs → overlays/native-go-jobs}/backend/internal/app/background_routes_test.go +0 -0
- /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/backend/internal/app/executor.go +0 -0
- /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/backend/internal/app/executor_test.go +0 -0
- /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/frontend/src/ExecutorGate.vue +0 -0
- /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/frontend/test/executor-gate.test.ts +0 -0
- /package/templates/{native-go-root-ops → overlays/native-go-root-ops}/root/whoami.sh +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/pnpm-workspace.yaml +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/CapabilityPanels.vue +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/ExecutorGate.vue +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/i18n.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/main.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/src/style.css +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/context.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/module-bundle.test.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/native-controls.test.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/test/page-spacing.test.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/tsconfig.json +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/frontend/vite.config.ts +0 -0
- /package/templates/{native-go-vue → overlays/native-go-vue}/gitignore +0 -0
- /package/templates/{native-node-delegate → overlays/native-node-delegate}/backend/src/delegate.ts +0 -0
- /package/templates/{native-node-delegate → overlays/native-node-delegate}/backend/test/delegate.test.ts +0 -0
- /package/templates/{native-node-delegate → overlays/native-node-delegate}/operations.patch.json +0 -0
- /package/templates/{native-node-jobs → overlays/native-node-jobs}/backend/src/jobs.ts +0 -0
- /package/templates/{native-node-jobs → overlays/native-node-jobs}/backend/test/jobs.test.ts +0 -0
- /package/templates/{native-node-jobs → overlays/native-node-jobs}/operations.patch.json +0 -0
- /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/backend/src/root-ops.ts +0 -0
- /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/backend/test/root-ops.test.ts +0 -0
- /package/templates/{native-node-root-ops → overlays/native-node-root-ops}/operations.patch.json +0 -0
- /package/templates/{native-node-vue → overlays/native-node-vue}/gitignore +0 -0
- /package/templates/{native-python-delegate → overlays/native-python-delegate}/backend/app/delegate.py +0 -0
- /package/templates/{native-python-delegate → overlays/native-python-delegate}/backend/tests/test_delegate.py +0 -0
- /package/templates/{native-python-delegate → overlays/native-python-delegate}/operations.patch.json +0 -0
- /package/templates/{native-python-jobs → overlays/native-python-jobs}/backend/app/jobs.py +0 -0
- /package/templates/{native-python-jobs → overlays/native-python-jobs}/backend/tests/test_jobs.py +0 -0
- /package/templates/{native-python-jobs → overlays/native-python-jobs}/operations.patch.json +0 -0
- /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/backend/app/root_ops.py +0 -0
- /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/backend/tests/test_root_ops.py +0 -0
- /package/templates/{native-python-root-ops → overlays/native-python-root-ops}/operations.patch.json +0 -0
- /package/templates/{native-python-vue → overlays/native-python-vue}/gitignore +0 -0
- /package/templates/{native-rust-delegate → overlays/native-rust-delegate}/backend/src/delegate.rs +0 -0
- /package/templates/{native-rust-delegate → overlays/native-rust-delegate}/operations.patch.json +0 -0
- /package/templates/{native-rust-jobs → overlays/native-rust-jobs}/backend/src/jobs.rs +0 -0
- /package/templates/{native-rust-jobs → overlays/native-rust-jobs}/operations.patch.json +0 -0
- /package/templates/{native-rust-root-ops → overlays/native-rust-root-ops}/backend/src/root_ops.rs +0 -0
- /package/templates/{native-rust-root-ops → overlays/native-rust-root-ops}/operations.patch.json +0 -0
- /package/templates/{native-rust-vue → overlays/native-rust-vue}/gitignore +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.43.0
|
|
4
|
+
|
|
5
|
+
- Move Vue and capability layers under `templates/overlays/`; keep six main templates.
|
|
6
|
+
- Let init resolve compatible SDK/UI releases and its own CLI version from shipped defaults.
|
|
7
|
+
- Refresh offline defaults and remove shipped npm lockfiles; first install creates them.
|
|
8
|
+
- Preserve release checksums and document Go/Rust dependency initialization.
|
|
9
|
+
|
|
10
|
+
## 0.42.2
|
|
11
|
+
|
|
12
|
+
- New Apps get no header Refresh. The Vue templates leave `AppShell`'s `#actions` empty (Sign out only with standalone login), so the shell draws no bar above the page; the plain UI's title row drops its Refresh button
|
|
13
|
+
- Data stays fresh without it: reopening the window reads the status, panels and portal again, the Vue status page reads again each time it is shown, and a failed read offers Retry beside its error
|
|
14
|
+
- Delegate templates keep their Retry inside the capability's own error Callout
|
|
15
|
+
- READMEs, `DESIGN.md` and `AGENTS.md` say `#actions` is for real page actions (such as Add), never a Refresh
|
|
16
|
+
- Drop the unused `refresh`, `greeting`, `save` and `saved` messages; error texts no longer ask the user to refresh
|
|
17
|
+
|
|
3
18
|
## 0.42.1
|
|
4
19
|
|
|
5
20
|
- The commented `backup` example in the native and binary `dsm-package.yaml` says online backup reads SQLite in place, and shows the optional `exclude` list of data-folder globs left out of the archive (SDK 0.53.35, CLI 0.53.13)
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ daemon:
|
|
|
24
24
|
window_seconds: 300
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Templates
|
|
27
|
+
Templates carry offline fallback dependency versions; init resolves compatible current releases.
|
|
28
28
|
Use a CLI that supports executor manifest format 1. The Vue `AppShell` shows a
|
|
29
29
|
non-blocking **Reload** notice when an upgrade replaced the UI an open page
|
|
30
30
|
loaded. Go Apps select
|
|
@@ -50,15 +50,20 @@ An opt-in [native UI plus DSM console example](examples/dual-entry-console/READM
|
|
|
50
50
|
shows the `console` declaration for an App that wraps a web service behind the
|
|
51
51
|
identity gateway and keeps its own settings in an administrator-only DSM window.
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
The first level of `templates/` contains the six main templates, `_shared/`,
|
|
54
|
+
and `overlays/`. All Vue, jobs, delegate and root-ops layers live under `overlays/`.
|
|
55
|
+
The shipped manifest versions are fallback defaults; init rewrites them through its
|
|
56
|
+
existing substitution pass. SDK/UI/CLI patches do not require a templates release.
|
|
57
|
+
|
|
58
|
+
| Template or overlay | What it adds |
|
|
54
59
|
| --- | --- |
|
|
55
60
|
| `native-go` | Base: `dsm-package.yaml`, Go module (`backend/cmd/{app,background-worker}`, `backend/internal/app`, `backend/internal/api/permissions.json`), plain `ui/`, i18n |
|
|
56
|
-
| `native-go-vue` | Vue shell in `frontend/` (`App.vue`, `main.ts`, app i18n, `CapabilityPanels.vue`, `ExecutorGate.vue`) |
|
|
57
|
-
| `native-go-jobs` | Background job routes in `internal/app` and a shell lifecycle test |
|
|
58
|
-
| `native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
|
|
59
|
-
| `native-go-root-ops` | The SDK's executor routes and `root.run` in `internal/app`, an example `root/whoami.sh`, and the Vue `ExecutorGate.vue` that holds the pages until the executor is approved |
|
|
61
|
+
| `overlays/native-go-vue` | Vue shell in `frontend/` (`App.vue`, `main.ts`, app i18n, `CapabilityPanels.vue`, `ExecutorGate.vue`) |
|
|
62
|
+
| `overlays/native-go-jobs` | Background job routes in `internal/app` and a shell lifecycle test |
|
|
63
|
+
| `overlays/native-go-delegate` | Delegate routes, the delegate background worker, the delegate `CapabilityPanels.vue` |
|
|
64
|
+
| `overlays/native-go-root-ops` | The SDK's executor routes and `root.run` in `internal/app`, an example `root/whoami.sh`, and the Vue `ExecutorGate.vue` that holds the pages until the executor is approved |
|
|
60
65
|
| `native-python` | Base: `dsm-package.yaml` (`backend.runtime: python`), the App in `backend/app` (`routes.py`, stub capability modules, `permissions.json`), unittest tests |
|
|
61
|
-
| `native-node` | Base: `dsm-package.yaml` (`backend.runtime: node`), TypeScript in `backend/src` compiled into `backend/app`, node:test tests,
|
|
66
|
+
| `native-node` | Base: `dsm-package.yaml` (`backend.runtime: node`), TypeScript in `backend/src` compiled into `backend/app`, node:test tests, an install-generated lockfile |
|
|
62
67
|
| `native-rust` | Base: `dsm-package.yaml` (`backend.runtime: rust`, `methods`), the Cargo project in `backend` on the `syno-pkg-land-app` crate, `Cargo.lock`, `rust-toolchain.toml` |
|
|
63
68
|
| `native-{python,node,rust}-{jobs,root-ops,delegate}` | The capability's example module, replacing the base's stub, with its tests |
|
|
64
69
|
| `native-{python,node,rust}-vue` | The README and `.gitignore` of the Vue shell |
|
|
@@ -70,8 +75,8 @@ Overlays are copied over `native-go` in the order root-ops, vue, jobs, delegate.
|
|
|
70
75
|
An overlay may replace `internal/app/*_none.go` (the CLI deletes the matching
|
|
71
76
|
`_none.go` file); nothing outside `internal/app` and the Vue shell differs.
|
|
72
77
|
The Python, Node.js and Rust templates borrow the Go template's UI: `ui/` and
|
|
73
|
-
`i18n/` from `native-go`, `frontend/` from `native-go-vue` (and the jobs and
|
|
74
|
-
delegate overlays' frontend files), `root/whoami.sh` from `native-go-root-ops`.
|
|
78
|
+
`i18n/` from `native-go`, `frontend/` from `overlays/native-go-vue` (and the jobs and
|
|
79
|
+
delegate overlays' frontend files), `root/whoami.sh` from `overlays/native-go-root-ops`.
|
|
75
80
|
Their overlays are copied in the order vue, root-ops, jobs, delegate; delegate
|
|
76
81
|
also makes `app.status` and `report.save` `authenticated`, and the Rust
|
|
77
82
|
manifest gets the overlays' methods. `init` copies the App SDK into
|
|
@@ -84,13 +89,22 @@ calls each one from the generated script of the same name (`synopkgland skill sh
|
|
|
84
89
|
The placeholders `__PACKAGE__` (also the Go module path), `__DISPLAY_NAME__` and
|
|
85
90
|
`__BACKGROUND_ENABLED__` are substituted by `init`.
|
|
86
91
|
|
|
87
|
-
`
|
|
88
|
-
the
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
`init` defaults to `native-go` with Vue. The CLI writes its own `~` version,
|
|
93
|
+
selects the newest stable, non-deprecated SDK and UI releases in its declared
|
|
94
|
+
compatibility ranges, and writes the same exact SDK version to npm and the backend.
|
|
95
|
+
UI stays in the supported minor line. Registry errors or unavailable compatible
|
|
96
|
+
releases print one hint and use the shipped defaults; there is no short custom timeout.
|
|
97
|
+
Templates are still read from the installed package, never downloaded by `init`.
|
|
98
|
+
The CLI compatibility ranges live in `src/init-versions.ts`.
|
|
99
|
+
|
|
100
|
+
Templates do not ship npm lockfiles. Run `pnpm install` in the project root and
|
|
101
|
+
frontend (and the Node backend) to create them, then commit them and use
|
|
102
|
+
`pnpm install --frozen-lockfile` for subsequent installs. For Go, run
|
|
103
|
+
`(cd backend && go mod tidy)` before check/build. When init selects a newer Rust
|
|
104
|
+
SDK tag, run `(cd backend && cargo generate-lockfile)` before check/build;
|
|
105
|
+
the old release's Cargo.lock is removed rather than relabeling its commit.
|
|
106
|
+
`SYNOPKGLAND_SDK_DIR` still overrides the generated SDK dependency for local development.
|
|
107
|
+
|
|
94
108
|
Read the SDK's published peer dependency range with
|
|
95
109
|
`npm view @synopackageland/sdk peerDependencies` rather than overriding it. Tests use jsdom 30 for UI floating-layer styles.
|
|
96
110
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/templates",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Project templates for synopkgland init: native-go, native-python, native-node and native-rust (plain or Vue, with
|
|
3
|
+
"version": "0.43.0",
|
|
4
|
+
"description": "Project templates for synopkgland init: native-go, native-python, native-node and native-rust (plain or Vue, with layers in templates/overlays), binary and compose.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -17,12 +17,18 @@ Only a confirmed refusal (signed out, expired session, not an administrator)
|
|
|
17
17
|
shows the sign-in page or a `@synopackageland/ui` Dialog; loading text inside a
|
|
18
18
|
section is fine.
|
|
19
19
|
|
|
20
|
+
Do not add a header Refresh. Re-read data when the window is shown again
|
|
21
|
+
(`ctx.reopen`) and when a page is shown; a failed read offers Retry beside its
|
|
22
|
+
error. `AppShell`'s `#actions` is for real page actions (such as Add); with
|
|
23
|
+
nothing in it the shell draws no bar. A section that needs a manual re-read
|
|
24
|
+
gets its own action in that section.
|
|
25
|
+
|
|
20
26
|
Everything below holds for every native backend language; the backend
|
|
21
27
|
sections at the end name each language's files, types and test commands.
|
|
22
28
|
|
|
23
29
|
From the project root, run `synopkgland check --json`,
|
|
24
30
|
`synopkgland build --json`, then `synopkgland inspect <spk> --json` on the emitted SPK.
|
|
25
|
-
For Vue, first run `pnpm install --
|
|
31
|
+
For Vue, first run `pnpm install --prod=false` (creates its lockfile) and `pnpm run build` in frontend. Run its tests only if the user chose tests.
|
|
26
32
|
Do not connect to or change a NAS without explicit task authorization.
|
|
27
33
|
|
|
28
34
|
## Optional testing
|
|
@@ -402,7 +408,7 @@ their capabilities with `synopkgland init --with`.
|
|
|
402
408
|
`new AppError(code, message)`, `AppError.badRequest(message)`. Call services
|
|
403
409
|
through `service(ctx, op, params)` (`service.ts`), which passes the runtime's
|
|
404
410
|
refusals on; a bare `ctx.runtime` refusal would reach the browser as `internal`.
|
|
405
|
-
- Test with `(cd backend && pnpm install --
|
|
411
|
+
- Test with `(cd backend && pnpm install --prod=false && pnpm test && pnpm run typecheck)`; `test/support.ts`'s
|
|
406
412
|
`call` plays the runtime.
|
|
407
413
|
|
|
408
414
|
## Rust backend
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"e2e:ai": "node --env-file-if-exists=.env node_modules/@synopackageland/cli/dist/e2e/dsm.js tunnel -- e2e run --config e2e.ai.config.ts tests/e2e/action.ai.e2e.ts"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@synopackageland/cli": "~0.
|
|
14
|
+
"@synopackageland/cli": "~0.53.18",
|
|
15
15
|
"@e2e-dev/web": "^0.14.0",
|
|
16
16
|
"e2e": "^0.19.0"
|
|
17
17
|
},
|
|
@@ -23,7 +23,7 @@ compose:
|
|
|
23
23
|
web: {service: web, port: 8080, health: {path: /, status: 200}}
|
|
24
24
|
network: {egress: isolated}
|
|
25
25
|
identity_gateway:
|
|
26
|
-
sdk: 0.53.
|
|
26
|
+
sdk: 0.53.42
|
|
27
27
|
mode: none
|
|
28
28
|
listen: {http: 28000}
|
|
29
29
|
# Web Apps default to new-page through the shared app-launch resolver.
|
|
@@ -205,7 +205,10 @@ the new version; `synopkgland check` refuses mismatched versions.
|
|
|
205
205
|
`ui/app.js` must register `window.DsmPackageApps[<package>].mount(root, ctx)`
|
|
206
206
|
(the template shows how, using `document.currentScript.dataset.package`).
|
|
207
207
|
`ctx.call(method, params)` is the only transport. `ctx.reopen(fn)` runs `fn`
|
|
208
|
-
whenever DSM shows the window again and returns an idempotent unsubscribe function.
|
|
208
|
+
whenever DSM shows the window again and returns an idempotent unsubscribe function.
|
|
209
|
+
The template re-reads its status there instead of showing a Refresh button; a
|
|
210
|
+
failed read shows Retry beside its error. Keep header buttons for real page
|
|
211
|
+
actions, such as Add. Scope your CSS under your own root class:
|
|
209
212
|
every DSM app shares one page.
|
|
210
213
|
|
|
211
214
|
Plain JS and Vue receive the same `ctx.host` adapter. `ctx.host.platform()`
|
|
@@ -495,3 +498,6 @@ Keep `synology/backend/`, `synology/i18n/messages/`, `synology/operations.json`
|
|
|
495
498
|
the local/ctl tests: the entry gate still needs the backend and message catalogs.
|
|
496
499
|
Read `synopkgland skill show upstream-fork` and
|
|
497
500
|
`synopkgland skill show orchestrator` for the wrapper workflow.
|
|
501
|
+
|
|
502
|
+
Before the first check/build, install the project dependencies with `pnpm install`
|
|
503
|
+
and run `(cd backend && go mod tidy)` to populate checksums for the selected SDK.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
github.com/synopackageland/syno-pkg-land-sdk v0.53.
|
|
2
|
-
github.com/synopackageland/syno-pkg-land-sdk v0.53.
|
|
1
|
+
github.com/synopackageland/syno-pkg-land-sdk v0.53.42 h1:qhbKCjU6ME8OpuMgpz03LHs3KGL66xSwDRvePGWlyEU=
|
|
2
|
+
github.com/synopackageland/syno-pkg-land-sdk v0.53.42/go.mod h1:mmtgnyafLwci1588LJFpRIsWflHwjaHJoDm7grXFh8A=
|
|
3
3
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
|
4
4
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
|
@@ -163,9 +163,7 @@
|
|
|
163
163
|
"es": "Actualizar",
|
|
164
164
|
"it": "Aggiorna"
|
|
165
165
|
},
|
|
166
|
-
"keys": [
|
|
167
|
-
"app.refresh"
|
|
168
|
-
]
|
|
166
|
+
"keys": []
|
|
169
167
|
},
|
|
170
168
|
{
|
|
171
169
|
"id": "retry",
|
|
@@ -181,7 +179,9 @@
|
|
|
181
179
|
"es": "Volver a intentar",
|
|
182
180
|
"it": "Riprova"
|
|
183
181
|
},
|
|
184
|
-
"keys": [
|
|
182
|
+
"keys": [
|
|
183
|
+
"app.retry"
|
|
184
|
+
]
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
187
|
"id": "back",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"app.
|
|
2
|
+
"app.retry": "Neuer Versuch",
|
|
3
3
|
"app.title": "Es funktioniert",
|
|
4
4
|
"error.admin_required": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen",
|
|
5
5
|
"error.app_privilege_denied": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"app.
|
|
2
|
+
"app.retry": "Retry",
|
|
3
3
|
"app.title": "It works",
|
|
4
4
|
"error.admin_required": "Sorry, this user account has not been assigned proper privileges to perform this action",
|
|
5
5
|
"error.app_privilege_denied": "Sorry, this user account has not been assigned proper privileges to perform this action",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"app.
|
|
2
|
+
"app.retry": "Volver a intentar",
|
|
3
3
|
"app.title": "Funciona",
|
|
4
4
|
"error.admin_required": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción",
|
|
5
5
|
"error.app_privilege_denied": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"app.
|
|
2
|
+
"app.retry": "Réessayer",
|
|
3
3
|
"app.title": "Ça fonctionne",
|
|
4
4
|
"error.admin_required": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action",
|
|
5
5
|
"error.app_privilege_denied": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"app.
|
|
2
|
+
"app.retry": "Riprova",
|
|
3
3
|
"app.title": "Funziona",
|
|
4
4
|
"error.admin_required": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione",
|
|
5
5
|
"error.app_privilege_denied": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione",
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
background: var(--ui-surface);
|
|
35
35
|
}
|
|
36
36
|
.dsmapp *, .dsmapp *::before, .dsmapp *::after { box-sizing: inherit; }
|
|
37
|
-
.dsmapp-header { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-3); }
|
|
38
37
|
.dsmapp h1 { margin: 0 0 var(--ui-space-1); font-size: var(--ui-font-size-title); font-weight: 600; }
|
|
39
38
|
.dsmapp-secondary {
|
|
40
39
|
height: var(--ui-control-md); padding: 0 var(--ui-space-3); border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm);
|
|
@@ -55,6 +54,8 @@
|
|
|
55
54
|
.dsmapp-form button:disabled { opacity: 0.6; cursor: default; }
|
|
56
55
|
.dsmapp-note { margin: 0; color: var(--ui-text-secondary); font-size: var(--ui-font-size-sm); }
|
|
57
56
|
.dsmapp-note[hidden] { display: none; }
|
|
57
|
+
.dsmapp-message-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3); }
|
|
58
|
+
.dsmapp-message-row .dsmapp-message { flex: 1 1 auto; }
|
|
58
59
|
.dsmapp-message { min-height: var(--ui-line-height); color: var(--ui-danger-text); }
|
|
59
60
|
.dsmapp-facts { display: grid; grid-template-columns: fit-content(40%) minmax(0, 1fr); gap: var(--ui-space-1) var(--ui-space-4); margin: 0; }
|
|
60
61
|
.dsmapp-facts dt { color: var(--ui-text-secondary); }
|
|
@@ -36,14 +36,16 @@
|
|
|
36
36
|
function mount(root, ctx) {
|
|
37
37
|
var t = ctx.t;
|
|
38
38
|
var status = el("dl", { class: "dsmapp-facts" });
|
|
39
|
-
var refreshButton = el("button", { type: "button", class: "dsmapp-secondary", text: t("app.refresh") });
|
|
40
39
|
var message = el("p", { class: "dsmapp-message", role: "status" });
|
|
40
|
+
// Shown only after a failed read; the App re-reads on reopen, so no header Refresh.
|
|
41
|
+
var retryButton = el("button", { type: "button", class: "dsmapp-secondary", text: t("app.retry") });
|
|
42
|
+
retryButton.hidden = true;
|
|
41
43
|
var portal = ctx.portal ? el("section", { class: "dsmapp-portal" }) : null;
|
|
42
44
|
|
|
43
45
|
root.classList.add("dsmapp");
|
|
44
46
|
root.replaceChildren(
|
|
45
|
-
el("
|
|
46
|
-
message,
|
|
47
|
+
el("h1", { text: t("app.title") }),
|
|
48
|
+
el("div", { class: "dsmapp-message-row" }, [message, retryButton]),
|
|
47
49
|
el("h2", { text: t("status.heading") }),
|
|
48
50
|
status
|
|
49
51
|
);
|
|
@@ -54,10 +56,12 @@
|
|
|
54
56
|
var code = (error && error.code) || "internal";
|
|
55
57
|
var text = t("error." + code);
|
|
56
58
|
message.textContent = text === "error." + code ? (error && error.message) || t("error.internal") : text;
|
|
59
|
+
retryButton.hidden = false;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
function refresh() {
|
|
60
63
|
message.textContent = "";
|
|
64
|
+
retryButton.hidden = true;
|
|
61
65
|
ctx.call("app.status").then(function (data) {
|
|
62
66
|
status.replaceChildren();
|
|
63
67
|
[[t("status.user"), data.admin ? t("status.userAdmin", { user: data.user }) : data.user],
|
|
@@ -73,7 +77,7 @@
|
|
|
73
77
|
}).catch(showError);
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
|
|
80
|
+
retryButton.addEventListener("click", refresh);
|
|
77
81
|
|
|
78
82
|
ctx.reopen(refresh);
|
|
79
83
|
refresh();
|
|
@@ -51,7 +51,7 @@ run `synopkgland ctl generate`.
|
|
|
51
51
|
Needs Node.js 20 or later with `synopkgland` installed. The SPK depends on DSM's **Node.js v20** package (INFO `install_dep_packages`).
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
(cd backend && pnpm install --
|
|
54
|
+
(cd backend && pnpm install --prod=false && pnpm test && pnpm run build) # method tests, then app/*.js
|
|
55
55
|
synopkgland ctl generate
|
|
56
56
|
synopkgland check
|
|
57
57
|
synopkgland build # → dist/__PACKAGE__-0.1.0-0001-{x86_64,aarch64}.spk
|
|
@@ -225,3 +225,6 @@ Draft writes require a non-mutating preview and explicit human confirmation.
|
|
|
225
225
|
Long operations use the existing job flow; tools own polling and pagination.
|
|
226
226
|
|
|
227
227
|
Use a matching SDK/CLI/templates release containing the registry support.
|
|
228
|
+
|
|
229
|
+
After init selects a new SDK tag, run `(cd backend && cargo generate-lockfile)`
|
|
230
|
+
before check/build, then commit the generated Cargo.lock.
|
|
@@ -14,15 +14,15 @@ dependencies = [
|
|
|
14
14
|
|
|
15
15
|
[[package]]
|
|
16
16
|
name = "itoa"
|
|
17
|
-
version = "1.0.
|
|
17
|
+
version = "1.0.19"
|
|
18
18
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
19
|
-
checksum = "
|
|
19
|
+
checksum = "3bd1574e617a9a6c1f8f8181bd7e841e1f20e4277607ef28945765188d6284d4"
|
|
20
20
|
|
|
21
21
|
[[package]]
|
|
22
22
|
name = "libc"
|
|
23
|
-
version = "0.2.
|
|
23
|
+
version = "0.2.191"
|
|
24
24
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
25
|
-
checksum = "
|
|
25
|
+
checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
|
|
26
26
|
|
|
27
27
|
[[package]]
|
|
28
28
|
name = "memchr"
|
|
@@ -93,9 +93,9 @@ dependencies = [
|
|
|
93
93
|
|
|
94
94
|
[[package]]
|
|
95
95
|
name = "syn"
|
|
96
|
-
version = "3.0.
|
|
96
|
+
version = "3.0.10"
|
|
97
97
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
98
|
-
checksum = "
|
|
98
|
+
checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79"
|
|
99
99
|
dependencies = [
|
|
100
100
|
"proc-macro2",
|
|
101
101
|
"quote",
|
|
@@ -104,8 +104,8 @@ dependencies = [
|
|
|
104
104
|
|
|
105
105
|
[[package]]
|
|
106
106
|
name = "syno-pkg-land-app"
|
|
107
|
-
version = "0.53.
|
|
108
|
-
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.53.
|
|
107
|
+
version = "0.53.42"
|
|
108
|
+
source = "git+https://github.com/synopackageland/syno-pkg-land-sdk?tag=v0.53.42#02d5b526c852b3bd30e4dc9031414c9907fadb57"
|
|
109
109
|
dependencies = [
|
|
110
110
|
"libc",
|
|
111
111
|
"serde",
|
|
@@ -9,7 +9,7 @@ libc = "0.2"
|
|
|
9
9
|
serde = { version = "1", features = ["derive"] }
|
|
10
10
|
serde_json = "1"
|
|
11
11
|
# The SDK version is the tag; `synopkgland check` reads it from Cargo.lock.
|
|
12
|
-
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.53.
|
|
12
|
+
syno-pkg-land-app = { git = "https://github.com/synopackageland/syno-pkg-land-sdk", tag = "v0.53.42" }
|
|
13
13
|
|
|
14
14
|
[profile.release]
|
|
15
15
|
# A handler panic becomes an "internal" reply; abort would end the App without one.
|
|
@@ -102,7 +102,8 @@ test('the app mount forwards ctx.executor to administrator setup only',async()=>
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
})
|
|
105
|
-
|
|
105
|
+
// No header Refresh: reopening the App reloads the save destinations.
|
|
106
|
+
test('reopening the App reloads the save destinations',async()=>{
|
|
106
107
|
const call=vi.fn(async(method:string)=>{
|
|
107
108
|
if(method==='app.status')return {package:'DelegateApp',version:'1',user:'alice',admin:false}
|
|
108
109
|
if(method==='delegate.status')return {state:'ready',disabled:false,lifetime:'until-revoked',destinations:['save']}
|
|
@@ -112,11 +113,13 @@ test('the header Refresh reloads the save destinations',async()=>{
|
|
|
112
113
|
throw {code:'unknown_method'}
|
|
113
114
|
})
|
|
114
115
|
const root=document.createElement('div');document.body.append(root)
|
|
115
|
-
const
|
|
116
|
+
const reopen:Array<()=>void>=[]
|
|
117
|
+
const app=mount(root,dsmWindow({call,reopen(fn:()=>void){reopen.push(fn);return ()=>{}}}))
|
|
116
118
|
cleanup.push(()=>{app.unmount();root.remove()});await settle()
|
|
117
119
|
const reads=()=>call.mock.calls.filter(([method])=>method==='delegate.destination').length
|
|
118
120
|
const before=reads();expect(before).toBeGreaterThan(0)
|
|
119
|
-
|
|
121
|
+
expect([...root.querySelectorAll('button')].some(n=>n.textContent?.trim()==='Refresh')).toBe(false)
|
|
122
|
+
reopen.forEach(fn=>fn());await settle()
|
|
120
123
|
expect(reads()).toBeGreaterThan(before)
|
|
121
124
|
})
|
|
122
125
|
test('the panels show a skeleton while the delegate status loads',async()=>{
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import {expect,test,vi} from 'vitest'
|
|
3
|
+
import {nextTick} from 'vue'
|
|
4
|
+
import {mount} from '../src/main'
|
|
5
|
+
import {dsmWindow} from './context'
|
|
6
|
+
async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}}
|
|
7
|
+
test('a jobs project opens its shell without starting a job',async()=>{
|
|
8
|
+
const call=vi.fn(async(method:string)=>{
|
|
9
|
+
if(method==='app.status')return {package:'Jobs',version:'1',user:'alice',admin:false}
|
|
10
|
+
throw {code:'unknown_method'}
|
|
11
|
+
})
|
|
12
|
+
const root=document.createElement('div');document.body.append(root)
|
|
13
|
+
const app=mount(root,dsmWindow({call}))
|
|
14
|
+
try{
|
|
15
|
+
await settle()
|
|
16
|
+
expect(root.querySelector('[data-app-status]')).not.toBeNull()
|
|
17
|
+
expect(call.mock.calls.some(([method])=>method.startsWith('bg.'))).toBe(false)
|
|
18
|
+
}finally{app.unmount();root.remove()}
|
|
19
|
+
})
|
|
20
|
+
// No header Refresh: showing the status page again reads its status again.
|
|
21
|
+
test('returning to the status page reads its status again',async()=>{
|
|
22
|
+
const call=vi.fn(async(method:string)=>{
|
|
23
|
+
if(method==='app.status')return {package:'Jobs',version:'1',user:'alice',admin:false}
|
|
24
|
+
throw {code:'unknown_method'}
|
|
25
|
+
})
|
|
26
|
+
const root=document.createElement('div');document.body.append(root)
|
|
27
|
+
const app=mount(root,dsmWindow({call}))
|
|
28
|
+
try{
|
|
29
|
+
await settle()
|
|
30
|
+
const reads=()=>call.mock.calls.filter(([method])=>method==='app.status').length
|
|
31
|
+
const item=(name:string)=>[...root.querySelectorAll<HTMLElement>('button')].find(n=>n.textContent?.trim()===name)!
|
|
32
|
+
item('Background jobs').click();await settle()
|
|
33
|
+
const before=reads()
|
|
34
|
+
item('Status').click();await settle()
|
|
35
|
+
expect(reads()).toBeGreaterThan(before)
|
|
36
|
+
}finally{app.unmount();root.remove()}
|
|
37
|
+
})
|
|
@@ -37,13 +37,12 @@ See the [fork guide](https://github.com/synopackageland/syno-pkg-land-templates#
|
|
|
37
37
|
|
|
38
38
|
```sh
|
|
39
39
|
cd frontend
|
|
40
|
-
pnpm install --
|
|
40
|
+
pnpm install --prod=false
|
|
41
41
|
pnpm test
|
|
42
42
|
pnpm run build
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
The base app reads package status
|
|
46
|
-
`ctx.call`. Each window has its own Vue mount, request state and host
|
|
45
|
+
The base app reads package status through `ctx.call`. Each window has its own Vue mount, request state and host
|
|
47
46
|
subscriptions; unmount disposes subscriptions and ignores late responses.
|
|
48
47
|
|
|
49
48
|
The build emits `app.module.js`, `app.css` and any lazy chunks. The entry
|
|
@@ -94,7 +93,7 @@ SDK's light default in place.
|
|
|
94
93
|
|
|
95
94
|
Use the installed `@synopackageland/ui` and its declared compatible patch range.
|
|
96
95
|
`App.vue` lays the shell out with the SDK's `AppShell` (`@synopackageland/sdk/vue`):
|
|
97
|
-
`pages` from `shellPages`,
|
|
96
|
+
`pages` from `shellPages`, real page actions in `#actions` and the pages in its
|
|
98
97
|
default slot. On desktop, the sidebar names the page: the shell shows no page title, puts
|
|
99
98
|
`#actions` in a bar above the page and scrolls only the content; a settings
|
|
100
99
|
page (`SectionTabs fill` or `SettingsPage`) keeps its tabs and footer in place
|
|
@@ -109,6 +108,14 @@ device-width viewport. Its full-page sidebar names the App with
|
|
|
109
108
|
shows the signed-in DSM account and its role from `ctx.user`. See the ui's
|
|
110
109
|
`docs/adaptive-layout.md`.
|
|
111
110
|
|
|
111
|
+
The template puts no Refresh in `#actions`, and with nothing there `AppShell`
|
|
112
|
+
draws no bar above the page. Data stays fresh without one: `ctx.reopen` reads
|
|
113
|
+
the status, the panels and the portal again when the window is shown again,
|
|
114
|
+
and showing the status page again reads it again. A failed read offers Retry
|
|
115
|
+
beside its error. Sign out appears in `#actions` only when standalone login is
|
|
116
|
+
on. Keep `#actions` for real page actions, such as Add; a section that needs a
|
|
117
|
+
manual re-read gets its own action in that section, not a header Refresh.
|
|
118
|
+
|
|
112
119
|
The frontend SDK and UI use patch ranges; the lockfile records the installed
|
|
113
120
|
versions. Update the lockfile deliberately when taking a newer patch.
|
|
114
121
|
|
|
@@ -120,8 +127,8 @@ keeps that branding, and the UI hides a bar with nothing in it. When using
|
|
|
120
127
|
even with `phone-bar-title="none"`. Pages outside the tab bar and detail pages
|
|
121
128
|
with Back keep their title bar. `header-actions` share one "…" menu; only an
|
|
122
129
|
entry marked `primary: true`, or a sole entry with an icon, becomes a separate
|
|
123
|
-
bar button. The template's `#actions`
|
|
124
|
-
workaround is needed.
|
|
130
|
+
bar button. The template's `#actions` holds only real page actions; no title or
|
|
131
|
+
empty-bar workaround is needed.
|
|
125
132
|
|
|
126
133
|
`AppShell`'s `app-root` wraps it in an app-local `AppRoot` (app modal scope, on
|
|
127
134
|
a full page as well, bounded at `height: 100%`) with the UI locale from
|
|
@@ -143,3 +150,6 @@ For UI discovery, run `pnpm exec syno-pkg-land-ui catalog --json` and
|
|
|
143
150
|
`pnpm exec syno-pkg-land-ui describe Button --json` from the installed frontend.
|
|
144
151
|
Read its prompt and exported Vue docs/types before choosing component APIs.
|
|
145
152
|
Use `syno-pkg-land-ui` directly in package scripts; keep AI guidance version-independent.
|
|
153
|
+
|
|
154
|
+
Before the first check/build, install the project dependencies with `pnpm install`
|
|
155
|
+
and run `(cd backend && go mod tidy)` to populate checksums for the selected SDK.
|
|
@@ -30,8 +30,8 @@ Use `syno-pkg-land-ui` directly in package scripts; keep AI guidance version-ind
|
|
|
30
30
|
## Overview
|
|
31
31
|
|
|
32
32
|
The template runs inside a DSM package window. `AppShell` provides status and
|
|
33
|
-
optional background navigation. The base page shows package status
|
|
34
|
-
|
|
33
|
+
optional background navigation. The base page shows package status; the root
|
|
34
|
+
overlay adds its existing fixed-operation authorization gate.
|
|
35
35
|
|
|
36
36
|
Use the installed `@synopackageland/ui` controls and `themes/dsm7-embedded.css`.
|
|
37
37
|
The theme owns colors, typography, spacing and dialogs. Keep per-app modal scope,
|
|
@@ -39,7 +39,11 @@ a unique Vue ID prefix and vertical scrolling at the DSM minimum window size.
|
|
|
39
39
|
In a DSM window, Dialogs may leave the window (`dialog-bounds="viewport"`) and a
|
|
40
40
|
press on one brings the window to the front; below 600px they are bottom sheets.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
There is no header Refresh: reopening the window, or showing the status page
|
|
43
|
+
again, reads it again, and a failed read offers Retry beside its error. The
|
|
44
|
+
shell's `#actions` holds only real page actions (Sign out with standalone
|
|
45
|
+
login); empty, the shell draws no bar. Reads expose busy state and localized
|
|
46
|
+
errors.
|
|
43
47
|
Each mount owns its state; unmount unsubscribes from host events and ignores late
|
|
44
48
|
responses. Backend route policies decide access.
|
|
45
49
|
|