@dyrected/admin 2.5.33 → 2.5.35
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/dist/components/forms/utils.d.ts +39 -0
- package/dist/index.d.ts +52 -2
- package/dist/index.mjs +119 -7
- package/dist/lib/admin-icons.d.ts +11 -0
- package/dist/lib/filter-rules.d.ts +20 -4
- package/dist/lib/utils.d.ts +19 -0
- package/dist/providers/dyrected-provider.d.ts +7 -0
- package/dist/types/admin-components.d.ts +44 -0
- package/package.json +3 -3
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Field as FieldSchema } from '@dyrected/sdk';
|
|
2
2
|
import * as z from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Normalises a field's `options` array to the canonical `{ label, value }` shape.
|
|
5
|
+
* Accepts either a shorthand string array or the full object form.
|
|
6
|
+
*/
|
|
3
7
|
export declare function normalizeOptions(options: string[] | {
|
|
4
8
|
label: string;
|
|
5
9
|
value: string;
|
|
@@ -7,10 +11,45 @@ export declare function normalizeOptions(options: string[] | {
|
|
|
7
11
|
label: string;
|
|
8
12
|
value: string;
|
|
9
13
|
}[];
|
|
14
|
+
/**
|
|
15
|
+
* Builds a Zod schema shape from a collection's field definitions.
|
|
16
|
+
* Used by the form engine to validate the edit form before submission.
|
|
17
|
+
*
|
|
18
|
+
* @param fields - Field definitions from the collection schema.
|
|
19
|
+
* @param isEdit - When `true`, password fields accept an empty string (no change).
|
|
20
|
+
* @returns A record of Zod validators keyed by field name, suitable for `z.object(shape)`.
|
|
21
|
+
*/
|
|
10
22
|
export declare function buildSchemaShape(fields: FieldSchema[], isEdit?: boolean): Record<string, z.ZodTypeAny>;
|
|
23
|
+
/**
|
|
24
|
+
* Builds `react-hook-form` default values from a collection's field definitions
|
|
25
|
+
* and an existing document (or an empty object for new documents).
|
|
26
|
+
*
|
|
27
|
+
* Handles nested `object`, `array`, and `blocks` fields recursively.
|
|
28
|
+
* Relationship and image fields are normalised to their IDs.
|
|
29
|
+
* Password fields are always reset to `""` so they are never pre-filled.
|
|
30
|
+
*
|
|
31
|
+
* @param fields - Field definitions from the collection schema.
|
|
32
|
+
* @param defaults - Existing document data, or `{}` for a new document.
|
|
33
|
+
*/
|
|
11
34
|
export declare function buildDefaultValues(fields: FieldSchema[], defaults: any): any;
|
|
35
|
+
/**
|
|
36
|
+
* Flattens a nested `react-hook-form` errors object into a list of
|
|
37
|
+
* `{ path, message }` pairs for rendering under individual fields.
|
|
38
|
+
*
|
|
39
|
+
* @param errors - The `formState.errors` object from `react-hook-form`.
|
|
40
|
+
* @param path - Dot-notation prefix accumulated during recursion (omit when calling externally).
|
|
41
|
+
* @returns A flat array of field path / error message pairs.
|
|
42
|
+
*/
|
|
12
43
|
export declare function getFlatErrors(errors: Record<string, unknown>, path?: string): {
|
|
13
44
|
path: string;
|
|
14
45
|
message: string;
|
|
15
46
|
}[];
|
|
47
|
+
/**
|
|
48
|
+
* Formats a dot-notation field path into a human-readable label.
|
|
49
|
+
* Array indices are converted to 1-based "Item N" labels.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* formatPath("address.street") // → "Address > Street"
|
|
53
|
+
* formatPath("items.0.name") // → "Items > Item 1 > Name"
|
|
54
|
+
*/
|
|
16
55
|
export declare function formatPath(path: string): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import { DyrectedProviderProps } from './providers/dyrected-provider';
|
|
2
2
|
export type { AdminComponents, AdminSchemas, CollectionListSlotProps, DashboardSlotProps, } from './types/admin-components';
|
|
3
|
+
/**
|
|
4
|
+
* Props for the `<AdminUI />` embedded component.
|
|
5
|
+
*
|
|
6
|
+
* Use this when mounting the admin inside an existing React app or a
|
|
7
|
+
* framework-specific wrapper (Next.js, Nuxt, Astro, etc.).
|
|
8
|
+
*/
|
|
3
9
|
export interface AdminUIProps {
|
|
10
|
+
/** API key used to authenticate requests to the Dyrected backend. */
|
|
4
11
|
apiKey?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Base URL of the Dyrected backend API (e.g. `"https://example.com/dyrected"`).
|
|
14
|
+
* Defaults to `"/dyrected"` (same-origin).
|
|
15
|
+
*/
|
|
5
16
|
baseUrl?: string;
|
|
17
|
+
/** Site ID for multi-tenant deployments. Omit for single-site setups. */
|
|
6
18
|
siteId?: string;
|
|
7
19
|
/**
|
|
8
20
|
* The base path where the admin is mounted in the host app.
|
|
@@ -22,22 +34,60 @@ export interface AdminUIProps {
|
|
|
22
34
|
* <AdminUI onNavigate={(path) => navigateTo('/admin' + path)} ... />
|
|
23
35
|
*/
|
|
24
36
|
onNavigate?: (path: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Set to `true` when the admin is rendered inside a host app shell
|
|
39
|
+
* (e.g. inside a dashboard layout). Adjusts internal spacing and
|
|
40
|
+
* removes the standalone top-bar.
|
|
41
|
+
*/
|
|
25
42
|
isEmbedded?: boolean;
|
|
43
|
+
/** Custom component overrides for fields, dashboard slots, and collection list views. */
|
|
26
44
|
components?: DyrectedProviderProps['components'];
|
|
27
45
|
initialToken?: string;
|
|
28
46
|
defaultTechStack?: string;
|
|
29
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* The main admin UI component. Mount this inside your React app.
|
|
50
|
+
*
|
|
51
|
+
* Uses a `HashRouter` internally so it can be embedded without conflicting
|
|
52
|
+
* with the host app's router. If you need real URL history, use
|
|
53
|
+
* `renderAdminUI` with a custom router wrapper instead.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* <AdminUI baseUrl="/dyrected" apiKey="my-key" isEmbedded />
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
30
60
|
export declare function AdminUI({ apiKey, baseUrl, siteId, onNavigate, isEmbedded, components, initialToken, defaultTechStack, }: AdminUIProps): import("react/jsx-runtime").JSX.Element;
|
|
31
61
|
/**
|
|
32
|
-
*
|
|
33
|
-
* Useful for non-React frameworks
|
|
62
|
+
* Imperatively renders the Admin UI into a DOM element.
|
|
63
|
+
* Useful for non-React frameworks (Nuxt, Svelte, Vanilla JS, Web Components).
|
|
64
|
+
*
|
|
65
|
+
* @param container - The DOM element to mount into.
|
|
66
|
+
* @param props - Same props as `<AdminUI />`.
|
|
67
|
+
* @returns A cleanup function that unmounts the React root.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const cleanup = renderAdminUI(document.getElementById('admin')!, { baseUrl: '/dyrected' });
|
|
72
|
+
* // Later:
|
|
73
|
+
* cleanup();
|
|
74
|
+
* ```
|
|
34
75
|
*/
|
|
35
76
|
export declare function renderAdminUI(container: HTMLElement, props: AdminUIProps): () => void;
|
|
77
|
+
/** Props for the `<AdminStandalone />` self-contained iframe variant. */
|
|
36
78
|
export interface AdminStandaloneProps {
|
|
79
|
+
/** API key for authenticating backend requests. */
|
|
37
80
|
apiKey: string;
|
|
81
|
+
/** Base URL of the Dyrected backend API. */
|
|
38
82
|
baseUrl: string;
|
|
83
|
+
/** Site ID for multi-tenant deployments. */
|
|
39
84
|
siteId?: string;
|
|
40
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* A fully self-contained admin UI that uses a `MemoryRouter`.
|
|
88
|
+
* Intended for iframe or self-hosted deployments where the admin owns
|
|
89
|
+
* the entire page and does not share URL history with a host app.
|
|
90
|
+
*/
|
|
41
91
|
export declare function AdminStandalone({ apiKey, baseUrl, siteId }: AdminStandaloneProps): import("react/jsx-runtime").JSX.Element;
|
|
42
92
|
export { SetupPromptUI } from './pages/setup/setup-prompt';
|
|
43
93
|
export type { SetupPromptProps } from './pages/setup/setup-prompt';
|
package/dist/index.mjs
CHANGED
|
@@ -136,6 +136,13 @@ function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBas
|
|
|
136
136
|
children
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns the Dyrected admin context: the SDK client, current user, loaded
|
|
141
|
+
* schemas, auth helpers, and registered component overrides.
|
|
142
|
+
*
|
|
143
|
+
* Must be called within a component tree wrapped by `DyrectedProvider`.
|
|
144
|
+
* Throws if called outside of that context.
|
|
145
|
+
*/
|
|
139
146
|
var useDyrected = () => {
|
|
140
147
|
const context = useContext(DyrectedContext);
|
|
141
148
|
if (!context) throw new Error("useDyrected must be used within a DyrectedProvider");
|
|
@@ -156,9 +163,28 @@ function QueryProvider({ children }) {
|
|
|
156
163
|
//#endregion
|
|
157
164
|
//#region src/lib/utils.ts
|
|
158
165
|
var customTwMerge = extendTailwindMerge({ prefix: "dy-" });
|
|
166
|
+
/**
|
|
167
|
+
* Merges Tailwind class names, resolving conflicts with the `dy-` prefix.
|
|
168
|
+
* Drop-in replacement for `clsx` that handles Dyrected's scoped Tailwind build.
|
|
169
|
+
*/
|
|
159
170
|
function cn(...inputs) {
|
|
160
171
|
return customTwMerge(clsx(inputs));
|
|
161
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Resolves a media field value to an absolute URL.
|
|
175
|
+
*
|
|
176
|
+
* Handles three input shapes:
|
|
177
|
+
* - A fully-qualified URL (`https://...`) — returned as-is.
|
|
178
|
+
* - A root-relative path (`/uploads/...`) — origin prepended from `baseUrl`.
|
|
179
|
+
* - A bare filename or storage path (`default/photo.jpg`) — prefixed with `/api/media/`.
|
|
180
|
+
*
|
|
181
|
+
* Bare strings that look like document IDs (no extension, no slash) are returned
|
|
182
|
+
* as an empty string so they are not treated as media assets.
|
|
183
|
+
*
|
|
184
|
+
* @param val - A media field value: a URL string, storage path, or a document object with a `url` or `filename` property.
|
|
185
|
+
* @param baseUrl - The Dyrected backend base URL, used to build the origin for relative paths.
|
|
186
|
+
* @returns A fully-qualified URL string, or `""` if the value cannot be resolved.
|
|
187
|
+
*/
|
|
162
188
|
function getMediaUrl(val, baseUrl) {
|
|
163
189
|
if (!val) return "";
|
|
164
190
|
let baseOrigin = "";
|
|
@@ -193,9 +219,20 @@ function getMediaUrl(val, baseUrl) {
|
|
|
193
219
|
}
|
|
194
220
|
//#endregion
|
|
195
221
|
//#region src/lib/admin-icons.ts
|
|
222
|
+
/**
|
|
223
|
+
* Type guard — returns `true` if `value` is a string that matches a known
|
|
224
|
+
* Lucide icon name (i.e. a valid `AdminIconName`).
|
|
225
|
+
*/
|
|
196
226
|
function isAdminIconName(value) {
|
|
197
227
|
return typeof value === "string" && Object.prototype.hasOwnProperty.call(icons, value);
|
|
198
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Returns the Lucide icon component for `value` if it is a valid `AdminIconName`,
|
|
231
|
+
* otherwise returns `fallback`.
|
|
232
|
+
*
|
|
233
|
+
* @param value - An untrusted value that may or may not be an icon name.
|
|
234
|
+
* @param fallback - The icon to use when `value` is not a valid icon name.
|
|
235
|
+
*/
|
|
199
236
|
function resolveAdminIcon(value, fallback) {
|
|
200
237
|
return isAdminIconName(value) ? icons[value] : fallback;
|
|
201
238
|
}
|
|
@@ -893,7 +930,7 @@ function Dashboard() {
|
|
|
893
930
|
user,
|
|
894
931
|
schemas: resolvedSchemas
|
|
895
932
|
};
|
|
896
|
-
const dashboardSlots = resolvedSchemas
|
|
933
|
+
const dashboardSlots = resolvedSchemas?.admin?.components;
|
|
897
934
|
if (collections.length === 0 && globals.length === 0) return /* @__PURE__ */ jsxs("div", {
|
|
898
935
|
className: "dy-space-y-6",
|
|
899
936
|
children: [
|
|
@@ -1565,8 +1602,12 @@ function FilterBuilder({ schema, rules, onChange }) {
|
|
|
1565
1602
|
//#endregion
|
|
1566
1603
|
//#region src/lib/filter-rules.ts
|
|
1567
1604
|
/**
|
|
1568
|
-
* Converts an array of
|
|
1569
|
-
* All rules are
|
|
1605
|
+
* Converts an array of `FilterRule`s into a flat `WhereClause`.
|
|
1606
|
+
* All rules are AND'd together. When the same field appears more than once
|
|
1607
|
+
* the extra conditions are moved into the top-level `AND` array.
|
|
1608
|
+
*
|
|
1609
|
+
* @param rules - Active filter rules from the filter builder UI.
|
|
1610
|
+
* @returns A `WhereClause` ready to pass to `collection.find({ where })`.
|
|
1570
1611
|
*/
|
|
1571
1612
|
function rulesToWhere(rules) {
|
|
1572
1613
|
if (!rules || rules.length === 0) return {};
|
|
@@ -1582,8 +1623,12 @@ function rulesToWhere(rules) {
|
|
|
1582
1623
|
return clause;
|
|
1583
1624
|
}
|
|
1584
1625
|
/**
|
|
1585
|
-
* Converts a flat WhereClause back into an array of
|
|
1586
|
-
* Best
|
|
1626
|
+
* Converts a flat `WhereClause` back into an array of `FilterRule`s.
|
|
1627
|
+
* Best-effort: nested `AND` conditions are unpacked; `OR` clauses are ignored.
|
|
1628
|
+
* Used to restore filter builder state from the URL `?where=` param.
|
|
1629
|
+
*
|
|
1630
|
+
* @param where - A `WhereClause` object, typically parsed from the URL.
|
|
1631
|
+
* @returns An array of `FilterRule`s suitable for rendering in the filter builder.
|
|
1587
1632
|
*/
|
|
1588
1633
|
function whereToRules(where) {
|
|
1589
1634
|
if (!where || Object.keys(where).length === 0) return [];
|
|
@@ -2802,6 +2847,10 @@ var TabsContent = React$1.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
2802
2847
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
2803
2848
|
//#endregion
|
|
2804
2849
|
//#region src/components/forms/utils.ts
|
|
2850
|
+
/**
|
|
2851
|
+
* Normalises a field's `options` array to the canonical `{ label, value }` shape.
|
|
2852
|
+
* Accepts either a shorthand string array or the full object form.
|
|
2853
|
+
*/
|
|
2805
2854
|
function normalizeOptions(options) {
|
|
2806
2855
|
if (!options) return [];
|
|
2807
2856
|
return options.map((opt) => typeof opt === "string" ? {
|
|
@@ -2809,6 +2858,14 @@ function normalizeOptions(options) {
|
|
|
2809
2858
|
value: opt
|
|
2810
2859
|
} : opt);
|
|
2811
2860
|
}
|
|
2861
|
+
/**
|
|
2862
|
+
* Builds a Zod schema shape from a collection's field definitions.
|
|
2863
|
+
* Used by the form engine to validate the edit form before submission.
|
|
2864
|
+
*
|
|
2865
|
+
* @param fields - Field definitions from the collection schema.
|
|
2866
|
+
* @param isEdit - When `true`, password fields accept an empty string (no change).
|
|
2867
|
+
* @returns A record of Zod validators keyed by field name, suitable for `z.object(shape)`.
|
|
2868
|
+
*/
|
|
2812
2869
|
function buildSchemaShape(fields, isEdit = false) {
|
|
2813
2870
|
const shape = {};
|
|
2814
2871
|
fields.forEach((field) => {
|
|
@@ -2891,6 +2948,17 @@ function buildSchemaShape(fields, isEdit = false) {
|
|
|
2891
2948
|
});
|
|
2892
2949
|
return shape;
|
|
2893
2950
|
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Builds `react-hook-form` default values from a collection's field definitions
|
|
2953
|
+
* and an existing document (or an empty object for new documents).
|
|
2954
|
+
*
|
|
2955
|
+
* Handles nested `object`, `array`, and `blocks` fields recursively.
|
|
2956
|
+
* Relationship and image fields are normalised to their IDs.
|
|
2957
|
+
* Password fields are always reset to `""` so they are never pre-filled.
|
|
2958
|
+
*
|
|
2959
|
+
* @param fields - Field definitions from the collection schema.
|
|
2960
|
+
* @param defaults - Existing document data, or `{}` for a new document.
|
|
2961
|
+
*/
|
|
2894
2962
|
function buildDefaultValues(fields, defaults) {
|
|
2895
2963
|
return fields.reduce((acc, field) => {
|
|
2896
2964
|
if (field.type === "join") {
|
|
@@ -2939,6 +3007,14 @@ function buildDefaultValues(fields, defaults) {
|
|
|
2939
3007
|
return acc;
|
|
2940
3008
|
}, {});
|
|
2941
3009
|
}
|
|
3010
|
+
/**
|
|
3011
|
+
* Flattens a nested `react-hook-form` errors object into a list of
|
|
3012
|
+
* `{ path, message }` pairs for rendering under individual fields.
|
|
3013
|
+
*
|
|
3014
|
+
* @param errors - The `formState.errors` object from `react-hook-form`.
|
|
3015
|
+
* @param path - Dot-notation prefix accumulated during recursion (omit when calling externally).
|
|
3016
|
+
* @returns A flat array of field path / error message pairs.
|
|
3017
|
+
*/
|
|
2942
3018
|
function getFlatErrors(errors, path = "") {
|
|
2943
3019
|
const result = [];
|
|
2944
3020
|
if (!errors) return result;
|
|
@@ -2959,6 +3035,14 @@ function getFlatErrors(errors, path = "") {
|
|
|
2959
3035
|
}
|
|
2960
3036
|
return result;
|
|
2961
3037
|
}
|
|
3038
|
+
/**
|
|
3039
|
+
* Formats a dot-notation field path into a human-readable label.
|
|
3040
|
+
* Array indices are converted to 1-based "Item N" labels.
|
|
3041
|
+
*
|
|
3042
|
+
* @example
|
|
3043
|
+
* formatPath("address.street") // → "Address > Street"
|
|
3044
|
+
* formatPath("items.0.name") // → "Items > Item 1 > Name"
|
|
3045
|
+
*/
|
|
2962
3046
|
function formatPath(path) {
|
|
2963
3047
|
return path.split(".").map((part) => {
|
|
2964
3048
|
if (/^\d+$/.test(part)) return `Item ${parseInt(part, 10) + 1}`;
|
|
@@ -11170,6 +11254,18 @@ function AdminRoutes({ onNavigate, isEmbedded = false }) {
|
|
|
11170
11254
|
] }) })]
|
|
11171
11255
|
}) });
|
|
11172
11256
|
}
|
|
11257
|
+
/**
|
|
11258
|
+
* The main admin UI component. Mount this inside your React app.
|
|
11259
|
+
*
|
|
11260
|
+
* Uses a `HashRouter` internally so it can be embedded without conflicting
|
|
11261
|
+
* with the host app's router. If you need real URL history, use
|
|
11262
|
+
* `renderAdminUI` with a custom router wrapper instead.
|
|
11263
|
+
*
|
|
11264
|
+
* @example
|
|
11265
|
+
* ```tsx
|
|
11266
|
+
* <AdminUI baseUrl="/dyrected" apiKey="my-key" isEmbedded />
|
|
11267
|
+
* ```
|
|
11268
|
+
*/
|
|
11173
11269
|
function AdminUI({ apiKey, baseUrl = "/dyrected", siteId, onNavigate, isEmbedded, components, initialToken, defaultTechStack }) {
|
|
11174
11270
|
const [mounted, setMounted] = useState(false);
|
|
11175
11271
|
useEffect(() => setMounted(true), []);
|
|
@@ -11201,14 +11297,30 @@ function AdminUI({ apiKey, baseUrl = "/dyrected", siteId, onNavigate, isEmbedded
|
|
|
11201
11297
|
});
|
|
11202
11298
|
}
|
|
11203
11299
|
/**
|
|
11204
|
-
*
|
|
11205
|
-
* Useful for non-React frameworks
|
|
11300
|
+
* Imperatively renders the Admin UI into a DOM element.
|
|
11301
|
+
* Useful for non-React frameworks (Nuxt, Svelte, Vanilla JS, Web Components).
|
|
11302
|
+
*
|
|
11303
|
+
* @param container - The DOM element to mount into.
|
|
11304
|
+
* @param props - Same props as `<AdminUI />`.
|
|
11305
|
+
* @returns A cleanup function that unmounts the React root.
|
|
11306
|
+
*
|
|
11307
|
+
* @example
|
|
11308
|
+
* ```ts
|
|
11309
|
+
* const cleanup = renderAdminUI(document.getElementById('admin')!, { baseUrl: '/dyrected' });
|
|
11310
|
+
* // Later:
|
|
11311
|
+
* cleanup();
|
|
11312
|
+
* ```
|
|
11206
11313
|
*/
|
|
11207
11314
|
function renderAdminUI(container, props) {
|
|
11208
11315
|
const root = createRoot(container);
|
|
11209
11316
|
root.render(React.createElement(StrictMode, null, React.createElement(AdminUI, props)));
|
|
11210
11317
|
return () => root.unmount();
|
|
11211
11318
|
}
|
|
11319
|
+
/**
|
|
11320
|
+
* A fully self-contained admin UI that uses a `MemoryRouter`.
|
|
11321
|
+
* Intended for iframe or self-hosted deployments where the admin owns
|
|
11322
|
+
* the entire page and does not share URL history with a host app.
|
|
11323
|
+
*/
|
|
11212
11324
|
function AdminStandalone({ apiKey, baseUrl, siteId }) {
|
|
11213
11325
|
return /* @__PURE__ */ jsx("div", {
|
|
11214
11326
|
className: "dy-admin-ui dy-h-full",
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { LucideIcon } from 'lucide-react';
|
|
2
2
|
import { AdminIconName } from '@dyrected/core';
|
|
3
|
+
/**
|
|
4
|
+
* Type guard — returns `true` if `value` is a string that matches a known
|
|
5
|
+
* Lucide icon name (i.e. a valid `AdminIconName`).
|
|
6
|
+
*/
|
|
3
7
|
export declare function isAdminIconName(value: unknown): value is AdminIconName;
|
|
8
|
+
/**
|
|
9
|
+
* Returns the Lucide icon component for `value` if it is a valid `AdminIconName`,
|
|
10
|
+
* otherwise returns `fallback`.
|
|
11
|
+
*
|
|
12
|
+
* @param value - An untrusted value that may or may not be an icon name.
|
|
13
|
+
* @param fallback - The icon to use when `value` is not a valid icon name.
|
|
14
|
+
*/
|
|
4
15
|
export declare function resolveAdminIcon(value: unknown, fallback: LucideIcon): LucideIcon;
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import { WhereClause, WhereOperatorName } from '@dyrected/core';
|
|
2
|
+
/**
|
|
3
|
+
* A single filter rule in the admin filter builder.
|
|
4
|
+
* An array of rules is AND'd together and converted to a `WhereClause`
|
|
5
|
+
* before being passed to `collection.find({ where })`.
|
|
6
|
+
*/
|
|
2
7
|
export interface FilterRule {
|
|
8
|
+
/** Field name from the collection schema. */
|
|
3
9
|
field: string;
|
|
10
|
+
/** Comparison operator (e.g. `"equals"`, `"contains"`, `"gt"`). */
|
|
4
11
|
operator: WhereOperatorName;
|
|
12
|
+
/** Comparison value. `undefined` when the operator is `"exists"`. */
|
|
5
13
|
value: unknown;
|
|
6
14
|
}
|
|
7
15
|
/**
|
|
8
|
-
* Converts an array of
|
|
9
|
-
* All rules are
|
|
16
|
+
* Converts an array of `FilterRule`s into a flat `WhereClause`.
|
|
17
|
+
* All rules are AND'd together. When the same field appears more than once
|
|
18
|
+
* the extra conditions are moved into the top-level `AND` array.
|
|
19
|
+
*
|
|
20
|
+
* @param rules - Active filter rules from the filter builder UI.
|
|
21
|
+
* @returns A `WhereClause` ready to pass to `collection.find({ where })`.
|
|
10
22
|
*/
|
|
11
23
|
export declare function rulesToWhere(rules: FilterRule[]): WhereClause;
|
|
12
24
|
/**
|
|
13
|
-
* Converts a flat WhereClause back into an array of
|
|
14
|
-
* Best
|
|
25
|
+
* Converts a flat `WhereClause` back into an array of `FilterRule`s.
|
|
26
|
+
* Best-effort: nested `AND` conditions are unpacked; `OR` clauses are ignored.
|
|
27
|
+
* Used to restore filter builder state from the URL `?where=` param.
|
|
28
|
+
*
|
|
29
|
+
* @param where - A `WhereClause` object, typically parsed from the URL.
|
|
30
|
+
* @returns An array of `FilterRule`s suitable for rendering in the filter builder.
|
|
15
31
|
*/
|
|
16
32
|
export declare function whereToRules(where: WhereClause | undefined): FilterRule[];
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
1
|
import { ClassValue } from 'clsx';
|
|
2
|
+
/**
|
|
3
|
+
* Merges Tailwind class names, resolving conflicts with the `dy-` prefix.
|
|
4
|
+
* Drop-in replacement for `clsx` that handles Dyrected's scoped Tailwind build.
|
|
5
|
+
*/
|
|
2
6
|
export declare function cn(...inputs: ClassValue[]): string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves a media field value to an absolute URL.
|
|
9
|
+
*
|
|
10
|
+
* Handles three input shapes:
|
|
11
|
+
* - A fully-qualified URL (`https://...`) — returned as-is.
|
|
12
|
+
* - A root-relative path (`/uploads/...`) — origin prepended from `baseUrl`.
|
|
13
|
+
* - A bare filename or storage path (`default/photo.jpg`) — prefixed with `/api/media/`.
|
|
14
|
+
*
|
|
15
|
+
* Bare strings that look like document IDs (no extension, no slash) are returned
|
|
16
|
+
* as an empty string so they are not treated as media assets.
|
|
17
|
+
*
|
|
18
|
+
* @param val - A media field value: a URL string, storage path, or a document object with a `url` or `filename` property.
|
|
19
|
+
* @param baseUrl - The Dyrected backend base URL, used to build the origin for relative paths.
|
|
20
|
+
* @returns A fully-qualified URL string, or `""` if the value cannot be resolved.
|
|
21
|
+
*/
|
|
3
22
|
export declare function getMediaUrl(val: string | any, baseUrl: string): string;
|
|
@@ -28,5 +28,12 @@ export interface DyrectedProviderProps {
|
|
|
28
28
|
components?: DyrectedContextType['components'];
|
|
29
29
|
}
|
|
30
30
|
export declare function DyrectedProvider({ children, apiKey: initialApiKey, baseUrl: initialBaseUrl, siteId: initialSiteId, initialToken, defaultTechStack, components }: DyrectedProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the Dyrected admin context: the SDK client, current user, loaded
|
|
33
|
+
* schemas, auth helpers, and registered component overrides.
|
|
34
|
+
*
|
|
35
|
+
* Must be called within a component tree wrapped by `DyrectedProvider`.
|
|
36
|
+
* Throws if called outside of that context.
|
|
37
|
+
*/
|
|
31
38
|
export declare const useDyrected: () => DyrectedContextType;
|
|
32
39
|
export {};
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
import { ComponentType } from 'react';
|
|
2
2
|
import { AdminConfig, CollectionConfig, GlobalConfig } from '@dyrected/core';
|
|
3
3
|
import { DyrectedClient, PaginatedResult } from '@dyrected/sdk';
|
|
4
|
+
/** All collection and global schemas returned by the backend, plus optional admin config. */
|
|
4
5
|
export interface AdminSchemas {
|
|
5
6
|
collections: CollectionConfig[];
|
|
6
7
|
globals: GlobalConfig[];
|
|
7
8
|
admin?: AdminConfig;
|
|
8
9
|
}
|
|
10
|
+
/** Props injected into custom dashboard slot components. */
|
|
9
11
|
export interface DashboardSlotProps {
|
|
12
|
+
/** Authenticated SDK client — use this to call any API. */
|
|
10
13
|
client: DyrectedClient;
|
|
14
|
+
/** Currently logged-in user document, or `null` when unauthenticated. */
|
|
11
15
|
user: Record<string, unknown> | null;
|
|
16
|
+
/** All schemas loaded from the backend. */
|
|
12
17
|
schemas: AdminSchemas;
|
|
13
18
|
}
|
|
19
|
+
/** Props injected into custom collection list slot components. */
|
|
14
20
|
export interface CollectionListSlotProps {
|
|
21
|
+
/** Authenticated SDK client. */
|
|
15
22
|
client: DyrectedClient;
|
|
23
|
+
/** Currently logged-in user document, or `null` when unauthenticated. */
|
|
16
24
|
user: Record<string, unknown> | null;
|
|
25
|
+
/** Schema config for the collection being rendered. */
|
|
17
26
|
collection: CollectionConfig;
|
|
27
|
+
/** URL slug of the collection (e.g. `"posts"`). */
|
|
18
28
|
collectionSlug: string;
|
|
29
|
+
/** Raw paginated response from the last `find()` call. */
|
|
19
30
|
response: PaginatedResult<Record<string, unknown>> | undefined;
|
|
31
|
+
/** Unwrapped document array from `response`. */
|
|
20
32
|
documents: Record<string, unknown>[];
|
|
33
|
+
/** `true` while the list query is in-flight. */
|
|
21
34
|
isLoading: boolean;
|
|
22
35
|
pagination: {
|
|
23
36
|
page: number;
|
|
@@ -27,16 +40,47 @@ export interface CollectionListSlotProps {
|
|
|
27
40
|
hasPrevPage: boolean;
|
|
28
41
|
};
|
|
29
42
|
permissions: {
|
|
43
|
+
/** Whether the current user may read documents in this collection. */
|
|
30
44
|
canRead: boolean;
|
|
45
|
+
/** Whether the current user may create new documents. */
|
|
31
46
|
canCreate: boolean;
|
|
32
47
|
};
|
|
33
48
|
urls: {
|
|
49
|
+
/** Admin URL for the collection list view. */
|
|
34
50
|
collection: string;
|
|
51
|
+
/** Admin URL for the new-document form. */
|
|
35
52
|
create: string;
|
|
36
53
|
};
|
|
37
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Custom component overrides passed to `<DyrectedAdmin />`.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* <DyrectedAdmin
|
|
61
|
+
* components={{
|
|
62
|
+
* fields: { color: ColorPickerField },
|
|
63
|
+
* dashboard: { analytics: AnalyticsWidget },
|
|
64
|
+
* collectionList: { posts: PostsListView },
|
|
65
|
+
* }}
|
|
66
|
+
* />
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
38
69
|
export interface AdminComponents {
|
|
70
|
+
/**
|
|
71
|
+
* Custom field renderers keyed by field type name.
|
|
72
|
+
* A component registered here replaces the built-in renderer for every
|
|
73
|
+
* field whose `type` matches the key.
|
|
74
|
+
*/
|
|
39
75
|
fields?: Record<string, ComponentType<any>>;
|
|
76
|
+
/**
|
|
77
|
+
* Custom dashboard slot components keyed by a slot name of your choice.
|
|
78
|
+
* All registered components are rendered inside the dashboard page.
|
|
79
|
+
*/
|
|
40
80
|
dashboard?: Record<string, ComponentType<DashboardSlotProps>>;
|
|
81
|
+
/**
|
|
82
|
+
* Custom collection list slot components keyed by collection slug.
|
|
83
|
+
* The registered component replaces the entire list view for that collection.
|
|
84
|
+
*/
|
|
41
85
|
collectionList?: Record<string, ComponentType<CollectionListSlotProps>>;
|
|
42
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dyrected/admin",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"tailwind-merge": "^3.5.0",
|
|
63
63
|
"tailwindcss-animate": "^1.0.7",
|
|
64
64
|
"zod": "^3.25.76",
|
|
65
|
-
"@dyrected/core": "^2.5.
|
|
66
|
-
"@dyrected/sdk": "^2.5.
|
|
65
|
+
"@dyrected/core": "^2.5.35",
|
|
66
|
+
"@dyrected/sdk": "^2.5.35"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@tanstack/react-query": "^5.0.0",
|