xladmin 0.9.0 → 0.10.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/README.md +16 -0
- package/dist/client.d.ts +3 -3
- package/dist/components/ModelPage.d.ts +1 -0
- package/dist/components/form-dialog/useAdminFormSession.d.ts +25 -0
- package/dist/components/layout/ShellContext.d.ts +4 -2
- package/dist/components/model-page/ListRow.d.ts +1 -0
- package/dist/components/model-page/listRequests.d.ts +10 -0
- package/dist/components/model-page/useModelPageController.d.ts +3 -0
- package/dist/components/object-page/ObjectField.d.ts +1 -0
- package/dist/components/object-page/actionResult.d.ts +2 -0
- package/dist/components/object-page/useObjectPageController.d.ts +4 -3
- package/dist/index.js +1003 -714
- package/dist/router.d.ts +1 -0
- package/dist/types/index.d.ts +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
`xladmin` is the framework-agnostic React frontend for the `xladmin` backend.
|
|
13
13
|
|
|
14
|
+
## Read-only models
|
|
15
|
+
|
|
16
|
+
`AdminModelMeta.read_only` is a required boolean supplied by the backend. When true, model and object pages hide create, edit, delete and action controls; mutation handlers also reject submissions. List navigation, filters and selection for export remain available. `FormDialog` closes through its normal transition and disables pending submission when the model becomes read-only.
|
|
17
|
+
|
|
18
|
+
`ModelPageToolbarContext.meta.read_only` exposes the same policy to extensions. The import/export extension hides import and blocks validation/commit for read-only models while retaining export. Update backend, frontend and the extension together: these controls require backend metadata support and do not replace server-side authorization or domain commands.
|
|
19
|
+
|
|
14
20
|
## Install
|
|
15
21
|
|
|
16
22
|
```bash
|
|
@@ -111,6 +117,16 @@ If your application already has the user or a custom logout flow, pass them expl
|
|
|
111
117
|
|
|
112
118
|
Set `currentUser={null}` to hide the sidebar user panel.
|
|
113
119
|
|
|
120
|
+
## Scoped navigation and client lifetime
|
|
121
|
+
|
|
122
|
+
Every `AdminRouter` implements `resolveHref(href)`. The browser, Next.js and React Router adapters return the original URL. A host can override this method to preserve its workspace or tenant query parameter. `NavLink` uses the resolved URL both in the native anchor and in click navigation, so copying links and opening another tab retain the same context. Keep the resolver pure and idempotent; apply the same resolver in host `push`/`replace` wrappers for programmatic navigation. Custom router implementations must provide this method; tenant selection and authorization remain application concerns.
|
|
123
|
+
|
|
124
|
+
When the authenticated user or workspace changes, create a new `AdminClient` and remount the workspace subtree with a different React key. Caches are isolated by client identity. The object controller ignores late reads and mutation completions after its scope is retired, including navigation after deletion. The host should also cancel its old transport and prevent new requests through retired clients. Cancelling a request does not roll back an operation already accepted by the server.
|
|
125
|
+
|
|
126
|
+
## Item response contracts
|
|
127
|
+
|
|
128
|
+
`getItem` returns `AdminDetailResponse` with `{meta, item}`. `createItem` and `patchItem` return `AdminItemResponse` with `{item}` only. Custom clients and transport mocks must use the same response shapes. After saving an object, retain its loaded metadata and replace its item with the server response; do not read mutation metadata that the HTTP API does not return.
|
|
129
|
+
|
|
114
130
|
## Development
|
|
115
131
|
|
|
116
132
|
```bash
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AdminChoicesResponse, AdminDeletePreviewResponse, AdminDetailResponse, AdminCurrentUser, AdminListResponse, AdminModelMeta, AdminModelsResponse, AdminObjectActionResponse } from './types';
|
|
1
|
+
import type { AdminChoicesResponse, AdminDeletePreviewResponse, AdminDetailResponse, AdminItemResponse, AdminCurrentUser, AdminListResponse, AdminModelMeta, AdminModelsResponse, AdminObjectActionResponse } from './types';
|
|
2
2
|
export type AdminRequestOptions = {
|
|
3
3
|
signal?: AbortSignal;
|
|
4
4
|
};
|
|
@@ -22,8 +22,8 @@ export type AdminClient = {
|
|
|
22
22
|
sort?: string;
|
|
23
23
|
} & Record<string, unknown>) => Promise<AdminListResponse>;
|
|
24
24
|
getItem: (slug: string, id: string | number) => Promise<AdminDetailResponse>;
|
|
25
|
-
createItem: (slug: string, payload: Record<string, unknown>) => Promise<
|
|
26
|
-
patchItem: (slug: string, id: string | number, payload: Record<string, unknown>) => Promise<
|
|
25
|
+
createItem: (slug: string, payload: Record<string, unknown>) => Promise<AdminItemResponse>;
|
|
26
|
+
patchItem: (slug: string, id: string | number, payload: Record<string, unknown>) => Promise<AdminItemResponse>;
|
|
27
27
|
deleteItem: (slug: string, id: string | number) => Promise<void>;
|
|
28
28
|
getDeletePreview: (slug: string, id: string | number) => Promise<AdminDeletePreviewResponse>;
|
|
29
29
|
bulkDelete: (slug: string, ids: Array<string | number>, options?: AdminSelectionOptions) => Promise<{
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AdminClient } from '../../client';
|
|
2
|
+
import type { AdminEditableFieldMeta } from '../../types';
|
|
3
|
+
type FormSessionOptions = {
|
|
4
|
+
client: AdminClient;
|
|
5
|
+
identity: string;
|
|
6
|
+
open: boolean;
|
|
7
|
+
fields: AdminEditableFieldMeta[];
|
|
8
|
+
initialValues?: Record<string, unknown>;
|
|
9
|
+
errorFallback: string;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
};
|
|
12
|
+
/** Owns one opening of a form, independently of metadata reference refreshes. */
|
|
13
|
+
export declare function useAdminFormSession({ client, identity, open, fields, initialValues, errorFallback, onClose }: FormSessionOptions): {
|
|
14
|
+
values: Record<string, unknown>;
|
|
15
|
+
error: string | null;
|
|
16
|
+
isSubmitting: boolean;
|
|
17
|
+
editorVersion: number;
|
|
18
|
+
openPickerFieldName: string | null;
|
|
19
|
+
changeField: (name: string, value: unknown) => void;
|
|
20
|
+
requestPickerOpen: (name: string) => void;
|
|
21
|
+
requestPickerClose: (name: string) => void;
|
|
22
|
+
submit: (operation: (payload: Record<string, unknown>) => Promise<unknown>, onSuccess: () => void) => Promise<void>;
|
|
23
|
+
close: () => void;
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
type ShellContextValue = {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
hasSidebar: boolean;
|
|
4
|
+
sidebarId: string;
|
|
5
|
+
isSidebarOpen: boolean;
|
|
6
|
+
toggleSidebar: () => void;
|
|
5
7
|
pendingPath: string | null;
|
|
6
8
|
pendingView: 'overview' | 'model' | 'generic' | null;
|
|
7
9
|
startPendingNavigation: (path: string, view?: 'overview' | 'model' | 'generic') => void;
|
|
@@ -9,6 +9,7 @@ export type ListRowProps = {
|
|
|
9
9
|
locale: AdminLocale;
|
|
10
10
|
fieldMap: Map<string, AdminFieldMeta>;
|
|
11
11
|
isSelected: boolean;
|
|
12
|
+
canWrite: boolean;
|
|
12
13
|
onToggleSelection: (rowId: string | number, checked: boolean) => void;
|
|
13
14
|
onOpenMenu: (event: MouseEvent<HTMLElement>, rowId: string | number) => void;
|
|
14
15
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AdminClient } from '../../client';
|
|
2
|
+
type AdminListRequestParams = {
|
|
3
|
+
limit?: number;
|
|
4
|
+
offset?: number;
|
|
5
|
+
q?: string;
|
|
6
|
+
sort?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
export declare function requestListItems(client: AdminClient, slug: string, params: AdminListRequestParams, requestKey: string): Promise<import("../..").AdminListResponse>;
|
|
10
|
+
export {};
|
|
@@ -11,6 +11,9 @@ type UseModelPageControllerOptions = {
|
|
|
11
11
|
t: (key: AdminTranslationKey, params?: Record<string, string | number>) => string;
|
|
12
12
|
};
|
|
13
13
|
export declare function useModelPageController({ client, slug, pathname, locationSearch, router, t, }: UseModelPageControllerOptions): {
|
|
14
|
+
canWrite: boolean;
|
|
15
|
+
bulkActionFormOpen: boolean;
|
|
16
|
+
isBulkSubmitting: boolean;
|
|
14
17
|
allVisibleSelected: boolean;
|
|
15
18
|
appliedFilters: Record<string, string>;
|
|
16
19
|
appliedQuery: string;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** Refresh server-owned fields without discarding an unsaved card draft. */
|
|
2
|
+
export declare function mergeObjectActionValues(values: Record<string, unknown>, baseline: Record<string, unknown>, item: Record<string, unknown>, editableNames: ReadonlySet<string>): Record<string, unknown>;
|
|
@@ -11,6 +11,7 @@ type UseObjectPageControllerOptions = {
|
|
|
11
11
|
t: (key: AdminTranslationKey, params?: Record<string, string | number>) => string;
|
|
12
12
|
};
|
|
13
13
|
export declare function useObjectPageController({ client, slug, id, listPath, router, t, }: UseObjectPageControllerOptions): {
|
|
14
|
+
canWrite: boolean;
|
|
14
15
|
actionsAnchorEl: HTMLElement | null;
|
|
15
16
|
activeActionSlug: string | null;
|
|
16
17
|
activeObjectAction: import("@xladmin-core/types").AdminObjectActionMeta | null;
|
|
@@ -23,6 +24,7 @@ export declare function useObjectPageController({ client, slug, id, listPath, ro
|
|
|
23
24
|
error: string | null;
|
|
24
25
|
fieldMap: Map<string, import("@xladmin-core/types").AdminFieldMeta>;
|
|
25
26
|
handleDelete: () => Promise<void>;
|
|
27
|
+
handleCloseDeletePreview: () => void;
|
|
26
28
|
handleFieldChange: (fieldName: string, nextValue: unknown) => void;
|
|
27
29
|
handleNavigateBack: () => void;
|
|
28
30
|
handleOpenDeletePreview: () => Promise<void>;
|
|
@@ -37,13 +39,12 @@ export declare function useObjectPageController({ client, slug, id, listPath, ro
|
|
|
37
39
|
isDirty: boolean;
|
|
38
40
|
isLoading: boolean;
|
|
39
41
|
isSaving: boolean;
|
|
42
|
+
isMutating: boolean;
|
|
43
|
+
objectActionFormOpen: boolean;
|
|
40
44
|
meta: import("@xladmin-core/types").AdminModelMeta | null;
|
|
41
45
|
objectActions: import("@xladmin-core/types").AdminObjectActionMeta[];
|
|
42
46
|
objectTitle: string;
|
|
43
47
|
setActionsAnchorEl: import("react").Dispatch<import("react").SetStateAction<HTMLElement | null>>;
|
|
44
|
-
setDeleteConfirmOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
45
|
-
setDeletePreview: import("react").Dispatch<import("react").SetStateAction<AdminDeletePreviewResponse | null>>;
|
|
46
|
-
setDeletePreviewError: import("react").Dispatch<import("react").SetStateAction<string | null>>;
|
|
47
48
|
values: Record<string, unknown>;
|
|
48
49
|
};
|
|
49
50
|
export {};
|