@donotdev/ui 0.0.14 → 0.0.16
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/common/TechBento.d.ts.map +1 -1
- package/dist/components/common/TechBento.js +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.js +2 -2
- package/dist/components/layout/components/index.d.ts +3 -0
- package/dist/components/layout/components/index.d.ts.map +1 -1
- package/dist/components/layout/components/index.js +3 -0
- package/dist/crud/components/CrudCardLink.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.d.ts +1 -1
- package/dist/crud/components/EntityCardList.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.js +24 -35
- package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
- package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
- package/dist/crud/components/EntityDisplayRenderer.js +6 -2
- package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
- package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
- package/dist/crud/components/EntityFormRenderer.js +12 -29
- package/dist/crud/components/EntityList.d.ts.map +1 -1
- package/dist/crud/components/EntityList.js +7 -43
- package/dist/crud/components/EntityRecommendations.d.ts +1 -0
- package/dist/crud/components/EntityRecommendations.d.ts.map +1 -1
- package/dist/crud/components/EntityRecommendations.js +3 -2
- package/dist/dndev.css +11581 -0
- package/dist/index.js +4 -4
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.js +2 -9
- package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -1
- package/dist/internal/layout/components/FontPreloadLinks.js +1 -0
- package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
- package/dist/internal/providers/NavigationProvider.d.ts.map +1 -1
- package/dist/internal/providers/NavigationProvider.js +3 -5
- package/dist/providers/ViteAppProviders.d.ts.map +1 -1
- package/dist/providers/ViteAppProviders.js +3 -5
- package/dist/routing/GoToInput.d.ts.map +1 -1
- package/dist/routing/GoToInput.js +6 -6
- package/dist/routing/Link.d.ts.map +1 -1
- package/dist/routing/hooks/hooks.next.js +1 -1
- package/dist/routing/hooks/hooks.vite.js +1 -1
- package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
- package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
- package/dist/routing/hooks/useNavigate.next.js +1 -7
- package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
- package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
- package/dist/routing/hooks/useNavigate.vite.js +1 -7
- package/dist/routing/useRouteDiscovery.d.ts +4 -15
- package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
- package/dist/routing/useRouteDiscovery.js +6 -5
- package/dist/styles/index.css +96 -63
- package/dist/utils/sanitizeSvg.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.d.ts +2 -15
- package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.js +3 -33
- package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.js +1 -1
- package/dist/vite-routing/RootLayout.d.ts.map +1 -1
- package/dist/vite-routing/RootLayout.js +10 -15
- package/package.json +10 -10
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts +0 -14
- package/dist/routing/hooks/useFormNavigationBlocker.d.ts.map +0 -1
- package/dist/routing/hooks/useFormNavigationBlocker.js +0 -42
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TechBento.d.ts","sourceRoot":"","sources":["../../../src/components/common/TechBento.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TechBento.d.ts","sourceRoot":"","sources":["../../../src/components/common/TechBento.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,IAAI,EACL,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAK/D,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,OAAO,CAAC;QACd,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;QAC3C,OAAO,CAAC,EAAE,WAAW,CAAC;KACvB,CAAC,CAAC;IACH;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAC/B;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uEAAuE;IACvE,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA0CF,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,KAAK,EACL,IAAQ,EACR,OAAO,EACP,GAAc,EACd,SAAiB,EACjB,IAAiB,EACjB,KAAK,EACL,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,SAAS,GACV,EAAE,cAAc,2CA4DhB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// packages/ui/src/components/common/TechBento.tsx
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { Bento, Card, Section, Stack, Text, TONE, cn } from '@donotdev/components';
|
|
4
|
+
import { Bento, Card, Section, Stack, Text, TONE, cn, } from '@donotdev/components';
|
|
5
5
|
import { techLogos } from '../../data/techLogos';
|
|
6
6
|
import { sanitizeSvg } from '../../utils/sanitizeSvg';
|
|
7
7
|
function TechCard({ techKey, variant, }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeaderNavigation.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/components/header/HeaderNavigation.tsx"],"names":[],"mappings":"AAsBA,OAAO,EACL,OAAO,EAIR,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"HeaderNavigation.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/components/header/HeaderNavigation.tsx"],"names":[],"mappings":"AAsBA,OAAO,EACL,OAAO,EAIR,MAAM,sBAAsB,CAAC;AAa9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IACpC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;IACjD;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,gBAAgB,EAAE,aAAa,CAAC,qBAAqB,CA4E1D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -24,7 +24,7 @@ import { Link } from '../../../../routing/Link';
|
|
|
24
24
|
import { Icon } from '../../../common/icon';
|
|
25
25
|
import { DnDevNavigationMenu } from '../../../../routing/DnDevNavigationMenu';
|
|
26
26
|
import { NavigationItemComponent } from '../../../../routing/NavigationItem';
|
|
27
|
-
import { useNavigationItems, useNavigationRoute } from '../../../../routing/useNavigation';
|
|
27
|
+
import { useNavigationItems, useNavigationRoute, } from '../../../../routing/useNavigation';
|
|
28
28
|
/**
|
|
29
29
|
* HeaderNavigation - DISPLAY-aware adaptive navigation component
|
|
30
30
|
*
|
|
@@ -47,7 +47,7 @@ const HeaderNavigation = ({ className = '', showIcons = true, display = DISPLAY.
|
|
|
47
47
|
if (path) {
|
|
48
48
|
if (!singleRoute)
|
|
49
49
|
return null;
|
|
50
|
-
return (_jsx(Button, { variant: "ghost", display: display, icon: showIcons ? _jsx(Icon, { icon: singleRoute.icon, fallback: LinkIcon }) : undefined, className: className, render: ({ children, ...props }) => (_jsx(Link, { path: singleRoute.path, ...props, children: children })), children: singleRoute.label }));
|
|
50
|
+
return (_jsx(Button, { variant: "ghost", display: display, icon: showIcons ? (_jsx(Icon, { icon: singleRoute.icon, fallback: LinkIcon })) : undefined, className: className, render: ({ children, ...props }) => (_jsx(Link, { path: singleRoute.path, ...props, children: children })), children: singleRoute.label }));
|
|
51
51
|
}
|
|
52
52
|
const effectiveDisplay = display === DISPLAY.AUTO
|
|
53
53
|
? isMobile || isTablet
|
|
@@ -19,4 +19,7 @@ export { default as HeaderNavigation } from './header/HeaderNavigation';
|
|
|
19
19
|
export { default as Notifications } from './Notifications';
|
|
20
20
|
export { default as SettingsMenu } from './header/SettingsMenu';
|
|
21
21
|
export { default as ThemeToggle } from './header/ThemeToggle';
|
|
22
|
+
export { FooterBranding } from '../../../internal/layout/components/footer/FooterBranding';
|
|
23
|
+
export { FooterCopyright } from '../../../internal/layout/components/footer/FooterCopyright';
|
|
24
|
+
export { FooterLegalLinks } from '../../../internal/layout/components/footer/FooterLegalLinks';
|
|
22
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,2DAA2D,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,4DAA4D,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,6DAA6D,CAAC"}
|
|
@@ -20,3 +20,6 @@ export { default as HeaderNavigation } from './header/HeaderNavigation';
|
|
|
20
20
|
export { default as Notifications } from './Notifications';
|
|
21
21
|
export { default as SettingsMenu } from './header/SettingsMenu';
|
|
22
22
|
export { default as ThemeToggle } from './header/ThemeToggle';
|
|
23
|
+
export { FooterBranding } from '../../../internal/layout/components/footer/FooterBranding';
|
|
24
|
+
export { FooterCopyright } from '../../../internal/layout/components/footer/FooterCopyright';
|
|
25
|
+
export { FooterLegalLinks } from '../../../internal/layout/components/footer/FooterLegalLinks';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrudCardLink.d.ts","sourceRoot":"","sources":["../../../src/crud/components/CrudCardLink.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"CrudCardLink.d.ts","sourceRoot":"","sources":["../../../src/crud/components/CrudCardLink.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,aAAa,2CAkBvE;AAED,eAAe,QAAQ,CAAC"}
|
|
@@ -12,5 +12,5 @@ export type { EntityCardListProps };
|
|
|
12
12
|
* - Auto-routing when handler not provided
|
|
13
13
|
*/
|
|
14
14
|
export declare function EntityCardList({ entity, basePath, onClick, cols, staleTime, // 30 minutes default cache
|
|
15
|
-
filter, hideFilters, }: EntityCardListProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
filter, hideFilters, resultLabel, tone, }: EntityCardListProps): import("react/jsx-runtime").JSX.Element;
|
|
16
16
|
//# sourceMappingURL=EntityCardList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,gBAAgB,CAAC;AAIxE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAmB,EACnB,SAA0B,EAAE,2BAA2B;AACvD,MAAM,EACN,WAAmB,
|
|
1
|
+
{"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,gBAAgB,CAAC;AAIxE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAmB,EACnB,SAA0B,EAAE,2BAA2B;AACvD,MAAM,EACN,WAAmB,EACnB,WAAW,EACX,IAAI,GACL,EAAE,mBAAmB,2CA2LrB"}
|
|
@@ -9,16 +9,16 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
* **Routing:** Convention basePath = `/${collection}`. View = basePath/:id.
|
|
10
10
|
* Override basePath for nested routes; use onClick(id) to open sheet instead of navigating.
|
|
11
11
|
*
|
|
12
|
-
* @version 0.
|
|
12
|
+
* @version 0.3.0
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @author AMBROISE PARK Consulting
|
|
15
15
|
*/
|
|
16
16
|
import { useMemo, useCallback } from 'react';
|
|
17
17
|
import { Heart } from 'lucide-react';
|
|
18
|
-
import { Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
|
|
18
|
+
import { Card, Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
|
|
19
19
|
import { useTranslation, getListCardFieldNames } from '@donotdev/core';
|
|
20
20
|
import { useNavigate } from '../../routing';
|
|
21
|
-
import { useCrudCardList, EntityFilters, useEntityFavorites,
|
|
21
|
+
import { useCrudCardList, EntityFilters, useEntityFavorites, useCrudFilters, } from '@donotdev/crud';
|
|
22
22
|
import { CrudCard } from './CrudCardLink';
|
|
23
23
|
/**
|
|
24
24
|
* Entity Card List Component - Card grid view for public/user-facing browsing
|
|
@@ -32,36 +32,22 @@ import { CrudCard } from './CrudCardLink';
|
|
|
32
32
|
* - Auto-routing when handler not provided
|
|
33
33
|
*/
|
|
34
34
|
export function EntityCardList({ entity, basePath, onClick, cols = [1, 2, 3, 4], staleTime = 1000 * 60 * 30, // 30 minutes default cache
|
|
35
|
-
filter, hideFilters = false, }) {
|
|
35
|
+
filter, hideFilters = false, resultLabel, tone, }) {
|
|
36
36
|
const navigate = useNavigate();
|
|
37
37
|
const base = basePath ?? `/${entity.collection}`;
|
|
38
|
-
// useCrudCardList -> handles fetching
|
|
39
|
-
const {
|
|
40
|
-
const rawData = listData?.items || [];
|
|
38
|
+
// useCrudCardList -> handles fetching + client-side filter/search/sort via `processed`
|
|
39
|
+
const { items: rawData, processed, loading, } = useCrudCardList(entity, { staleTime });
|
|
41
40
|
// Favorites - always enabled, no props needed
|
|
42
41
|
const { isFavorite, toggleFavorite, favoritesFilter } = useEntityFavorites({
|
|
43
42
|
collection: entity.collection,
|
|
44
43
|
});
|
|
45
44
|
// Favorites toggle from CrudStore (persists across navigation)
|
|
46
|
-
|
|
47
|
-
const { showFavoritesOnly, setShowFavoritesOnly, filters } = useCrudFilters({
|
|
45
|
+
const { showFavoritesOnly, setShowFavoritesOnly } = useCrudFilters({
|
|
48
46
|
collection: entity.collection,
|
|
49
47
|
});
|
|
50
|
-
// Apply filters
|
|
51
|
-
const applyFilters = useCallback((item) => {
|
|
52
|
-
if (Object.keys(filters).length === 0)
|
|
53
|
-
return true;
|
|
54
|
-
return Object.entries(filters).every(([fieldName, filterValue]) => {
|
|
55
|
-
const itemValue = item[fieldName];
|
|
56
|
-
const fieldConfig = entity.fields[fieldName];
|
|
57
|
-
const fieldType = fieldConfig?.type || 'text';
|
|
58
|
-
return matchesFilter(itemValue, filterValue, fieldType);
|
|
59
|
-
});
|
|
60
|
-
}, [filters, entity.fields]);
|
|
61
|
-
// Apply client-side filtering (including favorites)
|
|
48
|
+
// Apply UI-specific filters (favorites, consumer filter prop) on top of processed
|
|
62
49
|
const data = useMemo(() => {
|
|
63
|
-
let result =
|
|
64
|
-
result = result.filter(applyFilters);
|
|
50
|
+
let result = processed;
|
|
65
51
|
// Apply favorites filter if enabled
|
|
66
52
|
if (showFavoritesOnly) {
|
|
67
53
|
result = result.filter(favoritesFilter);
|
|
@@ -70,7 +56,7 @@ filter, hideFilters = false, }) {
|
|
|
70
56
|
result = result.filter(filter);
|
|
71
57
|
}
|
|
72
58
|
return result;
|
|
73
|
-
}, [
|
|
59
|
+
}, [processed, showFavoritesOnly, favoritesFilter, filter]);
|
|
74
60
|
// Entity + crud namespaces so formatValue can resolve crud:price.* etc.
|
|
75
61
|
const { t } = useTranslation([entity.namespace, 'crud']);
|
|
76
62
|
const { t: tCrud } = useTranslation('crud');
|
|
@@ -89,18 +75,20 @@ filter, hideFilters = false, }) {
|
|
|
89
75
|
return (_jsxs(_Fragment, { children: [!hideFilters && (_jsx(Section, { title: tCrud('filters.title', {
|
|
90
76
|
entity: entityName,
|
|
91
77
|
defaultValue: `Browse ${entityName} - Filters`,
|
|
92
|
-
}), collapsible: true, defaultOpen: true, children: _jsxs(Stack, { direction: "column", children: [_jsx(Button, { variant: showFavoritesOnly ? 'primary' : 'outline', icon: _jsx(Heart, { size: 18 }), onClick: () => setShowFavoritesOnly(!showFavoritesOnly), children: showFavoritesOnly
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
}), collapsible: true, defaultOpen: true, tone: tone, children: _jsx(Card, { children: _jsxs(Stack, { direction: "column", children: [_jsx(Button, { variant: showFavoritesOnly ? 'primary' : 'outline', icon: _jsx(Heart, { size: 18 }), onClick: () => setShowFavoritesOnly(!showFavoritesOnly), children: showFavoritesOnly
|
|
79
|
+
? tCrud('favorites.showAll', { defaultValue: 'Show All' })
|
|
80
|
+
: tCrud('favorites.showFavorites', {
|
|
81
|
+
defaultValue: 'Show Favorites',
|
|
82
|
+
}) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: fieldsToFilter })] }) }) })), _jsx(Section, { title: loading
|
|
97
83
|
? tCrud('results.title.fetching', { defaultValue: 'Fetching...' })
|
|
98
|
-
:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:
|
|
103
|
-
|
|
84
|
+
: resultLabel
|
|
85
|
+
? resultLabel(data.length)
|
|
86
|
+
: tCrud('results.title.count', {
|
|
87
|
+
count: data.length,
|
|
88
|
+
defaultValue: data.length === 1
|
|
89
|
+
? 'Found 1 occurrence'
|
|
90
|
+
: `Found ${data.length} occurrences`,
|
|
91
|
+
}), collapsible: true, defaultOpen: true, tone: tone, children: loading ? (_jsx(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)' }, children: _jsx(Spinner, {}) })) : data.length === 0 ? (_jsxs(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)', textAlign: 'center' }, children: [_jsx(Text, { level: "h3", style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.title', {
|
|
104
92
|
defaultValue: `No ${entity.name.toLowerCase()} found`,
|
|
105
93
|
}) }), _jsx(Text, { style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.description', {
|
|
106
94
|
defaultValue: `No ${entity.name.toLowerCase()} available at this time.`,
|
|
@@ -108,6 +96,7 @@ filter, hideFilters = false, }) {
|
|
|
108
96
|
const itemIsFavorite = isFavorite(item.id);
|
|
109
97
|
const detailHref = onClick ? undefined : `${base}/${item.id}`;
|
|
110
98
|
return (_jsx(CrudCard, { item: item, entity: entity, detailHref: detailHref, onClick: onClick ? () => handleView(item.id) : undefined, renderActions: _jsx(Heart, { fill: itemIsFavorite ? '#ef4444' : '#ffffff', stroke: itemIsFavorite ? '#ef4444' : 'var(--muted-foreground)', onClick: (e) => {
|
|
99
|
+
e.preventDefault();
|
|
111
100
|
e.stopPropagation();
|
|
112
101
|
toggleFavorite(item.id);
|
|
113
102
|
}, style: {
|
|
@@ -16,6 +16,6 @@ export type { EntityDisplayRendererProps };
|
|
|
16
16
|
* <EntityDisplayRenderer entity={carEntity} id={carId} />
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
export declare function EntityDisplayRenderer<T extends EntityRecord = EntityRecord>({ entity, id, t, className, loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, }: EntityDisplayRendererProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare function EntityDisplayRenderer<T extends EntityRecord = EntityRecord>({ entity, id, t, className, loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, excludeFields, }: EntityDisplayRendererProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
20
20
|
export default EntityDisplayRenderer;
|
|
21
21
|
//# sourceMappingURL=EntityDisplayRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityDisplayRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityDisplayRenderer.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI/E,YAAY,EAAE,0BAA0B,EAAE,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EAC3E,MAAM,EACN,EAAE,EACF,CAAC,EACD,SAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"EntityDisplayRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityDisplayRenderer.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI/E,YAAY,EAAE,0BAA0B,EAAE,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EAC3E,MAAM,EACN,EAAE,EACF,CAAC,EACD,SAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EAAE,cAAc,EAC1B,aAAa,GACd,EAAE,0BAA0B,CAAC,CAAC,CAAC,2CAuM/B;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -31,7 +31,7 @@ import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
|
31
31
|
* <EntityDisplayRenderer entity={carEntity} id={carId} />
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
|
-
export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, }) {
|
|
34
|
+
export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, excludeFields, }) {
|
|
35
35
|
// Auto-detect role from auth; prop overrides
|
|
36
36
|
const authRole = useAuthSafe('userRole');
|
|
37
37
|
const viewerRole = viewerRoleProp ?? authRole;
|
|
@@ -95,6 +95,10 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMe
|
|
|
95
95
|
if (!displayData)
|
|
96
96
|
return [];
|
|
97
97
|
return Object.entries(entity.fields).filter(([fieldName, fieldConfig]) => {
|
|
98
|
+
// Skip excluded fields
|
|
99
|
+
if (excludeFields?.includes(fieldName)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
98
102
|
// Check visibility first
|
|
99
103
|
if (!isFieldVisible(fieldConfig.visibility, viewerRole)) {
|
|
100
104
|
return false;
|
|
@@ -126,7 +130,7 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMe
|
|
|
126
130
|
}
|
|
127
131
|
return true;
|
|
128
132
|
});
|
|
129
|
-
}, [entity.fields, viewerRole, displayData]);
|
|
133
|
+
}, [entity.fields, viewerRole, displayData, excludeFields]);
|
|
130
134
|
// Loading state
|
|
131
135
|
if (isLoading) {
|
|
132
136
|
return (_jsx("div", { style: {
|
|
@@ -13,6 +13,6 @@ export type { EntityFormRendererProps };
|
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @author AMBROISE PARK Consulting
|
|
15
15
|
*/
|
|
16
|
-
export declare function EntityFormRenderer<T extends EntityRecord = EntityRecord>({ entity, onSubmit, t, className, submitText, loading, defaultValues, submitVariant, secondaryButtonText, secondaryButtonVariant, onSecondarySubmit, viewerRole: viewerRoleProp, operation,
|
|
16
|
+
export declare function EntityFormRenderer<T extends EntityRecord = EntityRecord>({ entity, onSubmit, t, className, submitText, loading, defaultValues, submitVariant, secondaryButtonText, secondaryButtonVariant, onSecondarySubmit, viewerRole: viewerRoleProp, operation, formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges, unsavedChangesMessage, hideVisibilityInfo, }: EntityFormRendererProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
17
17
|
export default EntityFormRenderer;
|
|
18
18
|
//# sourceMappingURL=EntityFormRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityFormRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityFormRenderer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntityFormRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityFormRenderer.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EACxE,MAAM,EACN,QAAQ,EACR,CAAC,EACD,SAAc,EACd,UAAU,EACV,OAAe,EACf,aAAa,EACb,aAAyB,EACzB,mBAAmB,EACnB,sBAAkC,EAClC,iBAAiB,EACjB,UAAU,EAAE,cAAc,EAC1B,SAA6C,EAC7C,MAAM,EAAE,cAAc,EACtB,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,oBAA2B,EAC3B,qBAAqB,EACrB,kBAA0B,GAC3B,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CAkb5B;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -15,7 +15,7 @@ import { FormProvider } from 'react-hook-form';
|
|
|
15
15
|
import { Badge, Button, DropdownMenu, Grid, Stack, Spinner, } from '@donotdev/components';
|
|
16
16
|
import { hasRoleAccess, useTranslation } from '@donotdev/core';
|
|
17
17
|
import { useNavigate } from '../../routing';
|
|
18
|
-
import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm, useUnsavedChangesWarning,
|
|
18
|
+
import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm, useUnsavedChangesWarning, useFormStore, } from '@donotdev/crud';
|
|
19
19
|
import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
20
20
|
/**
|
|
21
21
|
* EntityFormRenderer - Dumb component that renders a form from entity definition.
|
|
@@ -30,7 +30,7 @@ import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
|
30
30
|
* @since 0.0.1
|
|
31
31
|
* @author AMBROISE PARK Consulting
|
|
32
32
|
*/
|
|
33
|
-
export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole: viewerRoleProp, operation = defaultValues ? 'edit' : 'create',
|
|
33
|
+
export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole: viewerRoleProp, operation = defaultValues ? 'edit' : 'create', formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges = true, unsavedChangesMessage, hideVisibilityInfo = false, }) {
|
|
34
34
|
const navigate = useNavigate();
|
|
35
35
|
// Auto-detect role from auth; prop overrides (e.g. View-As preview)
|
|
36
36
|
const authRole = useAuthSafe('userRole');
|
|
@@ -85,7 +85,6 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
85
85
|
defaultValues,
|
|
86
86
|
viewerRole,
|
|
87
87
|
t: translate,
|
|
88
|
-
autoSave,
|
|
89
88
|
});
|
|
90
89
|
const { control, handleSubmit, formState: { errors }, fields: rawFields, formStatus, uploadProgress, cleanup, isDirty, hasUserInteracted, resetForm, } = form;
|
|
91
90
|
const isDirtyForBlocking = isDirty && hasUserInteracted;
|
|
@@ -105,14 +104,13 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
105
104
|
return fieldRoleIndex <= previewRoleIndex;
|
|
106
105
|
});
|
|
107
106
|
}, [rawFields, canPreviewRole, previewRole]);
|
|
108
|
-
// Subscribe to setIsDirty action via React-compatible selector
|
|
109
|
-
const setFormIsDirty = useFormStore((state) => state.setIsDirty);
|
|
110
107
|
// Sync isDirty to FormStore (single source of truth)
|
|
108
|
+
// Use getState() to avoid subscribing to the action reference (Zustand anti-pattern)
|
|
111
109
|
useEffect(() => {
|
|
112
110
|
if (formId) {
|
|
113
|
-
|
|
111
|
+
useFormStore.getState().setIsDirty(formId, isDirtyForBlocking);
|
|
114
112
|
}
|
|
115
|
-
}, [formId, isDirtyForBlocking
|
|
113
|
+
}, [formId, isDirtyForBlocking]);
|
|
116
114
|
// Cleanup on unmount
|
|
117
115
|
useEffect(() => {
|
|
118
116
|
return cleanup;
|
|
@@ -122,39 +120,24 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
122
120
|
tCrud('messages.unsavedChangesLeave', {
|
|
123
121
|
defaultValue: 'You have unsaved changes. Are you sure you want to leave?',
|
|
124
122
|
}), [unsavedChangesMessage, tCrud]);
|
|
125
|
-
const unsavedChangesDiscardMessage = useMemo(() => unsavedChangesMessage ||
|
|
126
|
-
tCrud('messages.unsavedChangesDiscard', {
|
|
127
|
-
defaultValue: 'You have unsaved changes. Discard them?',
|
|
128
|
-
}), [unsavedChangesMessage, tCrud]);
|
|
129
123
|
// Warn about unsaved changes when navigating away (browser refresh/close)
|
|
130
|
-
//
|
|
124
|
+
// beforeunload is the only place we can't toast — browser requires native dialog
|
|
131
125
|
useUnsavedChangesWarning({
|
|
132
126
|
isDirty: isDirtyForBlocking,
|
|
133
127
|
enabled: warnOnUnsavedChanges,
|
|
134
128
|
message: unsavedChangesLeaveMessage,
|
|
135
129
|
});
|
|
136
|
-
//
|
|
137
|
-
const
|
|
138
|
-
// Handle cancel with confirmation
|
|
139
|
-
const handleCancel = async () => {
|
|
140
|
-
if (isDirtyForBlocking) {
|
|
141
|
-
const confirmed = await confirmNavigation();
|
|
142
|
-
if (!confirmed)
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
130
|
+
// Handle cancel — auto-save ensures draft is persisted, no confirm needed
|
|
131
|
+
const handleCancel = () => {
|
|
145
132
|
resetForm();
|
|
146
|
-
// If onCancel callback provided, use it (takes precedence)
|
|
147
133
|
if (onCancel) {
|
|
148
134
|
onCancel();
|
|
149
135
|
}
|
|
136
|
+
else if (cancelPath) {
|
|
137
|
+
navigate(cancelPath);
|
|
138
|
+
}
|
|
150
139
|
else {
|
|
151
|
-
|
|
152
|
-
if (cancelPath) {
|
|
153
|
-
navigate(cancelPath);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
navigate('back');
|
|
157
|
-
}
|
|
140
|
+
navigate('back');
|
|
158
141
|
}
|
|
159
142
|
};
|
|
160
143
|
// Wrap onSubmit to await the result before navigating
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,EACR,OAAO,EACP,WAAmB,EACnB,UAAqB,EACrB,QAAQ,EAAE,YAAY,EACtB,YAAY,EACZ,UAAiB,GAClB,EAAE,eAAe,2CA2QjB"}
|
|
@@ -9,7 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
* **Routing:** Convention basePath = `/${collection}`. View/Edit = basePath/:id, Create = basePath/new.
|
|
10
10
|
* Override basePath for nested routes; use onClick(id) to open sheet instead of navigating.
|
|
11
11
|
*
|
|
12
|
-
* @version 0.
|
|
12
|
+
* @version 0.4.0
|
|
13
13
|
* @since 0.0.1
|
|
14
14
|
* @author AMBROISE PARK Consulting
|
|
15
15
|
*/
|
|
@@ -18,7 +18,7 @@ import { useMemo, useCallback, useState } from 'react';
|
|
|
18
18
|
import { DataTable, Button, Stack, ActionButton, Section, Input, } from '@donotdev/components';
|
|
19
19
|
import { useTranslation } from '@donotdev/core';
|
|
20
20
|
import { useNavigate } from '../../routing';
|
|
21
|
-
import { translateFieldLabel, useCrud, useCrudList, EntityFilters,
|
|
21
|
+
import { translateFieldLabel, useCrud, useCrudList, EntityFilters, formatValue, } from '@donotdev/crud';
|
|
22
22
|
/**
|
|
23
23
|
* Entity List Component - Table view for admin/internal operations
|
|
24
24
|
*
|
|
@@ -37,11 +37,11 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
37
37
|
// For server-side, we need to track pageSize state (DataTable will call onPageSizeChange)
|
|
38
38
|
// For client-side, we just pass pageSizeProp to DataTable and it handles its own state
|
|
39
39
|
const [serverPageSize, setServerPageSize] = useState(pageSizeProp);
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
const { data: listData, loading, mutate: refreshList, } = useCrudList(entity, {
|
|
40
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
41
|
+
// useCrudList now handles client-side filter + search + sort via `processed`
|
|
42
|
+
const { data: listData, items: rawData, processed: filteredData, loading, mutate: refreshList, } = useCrudList(entity, {
|
|
44
43
|
pagination,
|
|
44
|
+
searchQuery,
|
|
45
45
|
...(queryOptions && { queryOptions }),
|
|
46
46
|
...(pagination === 'server' && {
|
|
47
47
|
page: currentPage,
|
|
@@ -51,14 +51,8 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
51
51
|
// useCrud -> handles actions (delete)
|
|
52
52
|
const { delete: deleteItem } = useCrud(entity);
|
|
53
53
|
const { t: tCrud } = useTranslation('crud');
|
|
54
|
-
const data = listData?.items || [];
|
|
55
54
|
// Entity + crud namespaces so formatValue can resolve crud:price.* etc.
|
|
56
55
|
const { t } = useTranslation([entity.namespace, 'crud']);
|
|
57
|
-
// Get filters for applying to data (EntityFilters manages its own state)
|
|
58
|
-
const { filters } = useCrudFilters({
|
|
59
|
-
collection: entity.collection,
|
|
60
|
-
});
|
|
61
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
62
56
|
// Refresh handler - triggers manual refetch in useList
|
|
63
57
|
const handleRefresh = useCallback(async () => {
|
|
64
58
|
await refreshList();
|
|
@@ -84,36 +78,6 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
84
78
|
const handleDelete = useCallback(async (itemId) => {
|
|
85
79
|
await deleteItem(itemId);
|
|
86
80
|
}, [deleteItem]);
|
|
87
|
-
// Apply search and filters to data
|
|
88
|
-
// @todo Server-side filtering: Currently only handles client-side filtering.
|
|
89
|
-
// When pagination='server', filters should be sent to the server via useCrudList options.
|
|
90
|
-
// Until then, filters are applied client-side after fetching.
|
|
91
|
-
const filteredData = useMemo(() => {
|
|
92
|
-
let result = data;
|
|
93
|
-
// Apply search query (searches all fields)
|
|
94
|
-
if (searchQuery) {
|
|
95
|
-
const searchLower = searchQuery.toLowerCase();
|
|
96
|
-
result = result.filter((item) => {
|
|
97
|
-
return Object.values(item).some((value) => {
|
|
98
|
-
if (value === null || value === undefined)
|
|
99
|
-
return false;
|
|
100
|
-
return String(value).toLowerCase().includes(searchLower);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
// Apply column filters
|
|
105
|
-
if (Object.keys(filters).length > 0) {
|
|
106
|
-
result = result.filter((item) => {
|
|
107
|
-
return Object.entries(filters).every(([fieldName, filterValue]) => {
|
|
108
|
-
const itemValue = item[fieldName];
|
|
109
|
-
const fieldConfig = entity.fields[fieldName];
|
|
110
|
-
const fieldType = fieldConfig?.type || 'text';
|
|
111
|
-
return matchesFilter(itemValue, filterValue, fieldType);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
return result;
|
|
116
|
-
}, [data, searchQuery, filters, entity.fields]);
|
|
117
81
|
// Generate columns from entity.listFields or entity.fields
|
|
118
82
|
const columns = useMemo(() => {
|
|
119
83
|
const fieldsToShow = entity.listFields || Object.keys(entity.fields);
|
|
@@ -170,7 +134,7 @@ export function EntityList({ entity, basePath, onClick, hideFilters = false, pag
|
|
|
170
134
|
defaultValue: `Browse ${entityName} - Filters`,
|
|
171
135
|
}), collapsible: true, defaultOpen: true, children: _jsxs(Stack, { children: [_jsxs(Stack, { direction: "row", gap: "tight", align: "center", className: "dndev-w-full", style: { display: 'grid', gridTemplateColumns: '1fr auto auto' }, children: [_jsx(Input, { placeholder: tCrud('search.placeholder', {
|
|
172
136
|
defaultValue: 'Search...',
|
|
173
|
-
}), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), icon: Search, className: "dndev-w-full" }), _jsx(Button, { icon: RefreshCw, variant: "outline", onClick: handleRefresh, disabled: loading, display: "compact", "aria-label": tCrud('refresh', { defaultValue: 'Refresh' }) }), _jsx(Button, { icon: Plus, onClick: handleCreate, display: "compact", children: tCrud('addNew', { defaultValue: 'Add New' }) })] }), !hideFilters && (_jsx(EntityFilters, { entity: entity, data:
|
|
137
|
+
}), value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), icon: Search, className: "dndev-w-full" }), _jsx(Button, { icon: RefreshCw, variant: "outline", onClick: handleRefresh, disabled: loading, display: "compact", "aria-label": tCrud('refresh', { defaultValue: 'Refresh' }) }), _jsx(Button, { icon: Plus, onClick: handleCreate, display: "compact", children: tCrud('addNew', { defaultValue: 'Add New' }) })] }), !hideFilters && (_jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: entity.listFields }))] }) }), _jsx(Section, { title: loading
|
|
174
138
|
? tCrud('results.title.fetching', {
|
|
175
139
|
defaultValue: 'Fetching...',
|
|
176
140
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityRecommendations.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityRecommendations.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAMjE
|
|
1
|
+
{"version":3,"file":"EntityRecommendations.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityRecommendations.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAMjE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,kDAuB5B"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Section } from '@donotdev/components';
|
|
4
|
-
import {
|
|
4
|
+
import { useCrudCardList } from '@donotdev/crud';
|
|
5
5
|
import { CrudCard } from './CrudCardLink';
|
|
6
6
|
/**
|
|
7
7
|
* Displays a grid of related entity cards.
|
|
8
|
+
* Uses useCrudCardList (listCard schema) so cards render identically to EntityCardList.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* <EntityRecommendations
|
|
@@ -20,7 +21,7 @@ import { CrudCard } from './CrudCardLink';
|
|
|
20
21
|
* />
|
|
21
22
|
*/
|
|
22
23
|
export function EntityRecommendations({ entity, queryOptions, title, basePath, cols = 3, className, }) {
|
|
23
|
-
const { items, loading } =
|
|
24
|
+
const { items, loading } = useCrudCardList(entity, {
|
|
24
25
|
queryOptions,
|
|
25
26
|
});
|
|
26
27
|
if (!loading && items.length === 0) {
|