@sito/dashboard-app 0.0.53 → 0.0.55
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 +259 -9
- package/dist/dashboard-app.cjs +1 -1
- package/dist/dashboard-app.js +1981 -1641
- package/dist/hooks/dialogs/types.d.ts +8 -7
- package/dist/hooks/dialogs/useFormDialog.d.ts +2 -10
- package/dist/hooks/forms/types.d.ts +1 -1
- package/dist/lib/api/IndexedDBClient.d.ts +2 -0
- package/dist/lib/api/SupabaseDataClient.d.ts +43 -0
- package/dist/lib/api/index.d.ts +2 -0
- package/dist/lib/api/supabaseAuth.d.ts +10 -0
- package/dist/lib/entities/base/BaseFilterDto.d.ts +2 -0
- package/dist/lib/entities/base/index.d.ts +2 -2
- package/dist/main.css +1 -1
- package/dist/providers/{AuthProvider.d.ts → Auth/AuthProvider.d.ts} +2 -2
- package/dist/providers/Auth/authContext.d.ts +3 -0
- package/dist/providers/Auth/index.d.ts +3 -0
- package/dist/providers/Auth/types.d.ts +17 -0
- package/dist/providers/Supbase/SupabaseAuthProvider.d.ts +3 -0
- package/dist/providers/Supbase/SupabaseContext.d.ts +3 -0
- package/dist/providers/Supbase/SupabaseManagerProvider.d.ts +3 -0
- package/dist/providers/Supbase/index.d.ts +4 -0
- package/dist/providers/Supbase/types.d.ts +15 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/types.d.ts +1 -16
- package/package.json +19 -12
package/README.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
`@sito/dashboard-app` is a React 18 component and utilities library for building Sito-style admin dashboards, CRUD screens, and internal tools. It packages UI components, hooks, providers, typed API helpers, and styles in a single npm package.
|
|
4
4
|
|
|
5
|
+
## Documentation scope and source of truth
|
|
6
|
+
|
|
7
|
+
Use documentation by target package:
|
|
8
|
+
|
|
9
|
+
| Document | Primary audience | Source of truth for |
|
|
10
|
+
| ----------------------- | ----------------------------- | ------------------------------------------------------- |
|
|
11
|
+
| `README.md` (this file) | Consumer apps and maintainers | Public usage of `@sito/dashboard-app` |
|
|
12
|
+
| `AGENTS.md` | AI agents and maintainers | Implementation rules for `@sito/dashboard-app` |
|
|
13
|
+
| `.sito/*.md` | Internal team and agents | Upstream reference notes for `@sito/dashboard` behavior |
|
|
14
|
+
|
|
15
|
+
Important:
|
|
16
|
+
|
|
17
|
+
- `.sito/*.md` is not the canonical integration guide for this package.
|
|
18
|
+
- For `@sito/dashboard-app` provider setup, use `ConfigProvider -> ManagerProvider -> AuthProvider -> NotificationProvider -> DrawerMenuProvider` (`NavbarProvider` when needed).
|
|
19
|
+
- `IconButton` differs by package:
|
|
20
|
+
- `@sito/dashboard`: `icon` accepts a React node.
|
|
21
|
+
- `@sito/dashboard-app`: `icon` expects `IconDefinition` (FontAwesome wrapper export).
|
|
22
|
+
|
|
5
23
|
## Installation
|
|
6
24
|
|
|
7
25
|
```bash
|
|
@@ -18,16 +36,17 @@ pnpm add @sito/dashboard-app
|
|
|
18
36
|
- React `18.3.1`
|
|
19
37
|
- React DOM `18.3.1`
|
|
20
38
|
- `@tanstack/react-query` `5.83.0`
|
|
39
|
+
- `@supabase/supabase-js` `2.100.0` (optional; only if using Supabase backend)
|
|
21
40
|
- `react-hook-form` `7.61.1`
|
|
22
|
-
- `@sito/dashboard` `^0.0.
|
|
23
|
-
- Font Awesome
|
|
41
|
+
- `@sito/dashboard` `^0.0.74`
|
|
42
|
+
- Font Awesome peers defined in `package.json`
|
|
24
43
|
|
|
25
44
|
Install all peers in consumer apps:
|
|
26
45
|
|
|
27
46
|
```bash
|
|
28
47
|
npm install \
|
|
29
48
|
react@18.3.1 react-dom@18.3.1 \
|
|
30
|
-
@sito/dashboard@^0.0.
|
|
49
|
+
@sito/dashboard@^0.0.74 \
|
|
31
50
|
@tanstack/react-query@5.83.0 \
|
|
32
51
|
react-hook-form@7.61.1 \
|
|
33
52
|
@fortawesome/fontawesome-svg-core@7.0.0 \
|
|
@@ -37,6 +56,12 @@ npm install \
|
|
|
37
56
|
@fortawesome/react-fontawesome@0.2.3
|
|
38
57
|
```
|
|
39
58
|
|
|
59
|
+
If your app uses the Supabase backend:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @supabase/supabase-js@2.100.0
|
|
63
|
+
```
|
|
64
|
+
|
|
40
65
|
## Core exports
|
|
41
66
|
|
|
42
67
|
- Layout and navigation: `Page`, `Navbar`, `Drawer`, `TabsLayout`, `PrettyGrid`, `ToTop`
|
|
@@ -44,7 +69,7 @@ npm install \
|
|
|
44
69
|
- Dialogs and forms: `Dialog`, `FormDialog`, `ImportDialog`, form inputs
|
|
45
70
|
- Feedback: `Notification`, `Loading`, `Empty`, `Error`, `Onboarding`
|
|
46
71
|
- Hooks: `useFormDialog` (generic state/entity), `usePostDialog`, `usePutDialog`, `useImportDialog`, `useDeleteDialog`, `usePostForm`, `useDeleteAction`, `useNavbar`, and more — all action hooks ship with default `sticky`, `multiple`, `id`, `icon`, and `tooltip` values so only `onClick` is required
|
|
47
|
-
- Providers and utilities: `ConfigProvider`, `ManagerProvider`, `AuthProvider`, `NotificationProvider`, `DrawerMenuProvider`, `NavbarProvider`, DTOs, API clients
|
|
72
|
+
- Providers and utilities: `ConfigProvider`, `ManagerProvider`, `SupabaseManagerProvider`, `AuthProvider`, `SupabaseAuthProvider`, `NotificationProvider`, `DrawerMenuProvider`, `NavbarProvider`, DTOs, API clients (`BaseClient`, `IndexedDBClient`, `SupabaseDataClient`), and `useSupabase`
|
|
48
73
|
|
|
49
74
|
## Component usage patterns
|
|
50
75
|
|
|
@@ -232,6 +257,101 @@ Main optional props:
|
|
|
232
257
|
- `scrollOnClick?: boolean` (default `true`)
|
|
233
258
|
- `onClick?: () => void`
|
|
234
259
|
|
|
260
|
+
## Dialog hook migration (`v0.0.54`)
|
|
261
|
+
|
|
262
|
+
`v0.0.54` removes the legacy entity-coupled `useFormDialog` contract.
|
|
263
|
+
|
|
264
|
+
### Breaking changes
|
|
265
|
+
|
|
266
|
+
- `useFormDialog` is now core lifecycle only (`mode: "state" | "entity"`).
|
|
267
|
+
- Legacy props were removed from `useFormDialog`: `mutationFn`, `queryKey`, `getFunction`, `dtoToForm`, `formToDto`.
|
|
268
|
+
- Deprecated aliases were removed:
|
|
269
|
+
- `useFormDialogLegacy`
|
|
270
|
+
- `useEntityFormDialog`
|
|
271
|
+
|
|
272
|
+
### What to use now
|
|
273
|
+
|
|
274
|
+
- Local/state-only dialog (filters/settings): `useFormDialog`
|
|
275
|
+
- Create flow (POST): `usePostDialog`
|
|
276
|
+
- Edit flow (PUT + get by id): `usePutDialog`
|
|
277
|
+
|
|
278
|
+
### Before -> After
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
// BEFORE (no longer supported in v0.0.54+)
|
|
282
|
+
const createDialog = useFormDialog<
|
|
283
|
+
ProductDto,
|
|
284
|
+
CreateProductDto,
|
|
285
|
+
ProductDto,
|
|
286
|
+
ProductForm
|
|
287
|
+
>({
|
|
288
|
+
title: "Create product",
|
|
289
|
+
defaultValues: { name: "", price: 0 },
|
|
290
|
+
mutationFn: (dto) => api.products.insert(dto),
|
|
291
|
+
formToDto: (form) => ({ name: form.name, price: form.price }),
|
|
292
|
+
queryKey: ["products"],
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// AFTER
|
|
296
|
+
const createDialog = usePostDialog<CreateProductDto, ProductDto, ProductForm>({
|
|
297
|
+
title: "Create product",
|
|
298
|
+
defaultValues: { name: "", price: 0 },
|
|
299
|
+
mutationFn: (dto) => api.products.insert(dto),
|
|
300
|
+
mapOut: (form) => ({ name: form.name, price: form.price }),
|
|
301
|
+
queryKey: ["products"],
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
// BEFORE (no longer supported in v0.0.54+)
|
|
307
|
+
const editDialog = useFormDialog<
|
|
308
|
+
ProductDto,
|
|
309
|
+
UpdateProductDto,
|
|
310
|
+
ProductDto,
|
|
311
|
+
ProductForm
|
|
312
|
+
>({
|
|
313
|
+
title: "Edit product",
|
|
314
|
+
defaultValues: { name: "", price: 0 },
|
|
315
|
+
getFunction: (id) => api.products.getById(id),
|
|
316
|
+
dtoToForm: (dto) => ({ name: dto.name, price: dto.price }),
|
|
317
|
+
mutationFn: (dto) => api.products.update(dto),
|
|
318
|
+
formToDto: (form) => ({ id: 0, ...form }),
|
|
319
|
+
queryKey: ["products"],
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// AFTER
|
|
323
|
+
const editDialog = usePutDialog<
|
|
324
|
+
ProductDto,
|
|
325
|
+
UpdateProductDto,
|
|
326
|
+
ProductDto,
|
|
327
|
+
ProductForm
|
|
328
|
+
>({
|
|
329
|
+
title: "Edit product",
|
|
330
|
+
defaultValues: { name: "", price: 0 },
|
|
331
|
+
getFunction: (id) => api.products.getById(id),
|
|
332
|
+
dtoToForm: (dto) => ({ name: dto.name, price: dto.price }),
|
|
333
|
+
mutationFn: (dto) => api.products.update(dto),
|
|
334
|
+
mapOut: (form, dto) => ({ id: dto?.id ?? 0, ...form }),
|
|
335
|
+
queryKey: ["products"],
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Core `useFormDialog` error handling
|
|
340
|
+
|
|
341
|
+
`useFormDialog` supports a core `onError` callback for failures in submit/apply/clear paths.
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
const filtersDialog = useFormDialog<ProductFilters>({
|
|
345
|
+
mode: "state",
|
|
346
|
+
title: "Filters",
|
|
347
|
+
defaultValues: { search: "", minPrice: 0 },
|
|
348
|
+
onSubmit: async (values) => setTableFilters(values),
|
|
349
|
+
onError: (error, { phase, values }) => {
|
|
350
|
+
console.error("Dialog error", { error, phase, values });
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
235
355
|
## Initial setup example
|
|
236
356
|
|
|
237
357
|
Wrap your app with providers in this order to enable routing integration, React Query, auth, notifications, and drawer/navbar state.
|
|
@@ -319,6 +439,132 @@ Notes:
|
|
|
319
439
|
- `NavbarProvider` is required when using `Navbar` or `useNavbar`; otherwise it can be omitted.
|
|
320
440
|
- If you customize auth storage keys in `AuthProvider`, pass the same keys to `IManager`/`BaseClient` auth config.
|
|
321
441
|
|
|
442
|
+
## Supabase setup (optional backend)
|
|
443
|
+
|
|
444
|
+
The library does not read `.env` values directly. The consumer app must create the Supabase client and pass it to `SupabaseManagerProvider`.
|
|
445
|
+
|
|
446
|
+
Use frontend-safe keys only:
|
|
447
|
+
|
|
448
|
+
- `VITE_SUPABASE_URL`
|
|
449
|
+
- `VITE_SUPABASE_ANON_KEY`
|
|
450
|
+
|
|
451
|
+
Do not expose service-role keys in the browser.
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
import type { ReactNode } from "react";
|
|
455
|
+
import { createClient } from "@supabase/supabase-js";
|
|
456
|
+
import { Link } from "react-router-dom";
|
|
457
|
+
import {
|
|
458
|
+
ConfigProvider,
|
|
459
|
+
SupabaseManagerProvider,
|
|
460
|
+
SupabaseAuthProvider,
|
|
461
|
+
NotificationProvider,
|
|
462
|
+
DrawerMenuProvider,
|
|
463
|
+
NavbarProvider,
|
|
464
|
+
} from "@sito/dashboard-app";
|
|
465
|
+
|
|
466
|
+
const supabase = createClient(
|
|
467
|
+
import.meta.env.VITE_SUPABASE_URL,
|
|
468
|
+
import.meta.env.VITE_SUPABASE_ANON_KEY,
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
function AppProviders({ children }: { children: ReactNode }) {
|
|
472
|
+
return (
|
|
473
|
+
<ConfigProvider
|
|
474
|
+
location={window.location}
|
|
475
|
+
navigate={() => {}}
|
|
476
|
+
linkComponent={Link}
|
|
477
|
+
>
|
|
478
|
+
<SupabaseManagerProvider supabase={supabase}>
|
|
479
|
+
<SupabaseAuthProvider>
|
|
480
|
+
<NotificationProvider>
|
|
481
|
+
<DrawerMenuProvider>
|
|
482
|
+
<NavbarProvider>{children}</NavbarProvider>
|
|
483
|
+
</DrawerMenuProvider>
|
|
484
|
+
</NotificationProvider>
|
|
485
|
+
</SupabaseAuthProvider>
|
|
486
|
+
</SupabaseManagerProvider>
|
|
487
|
+
</ConfigProvider>
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`useAuth` keeps the same contract with `SupabaseAuthProvider` (`account`, `logUser`, `logoutUser`, `logUserFromLocal`, `isInGuestMode`, `setGuestMode`).
|
|
493
|
+
|
|
494
|
+
`SupabaseDataClient` follows the same generic surface as `BaseClient` and `IndexedDBClient`, so entity clients can switch backend with minimal UI/hook changes.
|
|
495
|
+
It also supports optional configuration for conventional columns: `idColumn` (default `"id"`), `deletedAtColumn` (default `"deletedAt"`), and `defaultSortColumn`.
|
|
496
|
+
|
|
497
|
+
### Supabase entity client example
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
import type { SupabaseClient } from "@supabase/supabase-js";
|
|
501
|
+
import {
|
|
502
|
+
BaseCommonEntityDto,
|
|
503
|
+
BaseEntityDto,
|
|
504
|
+
BaseFilterDto,
|
|
505
|
+
DeleteDto,
|
|
506
|
+
ImportPreviewDto,
|
|
507
|
+
SupabaseDataClient,
|
|
508
|
+
} from "@sito/dashboard-app";
|
|
509
|
+
|
|
510
|
+
interface ProductDto extends BaseEntityDto {
|
|
511
|
+
name: string;
|
|
512
|
+
price: number;
|
|
513
|
+
categoryId?: number;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
interface ProductCommonDto extends BaseCommonEntityDto {
|
|
517
|
+
name: string;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
interface CreateProductDto {
|
|
521
|
+
name: string;
|
|
522
|
+
price: number;
|
|
523
|
+
categoryId?: number;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
interface UpdateProductDto extends DeleteDto {
|
|
527
|
+
name?: string;
|
|
528
|
+
price?: number;
|
|
529
|
+
categoryId?: number;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
interface ProductFilterDto extends BaseFilterDto {
|
|
533
|
+
categoryId?: number;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
interface ProductImportPreviewDto extends ImportPreviewDto {
|
|
537
|
+
id: number;
|
|
538
|
+
name: string;
|
|
539
|
+
price: number;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
class ProductsSupabaseClient extends SupabaseDataClient<
|
|
543
|
+
"products",
|
|
544
|
+
ProductDto,
|
|
545
|
+
ProductCommonDto,
|
|
546
|
+
CreateProductDto,
|
|
547
|
+
UpdateProductDto,
|
|
548
|
+
ProductFilterDto,
|
|
549
|
+
ProductImportPreviewDto
|
|
550
|
+
> {
|
|
551
|
+
constructor(supabase: SupabaseClient) {
|
|
552
|
+
super("products", supabase, {
|
|
553
|
+
defaultSortColumn: "id",
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const productsClient = new ProductsSupabaseClient(supabase);
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Compatibility and incremental migration
|
|
562
|
+
|
|
563
|
+
- The REST flow stays intact: existing apps using `ManagerProvider` + `AuthProvider` + `BaseClient` do not need changes.
|
|
564
|
+
- You can migrate entity by entity: move one resource client at a time from `BaseClient` to `SupabaseDataClient`.
|
|
565
|
+
- During migration, mixed data backends are valid (`BaseClient` for some entities, `SupabaseDataClient` for others) as long as each UI flow uses the corresponding client methods.
|
|
566
|
+
- If you switch auth to Supabase, use `SupabaseManagerProvider` + `SupabaseAuthProvider`; if you keep REST auth, continue with `ManagerProvider` + `AuthProvider`.
|
|
567
|
+
|
|
322
568
|
## Built-in auth refresh behavior
|
|
323
569
|
|
|
324
570
|
`APIClient` and `BaseClient` already include refresh/retry behavior for secured requests:
|
|
@@ -358,6 +604,7 @@ Notes:
|
|
|
358
604
|
- `npm run build`: compile TypeScript and build the library
|
|
359
605
|
- `npm run preview`: preview the Vite build locally
|
|
360
606
|
- `npm run lint`: run ESLint
|
|
607
|
+
- `npm run docs:check`: validate docs policy markers, relative links, and docs consistency rules
|
|
361
608
|
- `npm run test`: run unit/component tests once (Vitest)
|
|
362
609
|
- `npm run test:watch`: run tests in watch mode
|
|
363
610
|
- `npm run format`: run Prettier write mode
|
|
@@ -453,9 +700,11 @@ Contract and filtering notes:
|
|
|
453
700
|
- Preferred update contract is `update(value)` (aligned with `BaseClient.update(value)`).
|
|
454
701
|
- Legacy `update(id, value)` remains temporarily supported for backward compatibility.
|
|
455
702
|
- Filtering uses strict equality for regular keys.
|
|
456
|
-
- `deletedAt`
|
|
457
|
-
|
|
458
|
-
- `
|
|
703
|
+
- `deletedAt` remains a date filter (`Date | null`) for exact-match filtering.
|
|
704
|
+
- Use `softDeleteScope` for trash filters:
|
|
705
|
+
- `softDeleteScope: "ACTIVE"` => active rows (`deletedAt` null/undefined)
|
|
706
|
+
- `softDeleteScope: "DELETED"` => deleted rows (`deletedAt` not null/undefined)
|
|
707
|
+
- `softDeleteScope: "ALL"` => all rows
|
|
459
708
|
|
|
460
709
|
## Tests
|
|
461
710
|
|
|
@@ -476,6 +725,7 @@ npm run test:watch
|
|
|
476
725
|
Current validation stack:
|
|
477
726
|
|
|
478
727
|
- `npm run lint`
|
|
728
|
+
- `npm run docs:check`
|
|
479
729
|
- `npm run test`
|
|
480
730
|
- `npm run build`
|
|
481
731
|
- Storybook/manual behavior checks (optional visual validation)
|
|
@@ -498,8 +748,8 @@ npm run format
|
|
|
498
748
|
|
|
499
749
|
CI is available through GitHub Actions:
|
|
500
750
|
|
|
501
|
-
- `.github/workflows/ci.yml`: runs `lint + test + build` on `push` and `pull_request`
|
|
502
|
-
- `.github/workflows/lint.yml`: runs lint
|
|
751
|
+
- `.github/workflows/ci.yml`: runs `lint + docs:check + test + build` on `push` and `pull_request`
|
|
752
|
+
- `.github/workflows/lint.yml`: runs `lint + docs:check` on `push` and `pull_request`
|
|
503
753
|
|
|
504
754
|
Package release/publish is still handled manually.
|
|
505
755
|
|