@venizia/ardor 0.1.5 → 0.3.1

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/README.md CHANGED
@@ -95,7 +95,7 @@ The full guide, including the root component and the typed hooks, is in the
95
95
  ## Migrating from `@minimaltech/ra-core-infra`
96
96
 
97
97
  ARDOR is that package, split and rebranded. See
98
- [the migration guide](https://ardor.venizia.ai/guides/migration/from-ra-core-infra) -
98
+ [the migration guide](https://ardor.venizia.ai/guides/migrations/from-ra-core-infra) -
99
99
  the move is four mechanical edits plus four symbol renames.
100
100
 
101
101
  ## License
@@ -0,0 +1,5 @@
1
+ import { reactHouseConfigs } from '@venizia/dev-configs/linters';
2
+
3
+ // oxlint runs the shared rules; ESLint runs what oxlint cannot: the naming convention, the house rules
4
+ // and `no-leaked-render`.
5
+ export default reactHouseConfigs;
@@ -0,0 +1,4 @@
1
+ import { defineConfig } from 'oxfmt';
2
+ import { browserOxfmtConfigs } from '@venizia/dev-configs/formatters';
3
+
4
+ export default defineConfig(browserOxfmtConfigs);
@@ -0,0 +1,4 @@
1
+ import { defineConfig } from 'oxlint';
2
+ import { BrowserOxlintConfigs } from '@venizia/dev-configs/linters';
3
+
4
+ export default defineConfig(BrowserOxlintConfigs.create());
@@ -0,0 +1,7 @@
1
+ # {{app}}
2
+
3
+ The {{app}} admin of {{project}}, built on ARDOR: Vite, React and react-admin.
4
+
5
+ `bun run dev` serves `http://localhost:{{devPort}}`. `/api` is proxied to the backend app chosen when this app was added (`apiUrl` in `vite.config.mts`).
6
+
7
+ The `products` resource reads `GET /api/products` (a JSON array and a `Content-Range` header) and writes `POST /api/products` and `PATCH /api/products/:id`. Point it at your own resource by renaming `products` in `src/main.tsx`.
@@ -0,0 +1 @@
1
+ PORT={{devPort}}
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{app}}</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,19 @@
1
+ import 'reflect-metadata';
2
+
3
+ import AutoArtifacts from '@venizia/ignis-boot/auto';
4
+
5
+ import { BaseArdorApplication, type IApplicationInfo, type IArtifactIndex } from '@venizia/ardor';
6
+
7
+ // The decorated classes live in their own files and this module imports none of them: the build lists
8
+ // every one under src/ in `AutoArtifacts`.
9
+ export class Application extends BaseArdorApplication {
10
+ getAppInfo(): IApplicationInfo {
11
+ return { name: '{{app}}', version: '0.0.0', description: 'The {{app}} admin of {{project}}' };
12
+ }
13
+
14
+ override artifacts(): Array<IArtifactIndex> {
15
+ return [AutoArtifacts];
16
+ }
17
+
18
+ bindContext(): void {}
19
+ }
@@ -0,0 +1,44 @@
1
+ import {
2
+ type BaseArdorApplication as TArdorApplication,
3
+ configuration,
4
+ CoreBindings,
5
+ DefaultI18nProvider,
6
+ DefaultRestDataProvider,
7
+ englishMessages,
8
+ inject,
9
+ provide,
10
+ } from '@venizia/ardor';
11
+
12
+ // The two providers an application without sign-in needs. start() binds each @provide method under its
13
+ // key; the auth provider stays unbound, so every page is public.
14
+ @configuration()
15
+ export class AdminConfiguration {
16
+ constructor(
17
+ @inject({ key: CoreBindings.APPLICATION_INSTANCE })
18
+ private readonly application: TArdorApplication,
19
+ ) {}
20
+
21
+ @provide({ key: CoreBindings.REST_DATA_PROVIDER_OPTIONS })
22
+ restDataProviderOptions() {
23
+ // No sign-in: no request carries an Authorization header.
24
+ return { url: '/api', noAuthPathRegex: /./ };
25
+ }
26
+
27
+ @provide({ key: CoreBindings.I18N_PROVIDER_OPTIONS })
28
+ i18nProviderOptions() {
29
+ return {
30
+ i18nSources: { en: englishMessages },
31
+ languages: [{ locale: 'en', name: 'English' }],
32
+ };
33
+ }
34
+
35
+ @provide({ key: CoreBindings.DEFAULT_REST_DATA_PROVIDER })
36
+ restDataProvider() {
37
+ return this.application.instantiate(DefaultRestDataProvider).value(this.application);
38
+ }
39
+
40
+ @provide({ key: CoreBindings.DEFAULT_I18N_PROVIDER })
41
+ i18nProvider() {
42
+ return this.application.instantiate(DefaultI18nProvider).value(this.application);
43
+ }
44
+ }
@@ -0,0 +1,26 @@
1
+ import 'reflect-metadata';
2
+
3
+ import { configureStore } from '@reduxjs/toolkit';
4
+ import { ArdorApplication } from '@venizia/ardor';
5
+ import { createRoot } from 'react-dom/client';
6
+
7
+ import { Application } from '@/application';
8
+ import { ProductCreate } from '@/pages/product-create';
9
+ import { ProductEdit } from '@/pages/product-edit';
10
+ import { ProductList } from '@/pages/product-list';
11
+
12
+ const application = new Application();
13
+ const store = configureStore({
14
+ reducer: { app: (state: { ready: boolean } = { ready: true }) => state },
15
+ });
16
+
17
+ await application.start();
18
+
19
+ createRoot(document.getElementById('root')!).render(
20
+ <ArdorApplication
21
+ container={application}
22
+ reduxStore={store}
23
+ suspense={<p>Loading</p>}
24
+ resources={[{ name: 'products', list: ProductList, create: ProductCreate, edit: ProductEdit }]}
25
+ />,
26
+ );
@@ -0,0 +1,10 @@
1
+ import { CreateBase } from 'ra-core';
2
+
3
+ import { ProductForm } from '@/pages/product-form';
4
+
5
+ export const ProductCreate = () => (
6
+ <CreateBase resource="products" redirect="list">
7
+ <h1>Create a product</h1>
8
+ <ProductForm />
9
+ </CreateBase>
10
+ );
@@ -0,0 +1,10 @@
1
+ import { EditBase } from 'ra-core';
2
+
3
+ import { ProductForm } from '@/pages/product-form';
4
+
5
+ export const ProductEdit = () => (
6
+ <EditBase resource="products" redirect="list">
7
+ <h1>Edit a product</h1>
8
+ <ProductForm />
9
+ </EditBase>
10
+ );
@@ -0,0 +1,32 @@
1
+ import { Form, useInput } from 'ra-core';
2
+
3
+ const TextInput = (props: { source: string; label: string }) => {
4
+ const { field } = useInput({ source: props.source });
5
+
6
+ return (
7
+ <label>
8
+ {props.label} <input {...field} value={field.value ?? ''} />
9
+ </label>
10
+ );
11
+ };
12
+
13
+ const NumberInput = (props: { source: string; label: string }) => {
14
+ const { field } = useInput({
15
+ source: props.source,
16
+ parse: (value: string) => (value === '' ? null : Number(value)),
17
+ });
18
+
19
+ return (
20
+ <label>
21
+ {props.label} <input {...field} type="number" value={field.value ?? ''} />
22
+ </label>
23
+ );
24
+ };
25
+
26
+ export const ProductForm = () => (
27
+ <Form>
28
+ <TextInput source="name" label="Name" />
29
+ <NumberInput source="price" label="Price" />
30
+ <button type="submit">Save</button>
31
+ </Form>
32
+ );
@@ -0,0 +1,42 @@
1
+ import { Link } from 'react-router-dom';
2
+ import { ListBase, useCreatePath, useListContext } from 'ra-core';
3
+
4
+ interface IProduct {
5
+ id: number;
6
+ name: string;
7
+ price: number;
8
+ }
9
+
10
+ const Rows = () => {
11
+ const { data, total, isPending } = useListContext<IProduct>();
12
+ const createPath = useCreatePath();
13
+
14
+ if (isPending) {
15
+ return <p>Loading</p>;
16
+ }
17
+
18
+ return (
19
+ <main>
20
+ <h1>
21
+ Products <small>({total} total)</small>
22
+ </h1>
23
+ <Link to={createPath({ resource: 'products', type: 'create' })}>Create</Link>
24
+ <ul>
25
+ {(data ?? []).map((product) => (
26
+ <li key={product.id}>
27
+ <Link to={createPath({ resource: 'products', type: 'edit', id: product.id })}>
28
+ {product.name}
29
+ </Link>{' '}
30
+ - {product.price}
31
+ </li>
32
+ ))}
33
+ </ul>
34
+ </main>
35
+ );
36
+ };
37
+
38
+ export const ProductList = () => (
39
+ <ListBase resource="products" perPage={10}>
40
+ <Rows />
41
+ </ListBase>
42
+ );
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "http://json.schemastore.org/tsconfig",
3
+ "extends": "@venizia/dev-configs/tsconfig.react.json",
4
+ "compilerOptions": {
5
+ "target": "ESNext",
6
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
7
+ "types": ["vite/client"],
8
+ "noEmit": true,
9
+ "isolatedModules": true,
10
+
11
+ // Restated, not inherited: Bun ignores an `extends` that names a package.
12
+ "experimentalDecorators": true,
13
+ "emitDecoratorMetadata": true,
14
+ "useDefineForClassFields": false,
15
+
16
+ "paths": {
17
+ "@/*": ["./src/*"]
18
+ }
19
+ },
20
+ "include": ["src", "vite.config.mts"]
21
+ }
@@ -0,0 +1,36 @@
1
+ import { IgnisArtifactsVitePlugin } from '@venizia/ignis-boot/vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import { defineConfig, loadEnv } from 'vite';
4
+
5
+ export default defineConfig(({ mode }) => {
6
+ const env = loadEnv(mode, '.', '');
7
+ // The backend app `vulcan add --api` chose; empty when there is none, and then nothing is proxied.
8
+ const apiUrl: string = '{{apiUrl}}';
9
+ const proxy: Record<string, string> = apiUrl === '' ? {} : { '/api': apiUrl };
10
+
11
+ return {
12
+ // Builds the class list of src/ into the bundle, so a decorated class is bound without being imported.
13
+ plugins: [IgnisArtifactsVitePlugin.create(), react()],
14
+ resolve: { alias: { '@': '/src' } },
15
+ server: {
16
+ port: Number(env.PORT ?? '{{devPort}}'),
17
+ strictPort: true,
18
+ proxy,
19
+ },
20
+ build: {
21
+ rolldownOptions: {
22
+ output: {
23
+ // React, react-admin and the router weigh about 500 KB before any application code. Two
24
+ // vendor chunks keep the application's own chunk small, cacheable across a deploy, and
25
+ // under Vite's 500 KB warning.
26
+ codeSplitting: {
27
+ groups: [
28
+ { name: 'react', test: /node_modules[\\/](react|react-dom|scheduler)[\\/]/ },
29
+ { name: 'vendor', test: /node_modules/ },
30
+ ],
31
+ },
32
+ },
33
+ },
34
+ },
35
+ };
36
+ });
@@ -0,0 +1,71 @@
1
+ {
2
+ "presetVersion": 1,
3
+ "side": "frontend",
4
+ "summary": "An ARDOR admin on Vite and React: one products resource with list, create and edit pages, REST data provider and i18n, no sign-in.",
5
+ "devPort": 5173,
6
+ "urls": [
7
+ "/"
8
+ ],
9
+ "dependencies": {
10
+ "@reduxjs/toolkit": "^2.12.0",
11
+ "@tanstack/react-query": "^5.101.2",
12
+ "@venizia/ardor": "0.3.1",
13
+ "@venizia/ignis-connectors": "0.3.1",
14
+ "@venizia/ignis-filter": "0.3.1",
15
+ "@venizia/ignis-helpers": "0.3.1",
16
+ "@venizia/ignis-inversion": "0.3.1",
17
+ "@venizia/ignis-kernel": "0.3.1",
18
+ "ra-core": "^5.15.0",
19
+ "ra-i18n-polyglot": "^5.15.0",
20
+ "react": "^19.2.7",
21
+ "react-dom": "^19.2.7",
22
+ "react-redux": "^9.3.0",
23
+ "react-router-dom": "^7.9.4",
24
+ "reflect-metadata": "^0.2.2"
25
+ },
26
+ "devDependencies": {
27
+ "@types/react": "^19",
28
+ "@types/react-dom": "^19",
29
+ "@venizia/dev-configs": "0.3.1",
30
+ "@venizia/ignis-boot": "0.3.1",
31
+ "@vitejs/plugin-react": "^6.1.1",
32
+ "eslint": "^10.10.0",
33
+ "oxfmt": "0.73.0",
34
+ "oxlint": "1.88.0",
35
+ "oxlint-tsgolint": "7.0.2004",
36
+ "typescript": "^6.0.3",
37
+ "vite": "^8.2.2"
38
+ },
39
+ "peers": {
40
+ "@venizia/ignis-connectors": "^0.3.0",
41
+ "@venizia/ignis-filter": "^0.3.0",
42
+ "@venizia/ignis-helpers": "^0.3.0",
43
+ "@venizia/ignis-inversion": "^0.3.0",
44
+ "@venizia/ignis-kernel": "^0.3.0"
45
+ },
46
+ "scripts": {
47
+ "dev": "vite",
48
+ "build": "vite build",
49
+ "typecheck": "tsc --noEmit -p tsconfig.json",
50
+ "lint": "oxlint -c .configs/oxlint.config.mts --deny-warnings && eslint -c .configs/eslint.config.mjs . && oxfmt -c .configs/oxfmt.config.mts --check \"**/*.{js,mjs,ts,mts,tsx}\"",
51
+ "lint:fix": "oxlint -c .configs/oxlint.config.mts --fix && eslint -c .configs/eslint.config.mjs . --fix && oxfmt -c .configs/oxfmt.config.mts \"**/*.{js,mjs,ts,mts,tsx}\""
52
+ },
53
+ "checks": [
54
+ "typecheck",
55
+ "lint",
56
+ "build"
57
+ ],
58
+ "files": "./files",
59
+ "atlas": [
60
+ {
61
+ "name": "ardor",
62
+ "repo": "VENIZIA-AI/ardor",
63
+ "ref": "develop"
64
+ },
65
+ {
66
+ "name": "ignis",
67
+ "repo": "VENIZIA-AI/ignis",
68
+ "ref": "develop"
69
+ }
70
+ ]
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/ardor",
3
- "version": "0.1.5",
3
+ "version": "0.3.1",
4
4
  "description": "ARDOR - frontend application framework for the VENIZIA family. One entry point over ardor-kernel, ardor-react and ardor-admin: IGNIS inversion of control, a REST data layer, auth and i18n providers, and the React bindings for a react-admin application.",
5
5
  "keywords": [
6
6
  "ardor",
@@ -58,6 +58,9 @@
58
58
  "./package.json": "./package.json"
59
59
  },
60
60
  "sideEffects": false,
61
+ "vulcan": {
62
+ "preset": "./dist/vulcan-preset/preset.json"
63
+ },
61
64
  "files": [
62
65
  "README.md",
63
66
  "LICENSE.md",
@@ -73,18 +76,18 @@
73
76
  "prepublishOnly": "make rebuild"
74
77
  },
75
78
  "dependencies": {
76
- "@venizia/ardor-admin": "0.1.5",
77
- "@venizia/ardor-kernel": "0.1.5",
78
- "@venizia/ardor-react": "0.1.5"
79
+ "@venizia/ardor-admin": "0.3.0",
80
+ "@venizia/ardor-kernel": "0.3.0",
81
+ "@venizia/ardor-react": "0.3.0"
79
82
  },
80
83
  "peerDependencies": {
81
84
  "@reduxjs/toolkit": ">=2.12.0",
82
85
  "@tanstack/react-query": ">=5.101.2",
83
- "@venizia/ignis-connectors": "^0.2.2",
84
- "@venizia/ignis-filter": "^0.2.2",
85
- "@venizia/ignis-helpers": "^0.2.2",
86
- "@venizia/ignis-inversion": "^0.2.2",
87
- "@venizia/ignis-kernel": "^0.2.2",
86
+ "@venizia/ignis-connectors": "^0.3.0",
87
+ "@venizia/ignis-filter": "^0.3.0",
88
+ "@venizia/ignis-helpers": "^0.3.0",
89
+ "@venizia/ignis-inversion": "^0.3.0",
90
+ "@venizia/ignis-kernel": "^0.3.0",
88
91
  "ra-core": ">=5.15.0",
89
92
  "ra-i18n-polyglot": ">=5.15.0",
90
93
  "react": ">=18.0",
@@ -109,11 +112,11 @@
109
112
  "@types/bun": "^1.4.1",
110
113
  "@types/react": "^19",
111
114
  "@types/react-dom": "^19",
112
- "@venizia/dev-configs": "0.3.1",
113
- "@venizia/ignis-connectors": "0.2.2",
114
- "@venizia/ignis-filter": "0.2.2",
115
- "@venizia/ignis-inversion": "0.2.2",
116
- "@venizia/ignis-kernel": "0.2.2",
115
+ "@venizia/dev-configs": "^0.3.1",
116
+ "@venizia/ignis-connectors": "^0.3.1",
117
+ "@venizia/ignis-filter": "^0.3.1",
118
+ "@venizia/ignis-inversion": "^0.3.1",
119
+ "@venizia/ignis-kernel": "^0.3.1",
117
120
  "eslint": "^10.10.0",
118
121
  "oxfmt": "0.73.0",
119
122
  "oxlint": "1.88.0",