Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Commit 209224e

Browse files
committed
chore: bump nextcloud-vue + router, add axios alias + manifest-first README
package.json: - @conduction/nextcloud-vue ^0.1.0-beta.3 → ^1.0.0-beta.12 (the published lib version with the Vue.extend frozen-component fix). - @nextcloud/router ^2.0.1 → ^3.1.0 — required by @nextcloud/vue 8.37+ (NcDashboardWidget / NcAvatar import getBaseUrl, missing from router 2.x). - Add ajv ^8.17.1 + ajv-formats ^3.0.1 devDependencies for the manifest validator. - Add scripts.check:manifest → node tests/validate-manifest.js (satisfies the fleet adoption spec's build-time validation gate). webpack.config.js: - Add @nextcloud/axios$ alias to force the lib's transitive axios import to resolve to the app's installed copy (decidesk pattern, commit ed34703c). Without the $ exact-match suffix webpack walks up to the lib's own node_modules and loads a second axios instance, breaking shared interceptors / CSRF tokens. eslint.config.js: - Override no-console / n/no-process-exit / n/shebang for the tests/validate-manifest.js Node CLI script. README.md: - Lead with manifest-first messaging in the intro paragraph and in the OpenRegister callout. - Add an "Adding a page (manifest-first)" section that documents the page-type table and tells cloners to edit src/manifest.json rather than writing per-page Vue files. Custom Vue components are only required for type:"custom" pages. - Add a "Renaming the app" section listing the files where the app id appears (the manifest itself does NOT carry the id). - Update the directory-structure diagram to reflect the new layout (manifest.json, customComponents.js, no router/, no navigation/).
1 parent b60af2f commit 209224e

5 files changed

Lines changed: 2298 additions & 257 deletions

File tree

README.md

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
A starting point for building Nextcloud apps following ConductionNL conventions.
2020

21-
> **Pre-wired for [OpenRegister](https://github.com/ConductionNL/openregister)** — all data is stored as OpenRegister objects. If your app needs OpenRegister, install it first. If not, remove the dependency from `appinfo/info.xml` and `openspec/app-config.json`.
21+
> **Manifest-first** — pages, navigation, and dependencies are declared in `src/manifest.json`. The shell (CnAppRoot) reads the manifest at boot and renders index / detail / dashboard / settings pages without per-page Vue files. Reach for a custom Vue component only when the page is `type: "custom"`. See `openspec/architecture/` and hydra ADR-024 for the architectural rationale.
22+
23+
> **Pre-wired for [OpenRegister](https://github.com/ConductionNL/openregister)**`manifest.dependencies` lists `openregister`, so CnAppRoot's dependency-check phase ensures the OR app is installed and enabled before the UI mounts. If your app does not need OpenRegister, remove the entry from `src/manifest.json`, `appinfo/info.xml`, and `openspec/app-config.json`.
2224
2325
## Screenshots
2426

@@ -71,13 +73,14 @@ app-template/
7173
│ └── Settings/ # AdminSettings, app_template_register.json
7274
├── templates/ # PHP templates (SPA shells)
7375
├── src/ # Vue 2 frontend
74-
│ ├── main.js # App entry point
76+
│ ├── manifest.json # Pages + menu + dependencies (the source of truth)
77+
│ ├── main.js # App entry — bootstraps CnAppRoot from manifest
78+
│ ├── App.vue # Mounts CnAppRoot + #sidebar slot
79+
│ ├── customComponents.js # Registry for `type: "custom"` pages (escape hatch)
7580
│ ├── exampleWidget.js # Sample Nextcloud Dashboard widget entry-point
76-
│ ├── App.vue # Root component
77-
│ ├── navigation/MainMenu.vue # App navigation sidebar
78-
│ ├── router/ # Vue Router
79-
│ ├── store/ # Pinia stores
80-
│ ├── views/ # Route-level views + UserSettings.vue
81+
│ ├── settings.js # Nextcloud admin settings webpack entry-point
82+
│ ├── store/ # Pinia stores (used by AdminSettings)
83+
│ ├── views/CustomExample.vue # Example custom component (registry demo)
8184
│ └── views/widgets/ # Dashboard widget Vue components (ExampleWidget.vue)
8285
├── openspec/ # Specifications, decisions, and roadmap
8386
│ ├── app-config.json # Canonical app config (id, goal, dependencies, CI)
@@ -87,7 +90,8 @@ app-template/
8790
│ ├── ROADMAP.md # Product roadmap
8891
│ └── changes/ # OpenSpec change directories (created on first change)
8992
├── tests/ # Unit and integration tests
90-
├── l10n/ # Translations (en, nl)
93+
│ └── validate-manifest.js # Ajv schema validator for src/manifest.json
94+
├── l10n/ # Translations (en, en_US, nl)
9195
├── .github/workflows/ # CI/CD pipelines
9296
├── Makefile # Dev helpers (make dev-link)
9397
└── img/ # App icons and screenshots
@@ -134,10 +138,49 @@ docker compose -f ../openregister/docker-compose.yml up -d
134138

135139
```bash
136140
npm install
137-
npm run dev # Watch mode
138-
npm run build # Production build
141+
npm run dev # Watch mode
142+
npm run build # Production build
143+
npm run check:manifest # Validate src/manifest.json against the schema
139144
```
140145

146+
### Adding a page (manifest-first)
147+
148+
Pages live in [`src/manifest.json`](src/manifest.json) — NOT in
149+
`src/views/`. To add a page, edit the manifest:
150+
151+
1. **Add a menu entry** in `manifest.menu` (id, label, icon, route).
152+
2. **Add a page** in `manifest.pages` (id matches the menu's `route`).
153+
Pick the `type`:
154+
155+
| Type | Use when |
156+
|-------------|-------------------------------------------------------------|
157+
| `dashboard` | Home / overview with KPI widgets |
158+
| `index` | Schema-backed list view (CnDataTable + sidebar) |
159+
| `detail` | Single-object view at `/things/:id` |
160+
| `settings` | Admin/user settings with `version-info` / `register-mapping`|
161+
| `logs` | Tail-style audit log view |
162+
| `chat` | Conversation thread page |
163+
| `files` | Folder browser |
164+
| `custom` | Bespoke Vue component (last resort) |
165+
166+
3. **Run `npm run check:manifest`** to verify the manifest validates.
167+
168+
You only write a Vue file when the page is `type: "custom"`. In that
169+
case, drop the component into `src/views/`, register it in
170+
[`src/customComponents.js`](src/customComponents.js), and reference
171+
its registry name in the manifest entry's `component` field. See
172+
[`src/views/CustomExample.vue`](src/views/CustomExample.vue) for the
173+
canonical example.
174+
175+
### Renaming the app
176+
177+
Search-and-replace `app-template` (the `<id>` from `appinfo/info.xml`)
178+
in: `appinfo/info.xml`, `package.json`, `openspec/app-config.json`,
179+
`src/main.js` (the `app-id` prop, the `loadTranslations` arg, and the
180+
`generateUrl` base path), `src/App.vue` (the `app-id` prop and
181+
`translateForApp` argument), and `webpack.config.js` (the `appId`
182+
constant). The manifest itself does not carry the app id.
183+
141184
### Adding a dashboard widget
142185

143186
The template ships with a working `ExampleWidget` you can copy. Each widget is

eslint.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,13 @@ module.exports = defineConfig([{
4242
'import/no-named-as-default': 'off', // disable named-as-default checking to avoid parser requirement
4343
'import/no-named-as-default-member': 'off', // disable named-as-default-member checking to avoid parser requirement
4444
},
45+
}, {
46+
// Node-side CLI tools (build / validate scripts) legitimately use
47+
// console + process.exit and ship as plain JS (no shebang).
48+
files: ['tests/validate-manifest.js'],
49+
rules: {
50+
'no-console': 'off',
51+
'n/no-process-exit': 'off',
52+
'n/shebang': 'off',
53+
},
4554
}])

0 commit comments

Comments
 (0)