@donotdev/ui 0.0.13 → 0.0.14
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/auth/AuthMenu.d.ts.map +1 -1
- package/dist/components/auth/AuthMenu.js +19 -20
- package/dist/components/common/FeatureCard.d.ts +3 -1
- package/dist/components/common/FeatureCard.d.ts.map +1 -1
- package/dist/components/common/FeatureCard.js +2 -2
- package/dist/components/common/ProgressBar.js +2 -2
- package/dist/components/common/TechBento.d.ts +14 -2
- package/dist/components/common/TechBento.d.ts.map +1 -1
- package/dist/components/common/TechBento.js +8 -9
- package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
- package/dist/components/cookie-consent/CookieConsent.js +3 -4
- package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/DropdownNavigation.js +3 -12
- package/dist/components/layout/components/FloatingLanguageSwitcher.js +1 -1
- package/dist/components/layout/components/Notifications.d.ts +1 -3
- package/dist/components/layout/components/Notifications.d.ts.map +1 -1
- package/dist/components/layout/components/Notifications.js +4 -2
- package/dist/components/layout/components/header/AppBranding.d.ts.map +1 -1
- package/dist/components/layout/components/header/AppBranding.js +2 -1
- package/dist/components/layout/components/header/AppIcon.d.ts.map +1 -1
- package/dist/components/layout/components/header/AppIcon.js +5 -2
- package/dist/components/layout/components/header/CacheSettings.d.ts.map +1 -1
- package/dist/components/layout/components/header/CacheSettings.js +3 -1
- package/dist/components/layout/components/header/HeaderNavigation.d.ts +6 -0
- package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
- package/dist/components/layout/components/header/HeaderNavigation.js +12 -2
- package/dist/components/license/LicenseWatermark.d.ts.map +1 -1
- package/dist/components/license/LicenseWatermark.js +3 -1
- package/dist/crud/components/CrudCardLink.d.ts +17 -0
- package/dist/crud/components/CrudCardLink.d.ts.map +1 -0
- package/dist/crud/components/CrudCardLink.js +17 -0
- package/dist/crud/components/EntityCardList.d.ts.map +1 -1
- package/dist/crud/components/EntityCardList.js +24 -79
- 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 +29 -18
- package/dist/crud/components/EntityList.d.ts +1 -1
- package/dist/crud/components/EntityList.d.ts.map +1 -1
- package/dist/crud/components/EntityList.js +1 -1
- package/dist/crud/components/EntityRecommendations.d.ts +28 -0
- package/dist/crud/components/EntityRecommendations.d.ts.map +1 -0
- package/dist/crud/components/EntityRecommendations.js +31 -0
- package/dist/crud/components/index.d.ts +2 -1
- package/dist/crud/components/index.d.ts.map +1 -1
- package/dist/crud/components/index.js +1 -0
- package/dist/index.js +4 -4
- package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
- package/dist/internal/devtools/components/AuthDebugButton.js +1 -1
- package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
- package/dist/internal/devtools/components/DesignTab.js +3 -2
- package/dist/internal/devtools/components/LayoutReset.d.ts.map +1 -1
- package/dist/internal/devtools/components/LayoutReset.js +2 -0
- package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
- package/dist/internal/devtools/components/StoresTab.js +3 -0
- package/dist/internal/devtools/utils/envVarDiscovery.d.ts +1 -0
- package/dist/internal/devtools/utils/envVarDiscovery.d.ts.map +1 -1
- package/dist/internal/devtools/utils/envVarDiscovery.js +5 -0
- package/dist/internal/devtools/utils/virtualModuleInspector.d.ts.map +1 -1
- package/dist/internal/devtools/utils/virtualModuleInspector.js +27 -21
- package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
- package/dist/internal/initializers/BaseStoresInitializer.js +30 -6
- package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
- package/dist/internal/layout/components/AutoMetaTags.js +10 -8
- package/dist/internal/layout/components/FontPreloadLinks.d.ts +16 -0
- package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -0
- package/dist/internal/layout/components/FontPreloadLinks.js +32 -0
- package/dist/internal/layout/components/PerformanceHints.d.ts +7 -12
- package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -1
- package/dist/internal/layout/components/PerformanceHints.js +8 -12
- package/dist/internal/layout/components/footer/useLegalLinks.d.ts +6 -5
- package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
- package/dist/internal/layout/components/footer/useLegalLinks.js +6 -2
- package/dist/internal/layout/zones/DnDevFooter.d.ts +6 -0
- package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
- package/dist/internal/layout/zones/DnDevFooter.js +10 -4
- package/dist/internal/layout/zones/DnDevHeader.d.ts +7 -0
- package/dist/internal/layout/zones/DnDevHeader.d.ts.map +1 -1
- package/dist/internal/layout/zones/DnDevHeader.js +7 -0
- package/dist/internal/layout/zones/DnDevMergedBar.d.ts +7 -0
- package/dist/internal/layout/zones/DnDevMergedBar.d.ts.map +1 -1
- package/dist/internal/layout/zones/DnDevMergedBar.js +9 -0
- package/dist/internal/layout/zones/DnDevSidebar.d.ts +4 -0
- package/dist/internal/layout/zones/DnDevSidebar.d.ts.map +1 -1
- package/dist/internal/layout/zones/DnDevSidebar.js +13 -1
- package/dist/next.d.ts +1 -0
- package/dist/next.d.ts.map +1 -1
- package/dist/next.js +1 -0
- package/dist/routing/AuthGuard.d.ts +1 -1
- package/dist/routing/AuthGuard.d.ts.map +1 -1
- package/dist/routing/AuthGuard.js +3 -1
- package/dist/routing/GoTo.d.ts.map +1 -1
- package/dist/routing/GoTo.js +3 -1
- package/dist/routing/GoToDialog.d.ts.map +1 -1
- package/dist/routing/GoToDialog.js +2 -7
- package/dist/routing/GoToInput.d.ts +0 -3
- package/dist/routing/GoToInput.d.ts.map +1 -1
- package/dist/routing/GoToInput.js +4 -2
- package/dist/routing/Link.js +1 -1
- package/dist/routing/NavigationItem.d.ts +29 -7
- package/dist/routing/NavigationItem.d.ts.map +1 -1
- package/dist/routing/NavigationItem.js +22 -6
- package/dist/routing/hooks/hooks.next.js +1 -1
- package/dist/routing/hooks/hooks.vite.js +1 -1
- package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
- package/dist/routing/hooks/useRedirectGuard.next.js +9 -8
- package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
- package/dist/routing/hooks/useRedirectGuard.vite.js +9 -8
- package/dist/routing/hooks/useSearchParams.next.d.ts +18 -1
- package/dist/routing/hooks/useSearchParams.next.d.ts.map +1 -1
- package/dist/routing/hooks/useSearchParams.next.js +16 -0
- package/dist/routing/hooks/useSearchParams.vite.d.ts +16 -0
- package/dist/routing/hooks/useSearchParams.vite.d.ts.map +1 -1
- package/dist/routing/hooks/useSearchParams.vite.js +17 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +2 -0
- package/dist/routing/useNavigation.d.ts +30 -0
- package/dist/routing/useNavigation.d.ts.map +1 -1
- package/dist/routing/useNavigation.js +40 -3
- package/dist/routing/useRouteDiscovery.d.ts +2 -2
- package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
- package/dist/routing/useRouteDiscovery.js +10 -4
- package/dist/styles/index.css +268 -82
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/sanitizeSvg.d.ts +13 -0
- package/dist/utils/sanitizeSvg.d.ts.map +1 -0
- package/dist/utils/sanitizeSvg.js +47 -0
- package/dist/utils/useBillingVisibility.d.ts.map +1 -1
- package/dist/utils/useBillingVisibility.js +0 -7
- package/dist/utils/useCrudSafe.d.ts +0 -2
- package/dist/utils/useCrudSafe.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.d.ts +3 -1
- package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
- package/dist/utils/useFormStoreSafe.js +4 -5
- package/dist/vite-routing/AppRoutes.d.ts +19 -8
- package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
- package/dist/vite-routing/AppRoutes.js +0 -3
- package/package.json +15 -11
- package/assets/fonts/fonts.css +0 -206
- package/dist/dndev.css +0 -10733
- package/dist/routing/Navigate.d.ts +0 -10
- package/dist/routing/Navigate.d.ts.map +0 -1
- package/dist/routing/Navigate.js +0 -10
|
@@ -15,10 +15,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
15
15
|
*/
|
|
16
16
|
import { useMemo, useCallback } from 'react';
|
|
17
17
|
import { Heart } from 'lucide-react';
|
|
18
|
-
import { Grid,
|
|
19
|
-
import { useTranslation } from '@donotdev/core';
|
|
18
|
+
import { Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
|
|
19
|
+
import { useTranslation, getListCardFieldNames } from '@donotdev/core';
|
|
20
20
|
import { useNavigate } from '../../routing';
|
|
21
|
-
import {
|
|
21
|
+
import { useCrudCardList, EntityFilters, useEntityFavorites, matchesFilter, useCrudFilters, } from '@donotdev/crud';
|
|
22
|
+
import { CrudCard } from './CrudCardLink';
|
|
22
23
|
/**
|
|
23
24
|
* Entity Card List Component - Card grid view for public/user-facing browsing
|
|
24
25
|
*
|
|
@@ -43,11 +44,7 @@ filter, hideFilters = false, }) {
|
|
|
43
44
|
});
|
|
44
45
|
// Favorites toggle from CrudStore (persists across navigation)
|
|
45
46
|
// Note: EntityFilters now manages its own filters internally via useCrudFilters
|
|
46
|
-
const { showFavoritesOnly, setShowFavoritesOnly } = useCrudFilters({
|
|
47
|
-
collection: entity.collection,
|
|
48
|
-
});
|
|
49
|
-
// Get filters for applying to data (EntityFilters manages its own state)
|
|
50
|
-
const { filters } = useCrudFilters({
|
|
47
|
+
const { showFavoritesOnly, setShowFavoritesOnly, filters } = useCrudFilters({
|
|
51
48
|
collection: entity.collection,
|
|
52
49
|
});
|
|
53
50
|
// Apply filters from EntityFilters component
|
|
@@ -86,32 +83,8 @@ filter, hideFilters = false, }) {
|
|
|
86
83
|
navigate(`${base}/${id}`);
|
|
87
84
|
}
|
|
88
85
|
}, [base, navigate, onClick]);
|
|
89
|
-
//
|
|
90
|
-
const
|
|
91
|
-
const cardFields = entity.listCardFields ?? entity.listFields;
|
|
92
|
-
if (cardFields && cardFields.length > 0)
|
|
93
|
-
return cardFields;
|
|
94
|
-
return Object.keys(entity.fields).slice(0, 4);
|
|
95
|
-
}, [entity.listCardFields, entity.listFields, entity.fields]);
|
|
96
|
-
// Find image field
|
|
97
|
-
const imageField = useMemo(() => {
|
|
98
|
-
const imageFieldsInList = fieldsToShow.filter((fieldName) => {
|
|
99
|
-
const fieldConfig = entity.fields[fieldName];
|
|
100
|
-
return fieldConfig?.type === 'image' || fieldConfig?.type === 'images';
|
|
101
|
-
});
|
|
102
|
-
if (imageFieldsInList.length > 0)
|
|
103
|
-
return imageFieldsInList[0];
|
|
104
|
-
// Fallback: search all entity fields
|
|
105
|
-
const allImageFields = Object.keys(entity.fields).filter((fieldName) => {
|
|
106
|
-
const fieldConfig = entity.fields[fieldName];
|
|
107
|
-
return fieldConfig?.type === 'image' || fieldConfig?.type === 'images';
|
|
108
|
-
});
|
|
109
|
-
return allImageFields[0] || null;
|
|
110
|
-
}, [fieldsToShow, entity.fields]);
|
|
111
|
-
// Get other fields (non-image)
|
|
112
|
-
const otherFields = useMemo(() => {
|
|
113
|
-
return fieldsToShow.filter((fieldName) => fieldName !== imageField);
|
|
114
|
-
}, [fieldsToShow, imageField]);
|
|
86
|
+
// Flat field names for filters (works with both string[] and ListCardLayout)
|
|
87
|
+
const fieldsToFilter = useMemo(() => getListCardFieldNames(entity), [entity]);
|
|
115
88
|
const entityName = t('name', { defaultValue: entity.name });
|
|
116
89
|
return (_jsxs(_Fragment, { children: [!hideFilters && (_jsx(Section, { title: tCrud('filters.title', {
|
|
117
90
|
entity: entityName,
|
|
@@ -120,7 +93,7 @@ filter, hideFilters = false, }) {
|
|
|
120
93
|
? tCrud('favorites.showAll', { defaultValue: 'Show All' })
|
|
121
94
|
: tCrud('favorites.showFavorites', {
|
|
122
95
|
defaultValue: 'Show Favorites',
|
|
123
|
-
}) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter:
|
|
96
|
+
}) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: fieldsToFilter })] }) })), _jsx(Section, { title: loading
|
|
124
97
|
? tCrud('results.title.fetching', { defaultValue: 'Fetching...' })
|
|
125
98
|
: tCrud('results.title.count', {
|
|
126
99
|
count: data.length,
|
|
@@ -132,50 +105,22 @@ filter, hideFilters = false, }) {
|
|
|
132
105
|
}) }), _jsx(Text, { style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.description', {
|
|
133
106
|
defaultValue: `No ${entity.name.toLowerCase()} available at this time.`,
|
|
134
107
|
}) })] })) : (_jsx(Grid, { cols: cols, children: data.map((item) => {
|
|
135
|
-
const imageValue = imageField ? item[imageField] : null;
|
|
136
|
-
// Backend optimizes picture fields for listCard: returns thumbUrl string directly
|
|
137
|
-
// (or fullUrl if thumbUrl missing, or null if no picture)
|
|
138
|
-
const imageUrl = typeof imageValue === 'string' ? imageValue : null;
|
|
139
|
-
// Title from first non-image field
|
|
140
|
-
const titleField = otherFields[0];
|
|
141
|
-
const titleValue = titleField ? item[titleField] : item.id;
|
|
142
108
|
const itemIsFavorite = isFavorite(item.id);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
: tCrud('favorites.add', {
|
|
160
|
-
defaultValue: 'Add to favorites',
|
|
161
|
-
}) }), _jsxs(Stack, { direction: "column", children: [imageUrl && (_jsx("div", { style: {
|
|
162
|
-
width: '100%',
|
|
163
|
-
aspectRatio: '16/9',
|
|
164
|
-
borderRadius: 'var(--radius-md)',
|
|
165
|
-
overflow: 'hidden',
|
|
166
|
-
backgroundColor: 'var(--muted)',
|
|
167
|
-
position: 'relative',
|
|
168
|
-
}, children: _jsx("img", { src: imageUrl, alt: String(titleValue || ''), style: {
|
|
169
|
-
width: '100%',
|
|
170
|
-
height: '100%',
|
|
171
|
-
objectFit: 'cover',
|
|
172
|
-
} }) })), _jsx(Stack, { direction: "column", gap: "tight", children: otherFields.slice(1, 4).map((fieldName) => {
|
|
173
|
-
const fieldConfig = entity.fields[fieldName];
|
|
174
|
-
if (!fieldConfig)
|
|
175
|
-
return null;
|
|
176
|
-
return (_jsxs("div", { children: [_jsx(Text, { level: "small", variant: "muted", children: translateFieldLabel(fieldName, fieldConfig, t) }), _jsx(Text, { children: formatValue(item[fieldName], fieldConfig, t, {
|
|
177
|
-
compact: true,
|
|
178
|
-
}) })] }, fieldName));
|
|
179
|
-
}) })] })] }, item.id));
|
|
109
|
+
const detailHref = onClick ? undefined : `${base}/${item.id}`;
|
|
110
|
+
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) => {
|
|
111
|
+
e.stopPropagation();
|
|
112
|
+
toggleFavorite(item.id);
|
|
113
|
+
}, style: {
|
|
114
|
+
cursor: 'pointer',
|
|
115
|
+
width: 'var(--icon-md)',
|
|
116
|
+
height: 'var(--icon-md)',
|
|
117
|
+
transition: 'fill 0.2s, stroke 0.2s',
|
|
118
|
+
}, "aria-label": itemIsFavorite
|
|
119
|
+
? tCrud('favorites.remove', {
|
|
120
|
+
defaultValue: 'Remove from favorites',
|
|
121
|
+
})
|
|
122
|
+
: tCrud('favorites.add', {
|
|
123
|
+
defaultValue: 'Add to favorites',
|
|
124
|
+
}) }) }, item.id));
|
|
180
125
|
}) })) })] }));
|
|
181
126
|
}
|
|
@@ -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,
|
|
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;
|
|
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;
|
|
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,GAC3B,EAAE,0BAA0B,CAAC,CAAC,CAAC,2CAkM/B;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -14,6 +14,7 @@ import { useEffect, useState, useMemo } from 'react';
|
|
|
14
14
|
import { Stack, Spinner } from '@donotdev/components';
|
|
15
15
|
import { useTranslation, isFieldVisible } from '@donotdev/core';
|
|
16
16
|
import { useCrud, DisplayFieldRenderer } from '@donotdev/crud';
|
|
17
|
+
import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
17
18
|
/**
|
|
18
19
|
* EntityDisplayRenderer - Automatically fetches and displays entity data
|
|
19
20
|
*
|
|
@@ -30,8 +31,11 @@ import { useCrud, DisplayFieldRenderer } from '@donotdev/crud';
|
|
|
30
31
|
* <EntityDisplayRenderer entity={carEntity} id={carId} />
|
|
31
32
|
* ```
|
|
32
33
|
*/
|
|
33
|
-
export function EntityDisplayRenderer({ entity, id, t, className = '',
|
|
34
|
-
|
|
34
|
+
export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, }) {
|
|
35
|
+
// Auto-detect role from auth; prop overrides
|
|
36
|
+
const authRole = useAuthSafe('userRole');
|
|
37
|
+
const viewerRole = viewerRoleProp ?? authRole;
|
|
38
|
+
const { get, loading, data: storeData, error: storeError, isAvailable, } = useCrud(entity);
|
|
35
39
|
const [isFetching, setIsFetching] = useState(false);
|
|
36
40
|
const [fetchError, setFetchError] = useState(null);
|
|
37
41
|
const [data, setData] = useState(null);
|
|
@@ -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, operation, autoSave, formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges, unsavedChangesMessage, hideVisibilityInfo, }: EntityFormRendererProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function EntityFormRenderer<T extends EntityRecord = EntityRecord>({ entity, onSubmit, t, className, submitText, loading, defaultValues, submitVariant, secondaryButtonText, secondaryButtonVariant, onSecondarySubmit, viewerRole: viewerRoleProp, operation, autoSave, 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":"AAuCA,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,QAAiC,EACjC,MAAM,EAAE,cAAc,EACtB,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,oBAA2B,EAC3B,qBAAqB,EACrB,kBAA0B,GAC3B,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CA4c5B;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -16,6 +16,7 @@ import { Badge, Button, DropdownMenu, Grid, Stack, Spinner, } from '@donotdev/co
|
|
|
16
16
|
import { hasRoleAccess, useTranslation } from '@donotdev/core';
|
|
17
17
|
import { useNavigate } from '../../routing';
|
|
18
18
|
import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm, useUnsavedChangesWarning, useConfirmNavigation, useFormStore, } from '@donotdev/crud';
|
|
19
|
+
import { useAuthSafe } from '../../utils/useAuthSafe';
|
|
19
20
|
/**
|
|
20
21
|
* EntityFormRenderer - Dumb component that renders a form from entity definition.
|
|
21
22
|
*
|
|
@@ -29,8 +30,11 @@ import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm,
|
|
|
29
30
|
* @since 0.0.1
|
|
30
31
|
* @author AMBROISE PARK Consulting
|
|
31
32
|
*/
|
|
32
|
-
export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole, operation = defaultValues ? 'edit' : 'create', autoSave = operation === 'create', formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges = true, unsavedChangesMessage, hideVisibilityInfo = false, }) {
|
|
33
|
+
export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole: viewerRoleProp, operation = defaultValues ? 'edit' : 'create', autoSave = operation === 'create', formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges = true, unsavedChangesMessage, hideVisibilityInfo = false, }) {
|
|
33
34
|
const navigate = useNavigate();
|
|
35
|
+
// Auto-detect role from auth; prop overrides (e.g. View-As preview)
|
|
36
|
+
const authRole = useAuthSafe('userRole');
|
|
37
|
+
const viewerRole = viewerRoleProp ?? authRole;
|
|
34
38
|
// Generate stable form ID
|
|
35
39
|
const generatedFormId = useId();
|
|
36
40
|
const formId = externalFormId ?? `entity-form-${entity.name}-${generatedFormId}`;
|
|
@@ -101,12 +105,14 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
101
105
|
return fieldRoleIndex <= previewRoleIndex;
|
|
102
106
|
});
|
|
103
107
|
}, [rawFields, canPreviewRole, previewRole]);
|
|
108
|
+
// Subscribe to setIsDirty action via React-compatible selector
|
|
109
|
+
const setFormIsDirty = useFormStore((state) => state.setIsDirty);
|
|
104
110
|
// Sync isDirty to FormStore (single source of truth)
|
|
105
111
|
useEffect(() => {
|
|
106
112
|
if (formId) {
|
|
107
|
-
|
|
113
|
+
setFormIsDirty(formId, isDirtyForBlocking);
|
|
108
114
|
}
|
|
109
|
-
}, [formId, isDirtyForBlocking]);
|
|
115
|
+
}, [formId, isDirtyForBlocking, setFormIsDirty]);
|
|
110
116
|
// Cleanup on unmount
|
|
111
117
|
useEffect(() => {
|
|
112
118
|
return cleanup;
|
|
@@ -151,22 +157,27 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
159
|
};
|
|
154
|
-
// Wrap onSubmit to
|
|
160
|
+
// Wrap onSubmit to await the result before navigating
|
|
155
161
|
// handleSubmit from react-hook-form expects: (data: EntityData) => void | Promise<void>
|
|
156
162
|
// Our onSubmit prop is (data: T) => void | Promise<void>, where T extends EntityRecord
|
|
157
163
|
// EntityData should be compatible with T, so we can safely pass it
|
|
158
|
-
const handleFormSubmit = (data) => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
const handleFormSubmit = async (data) => {
|
|
165
|
+
try {
|
|
166
|
+
// Await onSubmit so navigation only happens after successful submission
|
|
167
|
+
// Type assertion is safe: EntityData is the validated form data, T is EntityRecord
|
|
168
|
+
await onSubmit(data);
|
|
169
|
+
// Navigate only after successful submission
|
|
170
|
+
if (successPath) {
|
|
171
|
+
navigate(successPath);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Default: navigate back (user came from list, go back there)
|
|
175
|
+
navigate('back');
|
|
176
|
+
}
|
|
166
177
|
}
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
|
|
178
|
+
catch {
|
|
179
|
+
// onSubmit rejected — stay on form so user can correct errors
|
|
180
|
+
// Error display is handled by the caller's onSubmit implementation
|
|
170
181
|
}
|
|
171
182
|
};
|
|
172
183
|
// Determine if cancel button should show
|
|
@@ -274,13 +285,13 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
|
|
|
274
285
|
if (buttonCount === 1) {
|
|
275
286
|
return (_jsx(Stack, { direction: "column", gap: "tight", style: buttonContainerStyle, children: buttons[0] }));
|
|
276
287
|
}
|
|
277
|
-
// Multiple buttons:
|
|
278
|
-
const
|
|
288
|
+
// Multiple buttons: responsive stacked on mobile, proportional on tablet+
|
|
289
|
+
const colTemplate = buttonCount === 2
|
|
279
290
|
? '1fr 2fr' // Cancel/Preview + Submit
|
|
280
291
|
: buttonCount === 3
|
|
281
292
|
? '1fr 1fr 2fr' // Cancel + Preview + Submit
|
|
282
293
|
: '1fr 1fr 1fr 2fr'; // Cancel + Preview + Secondary + Submit
|
|
283
|
-
return (_jsx(Grid, { cols: [
|
|
294
|
+
return (_jsx(Grid, { cols: ['1fr', colTemplate, colTemplate, colTemplate], gap: "tight", style: buttonContainerStyle, children: buttons }));
|
|
284
295
|
})()] })] }) }) }));
|
|
285
296
|
}
|
|
286
297
|
export default EntityFormRenderer;
|
|
@@ -10,5 +10,5 @@ export type { EntityListProps };
|
|
|
10
10
|
* - Edit and Delete actions (admin only)
|
|
11
11
|
* - Auto-routing when handlers not provided
|
|
12
12
|
*/
|
|
13
|
-
export declare function EntityList({ entity,
|
|
13
|
+
export declare function EntityList({ entity, basePath, onClick, hideFilters, pagination, pageSize: pageSizeProp, queryOptions, exportable, }: EntityListProps): import("react/jsx-runtime").JSX.Element;
|
|
14
14
|
//# sourceMappingURL=EntityList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AA0CA,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,2CAiTjB"}
|
|
@@ -29,7 +29,7 @@ import { translateFieldLabel, useCrud, useCrudList, EntityFilters, matchesFilter
|
|
|
29
29
|
* - Edit and Delete actions (admin only)
|
|
30
30
|
* - Auto-routing when handlers not provided
|
|
31
31
|
*/
|
|
32
|
-
export function EntityList({ entity,
|
|
32
|
+
export function EntityList({ entity, basePath, onClick, hideFilters = false, pagination = 'client', pageSize: pageSizeProp, queryOptions, exportable = true, }) {
|
|
33
33
|
const navigate = useNavigate();
|
|
34
34
|
const base = basePath ?? `/${entity.collection}`;
|
|
35
35
|
// Server-side pagination state (only used when pagination='server')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Reusable recommendations section for related entities
|
|
3
|
+
* @description Fetches and displays related entity cards in a grid.
|
|
4
|
+
* Caller defines "related by what" via queryOptions.
|
|
5
|
+
*
|
|
6
|
+
* @version 0.0.1
|
|
7
|
+
* @since 0.0.15
|
|
8
|
+
* @author AMBROISE PARK Consulting
|
|
9
|
+
*/
|
|
10
|
+
import type { EntityRecommendationsProps } from '@donotdev/core';
|
|
11
|
+
/**
|
|
12
|
+
* Displays a grid of related entity cards.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <EntityRecommendations
|
|
16
|
+
* entity={apartmentEntity}
|
|
17
|
+
* title={t('apartment.recommendations')}
|
|
18
|
+
* queryOptions={{
|
|
19
|
+
* where: [
|
|
20
|
+
* { field: 'district_code', operator: 'eq', value: current.district_code },
|
|
21
|
+
* { field: 'id', operator: 'neq', value: current.id },
|
|
22
|
+
* ],
|
|
23
|
+
* limit: 3,
|
|
24
|
+
* }}
|
|
25
|
+
* />
|
|
26
|
+
*/
|
|
27
|
+
export declare function EntityRecommendations({ entity, queryOptions, title, basePath, cols, className, }: EntityRecommendationsProps): import("react/jsx-runtime").JSX.Element | null;
|
|
28
|
+
//# sourceMappingURL=EntityRecommendations.d.ts.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,kDAuB5B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Section } from '@donotdev/components';
|
|
4
|
+
import { useCrudList } from '@donotdev/crud';
|
|
5
|
+
import { CrudCard } from './CrudCardLink';
|
|
6
|
+
/**
|
|
7
|
+
* Displays a grid of related entity cards.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <EntityRecommendations
|
|
11
|
+
* entity={apartmentEntity}
|
|
12
|
+
* title={t('apartment.recommendations')}
|
|
13
|
+
* queryOptions={{
|
|
14
|
+
* where: [
|
|
15
|
+
* { field: 'district_code', operator: 'eq', value: current.district_code },
|
|
16
|
+
* { field: 'id', operator: 'neq', value: current.id },
|
|
17
|
+
* ],
|
|
18
|
+
* limit: 3,
|
|
19
|
+
* }}
|
|
20
|
+
* />
|
|
21
|
+
*/
|
|
22
|
+
export function EntityRecommendations({ entity, queryOptions, title, basePath, cols = 3, className, }) {
|
|
23
|
+
const { items, loading } = useCrudList(entity, {
|
|
24
|
+
queryOptions,
|
|
25
|
+
});
|
|
26
|
+
if (!loading && items.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const resolvedBasePath = basePath ?? `/${entity.collection}`;
|
|
30
|
+
return (_jsx(Section, { title: title, gridCols: cols, className: className, children: items.map((item) => (_jsx(CrudCard, { item: item, entity: entity, detailHref: `${resolvedBasePath}/${item.id}` }, item.id))) }));
|
|
31
|
+
}
|
|
@@ -10,6 +10,7 @@ export { EntityDisplayRenderer } from './EntityDisplayRenderer';
|
|
|
10
10
|
export { EntityList } from './EntityList';
|
|
11
11
|
export { EntityCardList } from './EntityCardList';
|
|
12
12
|
export { EntityFormRenderer } from './EntityFormRenderer';
|
|
13
|
+
export { EntityRecommendations } from './EntityRecommendations';
|
|
13
14
|
export * from './Form';
|
|
14
|
-
export type { EntityListProps, EntityCardListProps, EntityFormRendererProps, EntityDisplayRendererProps, } from '@donotdev/core';
|
|
15
|
+
export type { EntityListProps, EntityCardListProps, EntityRecommendationsProps, EntityFormRendererProps, EntityDisplayRendererProps, } from '@donotdev/core';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crud/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,cAAc,QAAQ,CAAC;AAEvB,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crud/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,cAAc,QAAQ,CAAC;AAEvB,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC"}
|
|
@@ -11,4 +11,5 @@ export { EntityDisplayRenderer } from './EntityDisplayRenderer';
|
|
|
11
11
|
export { EntityList } from './EntityList';
|
|
12
12
|
export { EntityCardList } from './EntityCardList';
|
|
13
13
|
export { EntityFormRenderer } from './EntityFormRenderer';
|
|
14
|
+
export { EntityRecommendations } from './EntityRecommendations';
|
|
14
15
|
export * from './Form';
|