@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 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.72`
23
- - Font Awesome + Emotion peers defined in `package.json`
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.72 \
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` also supports boolean filtering:
457
- - `deletedAt: true` => deleted rows (`deletedAt` not null/undefined)
458
- - `deletedAt: false` => active rows (`deletedAt` null/undefined)
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 checks on `push` and `pull_request`
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