@object-ui/app-shell 3.3.0 → 3.3.1
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/CHANGELOG.md +45 -0
- package/README.md +22 -2
- package/dist/chrome/CommandPalette.d.ts +16 -0
- package/dist/chrome/CommandPalette.js +88 -0
- package/dist/chrome/ConditionalAuthWrapper.d.ts +23 -0
- package/dist/chrome/ConditionalAuthWrapper.js +135 -0
- package/dist/chrome/ConsoleToaster.d.ts +11 -0
- package/dist/chrome/ConsoleToaster.js +28 -0
- package/dist/chrome/ErrorBoundary.d.ts +39 -0
- package/dist/chrome/ErrorBoundary.js +64 -0
- package/dist/chrome/KeyboardShortcutsDialog.d.ts +7 -0
- package/dist/chrome/KeyboardShortcutsDialog.js +63 -0
- package/dist/chrome/LoadingScreen.d.ts +12 -0
- package/dist/chrome/LoadingScreen.js +44 -0
- package/dist/chrome/OnboardingWalkthrough.d.ts +9 -0
- package/dist/chrome/OnboardingWalkthrough.js +11 -0
- package/dist/chrome/ThemeProvider.d.ts +13 -0
- package/dist/chrome/ThemeProvider.js +37 -0
- package/dist/chrome/index.d.ts +8 -0
- package/dist/chrome/index.js +8 -0
- package/dist/console/AppContent.d.ts +26 -0
- package/dist/console/AppContent.js +266 -0
- package/dist/console/ConsoleShell.d.ts +66 -0
- package/dist/console/ConsoleShell.js +97 -0
- package/dist/console/auth/AuthPageLayout.d.ts +9 -0
- package/dist/console/auth/AuthPageLayout.js +4 -0
- package/dist/console/auth/ForgotPasswordPage.d.ts +4 -0
- package/dist/console/auth/ForgotPasswordPage.js +23 -0
- package/dist/console/auth/LoginPage.d.ts +4 -0
- package/dist/console/auth/LoginPage.js +24 -0
- package/dist/console/auth/RegisterPage.d.ts +4 -0
- package/dist/console/auth/RegisterPage.js +29 -0
- package/dist/console/auth/index.d.ts +4 -0
- package/dist/console/auth/index.js +4 -0
- package/dist/console/home/AppCard.d.ts +14 -0
- package/dist/console/home/AppCard.js +36 -0
- package/dist/console/home/HomeLayout.d.ts +15 -0
- package/dist/console/home/HomeLayout.js +20 -0
- package/dist/console/home/HomePage.d.ts +18 -0
- package/dist/console/home/HomePage.js +54 -0
- package/dist/console/home/QuickActions.d.ts +9 -0
- package/dist/console/home/QuickActions.js +53 -0
- package/dist/console/home/RecentApps.d.ts +13 -0
- package/dist/console/home/RecentApps.js +32 -0
- package/dist/console/home/StarredApps.d.ts +13 -0
- package/dist/console/home/StarredApps.js +29 -0
- package/dist/console/home/index.d.ts +11 -0
- package/dist/console/home/index.js +11 -0
- package/dist/console/organizations/CreateWorkspaceDialog.d.ts +16 -0
- package/dist/console/organizations/CreateWorkspaceDialog.js +71 -0
- package/dist/console/organizations/OrganizationsLayout.d.ts +15 -0
- package/dist/console/organizations/OrganizationsLayout.js +20 -0
- package/dist/console/organizations/OrganizationsPage.d.ts +9 -0
- package/dist/console/organizations/OrganizationsPage.js +76 -0
- package/dist/console/organizations/index.d.ts +8 -0
- package/dist/console/organizations/index.js +8 -0
- package/dist/console/organizations/manage/AcceptInvitationPage.d.ts +7 -0
- package/dist/console/organizations/manage/AcceptInvitationPage.js +100 -0
- package/dist/console/organizations/manage/InvitationsPage.d.ts +6 -0
- package/dist/console/organizations/manage/InvitationsPage.js +107 -0
- package/dist/console/organizations/manage/InviteMemberDialog.d.ts +16 -0
- package/dist/console/organizations/manage/InviteMemberDialog.js +83 -0
- package/dist/console/organizations/manage/MembersPage.d.ts +6 -0
- package/dist/console/organizations/manage/MembersPage.js +89 -0
- package/dist/console/organizations/manage/OrganizationLayout.d.ts +8 -0
- package/dist/console/organizations/manage/OrganizationLayout.js +51 -0
- package/dist/console/organizations/manage/SettingsPage.d.ts +6 -0
- package/dist/console/organizations/manage/SettingsPage.js +141 -0
- package/dist/console/organizations/manage/orgContext.d.ts +5 -0
- package/dist/console/organizations/manage/orgContext.js +4 -0
- package/dist/context/FavoritesProvider.d.ts +50 -0
- package/dist/context/FavoritesProvider.js +129 -0
- package/dist/context/NavigationContext.d.ts +46 -0
- package/dist/context/NavigationContext.js +59 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.js +2 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/useFavorites.d.ts +13 -0
- package/dist/hooks/useFavorites.js +13 -0
- package/dist/hooks/useMetadataService.d.ts +13 -0
- package/dist/hooks/useMetadataService.js +18 -0
- package/dist/hooks/useNavPins.d.ts +16 -0
- package/dist/hooks/useNavPins.js +72 -0
- package/dist/hooks/useNavigationSync.d.ts +82 -0
- package/dist/hooks/useNavigationSync.js +495 -0
- package/dist/hooks/useObjectActions.d.ts +38 -0
- package/dist/hooks/useObjectActions.js +92 -0
- package/dist/hooks/useRecentItems.d.ts +21 -0
- package/dist/hooks/useRecentItems.js +50 -0
- package/dist/hooks/useResponsiveSidebar.d.ts +8 -0
- package/dist/hooks/useResponsiveSidebar.js +28 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +35 -0
- package/dist/layout/ActivityFeed.d.ts +22 -0
- package/dist/layout/ActivityFeed.js +57 -0
- package/dist/layout/AppHeader.d.ts +33 -0
- package/dist/layout/AppHeader.js +182 -0
- package/dist/layout/AppSidebar.d.ts +14 -0
- package/dist/layout/AppSidebar.js +217 -0
- package/dist/layout/AppSwitcher.d.ts +12 -0
- package/dist/layout/AppSwitcher.js +39 -0
- package/dist/layout/AuthPageLayout.d.ts +9 -0
- package/dist/layout/AuthPageLayout.js +4 -0
- package/dist/layout/ConnectionStatus.d.ts +14 -0
- package/dist/layout/ConnectionStatus.js +36 -0
- package/dist/layout/ConsoleLayout.d.ts +21 -0
- package/dist/layout/ConsoleLayout.js +71 -0
- package/dist/layout/LocaleSwitcher.d.ts +7 -0
- package/dist/layout/LocaleSwitcher.js +27 -0
- package/dist/layout/ModeToggle.d.ts +1 -0
- package/dist/layout/ModeToggle.js +10 -0
- package/dist/layout/UnifiedSidebar.d.ts +22 -0
- package/dist/layout/UnifiedSidebar.js +210 -0
- package/dist/layout/index.d.ts +11 -0
- package/dist/layout/index.js +10 -0
- package/dist/providers/AdapterProvider.d.ts +21 -0
- package/dist/providers/AdapterProvider.js +52 -0
- package/dist/providers/ExpressionProvider.d.ts +50 -0
- package/dist/providers/ExpressionProvider.js +67 -0
- package/dist/providers/MetadataProvider.d.ts +18 -0
- package/dist/providers/MetadataProvider.js +324 -0
- package/dist/services/MetadataService.d.ts +119 -0
- package/dist/services/MetadataService.js +211 -0
- package/dist/skeletons/SkeletonDashboard.d.ts +13 -0
- package/dist/skeletons/SkeletonDashboard.js +12 -0
- package/dist/skeletons/SkeletonDetail.d.ts +15 -0
- package/dist/skeletons/SkeletonDetail.js +12 -0
- package/dist/skeletons/SkeletonGrid.d.ts +15 -0
- package/dist/skeletons/SkeletonGrid.js +12 -0
- package/dist/skeletons/index.d.ts +3 -0
- package/dist/skeletons/index.js +3 -0
- package/dist/utils/getIcon.d.ts +10 -0
- package/dist/utils/getIcon.js +24 -0
- package/dist/utils/index.d.ts +33 -0
- package/dist/utils/index.js +62 -0
- package/dist/utils/metadataConverters.d.ts +78 -0
- package/dist/utils/metadataConverters.js +74 -0
- package/dist/views/ActionConfirmDialog.d.ts +22 -0
- package/dist/views/ActionConfirmDialog.js +22 -0
- package/dist/views/ActionParamDialog.d.ts +23 -0
- package/dist/views/ActionParamDialog.js +67 -0
- package/dist/views/DashboardView.d.ts +9 -0
- package/dist/views/DashboardView.js +357 -0
- package/dist/views/DesignDrawer.d.ts +28 -0
- package/dist/views/DesignDrawer.js +51 -0
- package/dist/views/MetadataInspector.d.ts +40 -0
- package/dist/views/MetadataInspector.js +69 -0
- package/dist/views/ObjectView.d.ts +14 -0
- package/dist/views/ObjectView.js +770 -0
- package/dist/views/PageView.d.ts +6 -0
- package/dist/views/PageView.js +49 -0
- package/dist/views/RecordDetailView.d.ts +14 -0
- package/dist/views/RecordDetailView.js +508 -0
- package/dist/views/ReportView.d.ts +4 -0
- package/dist/views/ReportView.js +284 -0
- package/dist/views/SearchResultsPage.d.ts +9 -0
- package/dist/views/SearchResultsPage.js +107 -0
- package/dist/views/ViewConfigPanel.d.ts +56 -0
- package/dist/views/ViewConfigPanel.js +91 -0
- package/dist/views/index.d.ts +11 -0
- package/dist/views/index.js +11 -0
- package/package.json +59 -11
- package/.turbo/turbo-build.log +0 -4
- package/src/components/AppShell.tsx +0 -31
- package/src/components/DashboardRenderer.tsx +0 -36
- package/src/components/FormRenderer.tsx +0 -71
- package/src/components/ObjectRenderer.tsx +0 -122
- package/src/components/PageRenderer.tsx +0 -28
- package/src/index.ts +0 -20
- package/src/types.ts +0 -78
- package/tsconfig.json +0 -20
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
+
import { useParams } from 'react-router-dom';
|
|
4
|
+
import { ReportViewer, ReportConfigPanel } from '@object-ui/plugin-report';
|
|
5
|
+
import { Empty, EmptyTitle, EmptyDescription } from '@object-ui/components';
|
|
6
|
+
import { Pencil, BarChart3, Loader2 } from 'lucide-react';
|
|
7
|
+
import { MetadataPanel, useMetadataInspector } from './MetadataInspector';
|
|
8
|
+
import { useMetadata } from '../providers/MetadataProvider';
|
|
9
|
+
import { useAdapter } from '../providers/AdapterProvider';
|
|
10
|
+
// Fallback fields when no schema is available
|
|
11
|
+
const FALLBACK_FIELDS = [
|
|
12
|
+
{ value: 'month', label: 'Month', type: 'text' },
|
|
13
|
+
{ value: 'revenue', label: 'Revenue', type: 'number' },
|
|
14
|
+
{ value: 'count', label: 'Count', type: 'number' },
|
|
15
|
+
{ value: 'region', label: 'Region', type: 'text' },
|
|
16
|
+
{ value: 'product', label: 'Product', type: 'text' },
|
|
17
|
+
{ value: 'source', label: 'Lead Source', type: 'text' },
|
|
18
|
+
{ value: 'stage', label: 'Stage', type: 'text' },
|
|
19
|
+
{ value: 'amount', label: 'Amount', type: 'number' },
|
|
20
|
+
];
|
|
21
|
+
export function ReportView({ dataSource }) {
|
|
22
|
+
const { reportName } = useParams();
|
|
23
|
+
const { showDebug } = useMetadataInspector();
|
|
24
|
+
const adapter = useAdapter();
|
|
25
|
+
const [configPanelOpen, setConfigPanelOpen] = useState(false);
|
|
26
|
+
// Version counter — incremented on save to refresh the stable config reference
|
|
27
|
+
const [configVersion, setConfigVersion] = useState(0);
|
|
28
|
+
// Find report definition from API-driven metadata
|
|
29
|
+
const { reports, objects, loading, refresh } = useMetadata();
|
|
30
|
+
const initialReport = reports?.find((r) => r.name === reportName);
|
|
31
|
+
const [reportData, setReportData] = useState(initialReport);
|
|
32
|
+
// Local schema state for live preview — initialized from metadata
|
|
33
|
+
const [editSchema, setEditSchema] = useState(null);
|
|
34
|
+
// State for report runtime data
|
|
35
|
+
const [reportRuntimeData, setReportRuntimeData] = useState([]);
|
|
36
|
+
const [dataLoading, setDataLoading] = useState(false);
|
|
37
|
+
// Derive available fields from object schema for filter/sort editors
|
|
38
|
+
// Uses live editSchema when available to respond to objectName changes
|
|
39
|
+
const availableFields = useMemo(() => {
|
|
40
|
+
const liveReport = editSchema || reportData;
|
|
41
|
+
const objName = liveReport?.objectName || liveReport?.dataSource?.object || liveReport?.dataSource?.resource;
|
|
42
|
+
if (objName && objects?.length) {
|
|
43
|
+
const objDef = objects.find((o) => o.name === objName);
|
|
44
|
+
if (objDef?.fields) {
|
|
45
|
+
const fields = objDef.fields;
|
|
46
|
+
if (Array.isArray(fields)) {
|
|
47
|
+
return fields.map((f) => typeof f === 'string'
|
|
48
|
+
? { value: f, label: f, type: 'text' }
|
|
49
|
+
: { value: f.name, label: f.label || f.name, type: f.type || 'text' });
|
|
50
|
+
}
|
|
51
|
+
return Object.entries(fields).map(([name, def]) => ({
|
|
52
|
+
value: name,
|
|
53
|
+
label: def.label || name,
|
|
54
|
+
type: def.type || 'text',
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return FALLBACK_FIELDS;
|
|
59
|
+
}, [editSchema, reportData, objects]);
|
|
60
|
+
// ---- Save helper --------------------------------------------------------
|
|
61
|
+
const saveSchema = useCallback(async (schema) => {
|
|
62
|
+
try {
|
|
63
|
+
if (adapter) {
|
|
64
|
+
await adapter.update('sys_report', reportName, schema);
|
|
65
|
+
refresh().catch(() => { });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.warn('[ReportView] Auto-save failed:', err);
|
|
70
|
+
}
|
|
71
|
+
}, [adapter, reportName, refresh]);
|
|
72
|
+
// ---- Open / close config panel ------------------------------------------
|
|
73
|
+
const handleOpenConfigPanel = useCallback(() => {
|
|
74
|
+
setEditSchema(reportData);
|
|
75
|
+
setConfigPanelOpen(true);
|
|
76
|
+
setConfigVersion((v) => v + 1);
|
|
77
|
+
}, [reportData]);
|
|
78
|
+
const handleCloseConfigPanel = useCallback(() => {
|
|
79
|
+
setConfigPanelOpen(false);
|
|
80
|
+
}, []);
|
|
81
|
+
// ---- Report config panel handlers --------------------------------------
|
|
82
|
+
// Stabilize config reference: only recompute after explicit actions (panel
|
|
83
|
+
// open, save). configVersion is incremented on those actions.
|
|
84
|
+
// This prevents useConfigDraft from resetting the draft on every live field
|
|
85
|
+
// change (same pattern as DashboardView's dashboardConfig).
|
|
86
|
+
const reportConfig = useMemo(() => editSchema || reportData,
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
[configVersion]);
|
|
89
|
+
const handleReportConfigSave = useCallback((config) => {
|
|
90
|
+
setEditSchema(config);
|
|
91
|
+
saveSchema(config);
|
|
92
|
+
setConfigVersion((v) => v + 1);
|
|
93
|
+
}, [saveSchema]);
|
|
94
|
+
const handleReportFieldChange = useCallback((field, value) => {
|
|
95
|
+
setEditSchema((prev) => ({ ...prev, [field]: value }));
|
|
96
|
+
}, []);
|
|
97
|
+
// Sync reportData when metadata finishes loading or reportName changes
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
setReportData(initialReport);
|
|
100
|
+
}, [initialReport]);
|
|
101
|
+
// When metadata refreshes, discard stale editSchema if the config panel
|
|
102
|
+
// is already closed.
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!configPanelOpen) {
|
|
105
|
+
setEditSchema(null);
|
|
106
|
+
}
|
|
107
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
+
}, [initialReport]);
|
|
109
|
+
// Load report runtime data when report definition changes.
|
|
110
|
+
// Use the live editSchema (when available) so that config panel changes
|
|
111
|
+
// to objectName, filters, or limit are immediately reflected in the preview.
|
|
112
|
+
const dataFetchSource = editSchema || reportData;
|
|
113
|
+
// Memoize serialized dependency keys to avoid re-fetching on every render
|
|
114
|
+
const filtersKey = useMemo(() => JSON.stringify(dataFetchSource?.filters), [dataFetchSource?.filters]);
|
|
115
|
+
const dataSourceKey = useMemo(() => JSON.stringify(dataFetchSource?.dataSource), [dataFetchSource?.dataSource]);
|
|
116
|
+
const inlineDataKey = useMemo(() => JSON.stringify(dataFetchSource?.data), [dataFetchSource?.data]);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!dataFetchSource || !dataSource) {
|
|
119
|
+
setReportRuntimeData([]);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// If report has inline data, use it directly
|
|
123
|
+
if (dataFetchSource.data && Array.isArray(dataFetchSource.data)) {
|
|
124
|
+
setReportRuntimeData(dataFetchSource.data);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// If report has a dataSource config, fetch data using it
|
|
128
|
+
if (dataFetchSource.dataSource) {
|
|
129
|
+
const fetchDataFromSource = async () => {
|
|
130
|
+
setDataLoading(true);
|
|
131
|
+
try {
|
|
132
|
+
// Use the dataSource configuration to fetch data
|
|
133
|
+
const resource = dataFetchSource.dataSource.object || dataFetchSource.dataSource.resource;
|
|
134
|
+
if (!resource) {
|
|
135
|
+
console.warn('ReportView: dataSource missing object/resource property');
|
|
136
|
+
setReportRuntimeData([]);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const result = await dataSource.find(resource, {
|
|
140
|
+
$filter: dataFetchSource.dataSource.filter,
|
|
141
|
+
$orderby: dataFetchSource.dataSource.sort,
|
|
142
|
+
$top: dataFetchSource.dataSource.limit,
|
|
143
|
+
});
|
|
144
|
+
setReportRuntimeData(result.data || []);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error('ReportView: Failed to load data from dataSource', error);
|
|
148
|
+
setReportRuntimeData([]);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
setDataLoading(false);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
fetchDataFromSource();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// If report has an objectName, fetch data from that object
|
|
158
|
+
if (dataFetchSource.objectName) {
|
|
159
|
+
const fetchDataFromObject = async () => {
|
|
160
|
+
setDataLoading(true);
|
|
161
|
+
try {
|
|
162
|
+
const result = await dataSource.find(dataFetchSource.objectName, {
|
|
163
|
+
$filter: dataFetchSource.filters,
|
|
164
|
+
$orderby: dataFetchSource.sort,
|
|
165
|
+
$top: dataFetchSource.limit || 100, // Default limit to avoid fetching too much data
|
|
166
|
+
});
|
|
167
|
+
setReportRuntimeData(result.data || []);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error('ReportView: Failed to load data from objectName', error);
|
|
171
|
+
setReportRuntimeData([]);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
setDataLoading(false);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
fetchDataFromObject();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// No data source configured
|
|
181
|
+
setReportRuntimeData([]);
|
|
182
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
183
|
+
}, [
|
|
184
|
+
dataFetchSource?.objectName,
|
|
185
|
+
dataFetchSource?.limit,
|
|
186
|
+
filtersKey,
|
|
187
|
+
dataSourceKey,
|
|
188
|
+
inlineDataKey,
|
|
189
|
+
dataSource,
|
|
190
|
+
]);
|
|
191
|
+
if (loading) {
|
|
192
|
+
return (_jsx("div", { className: "h-full flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }));
|
|
193
|
+
}
|
|
194
|
+
if (!initialReport || !reportData) {
|
|
195
|
+
if (!loading && !initialReport) {
|
|
196
|
+
return (_jsx("div", { className: "h-full flex items-center justify-center p-8", children: _jsxs(Empty, { children: [_jsx("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-muted", children: _jsx(BarChart3, { className: "h-6 w-6 text-muted-foreground" }) }), _jsx(EmptyTitle, { children: "Report Not Found" }), _jsxs(EmptyDescription, { children: ["The report \"", reportName, "\" could not be found. It may have been removed or renamed."] })] }) }));
|
|
197
|
+
}
|
|
198
|
+
return (_jsx("div", { className: "h-full flex items-center justify-center p-8", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }));
|
|
199
|
+
}
|
|
200
|
+
// Wrap the report definition in the ReportViewer schema
|
|
201
|
+
// The ReportViewer expects a schema property which is of type ReportViewerSchema
|
|
202
|
+
// That schema has a 'report' property which is the actual report definition (ReportSchema)
|
|
203
|
+
// Map @objectstack/spec report format to @object-ui/types ReportSchema:
|
|
204
|
+
// - 'label' → 'title'
|
|
205
|
+
// - 'columns' (with 'field') → 'fields' (with 'name') + auto-generate 'sections'
|
|
206
|
+
const mapReportForViewer = (src) => {
|
|
207
|
+
const mapped = { ...src };
|
|
208
|
+
if (!mapped.title && mapped.label) {
|
|
209
|
+
mapped.title = mapped.label;
|
|
210
|
+
}
|
|
211
|
+
// Map spec 'columns' (field/label/aggregate) → ReportSchema 'fields' (name/label/aggregation)
|
|
212
|
+
if (!mapped.fields && Array.isArray(mapped.columns)) {
|
|
213
|
+
mapped.fields = mapped.columns.map((col) => ({
|
|
214
|
+
name: col.field || col.name,
|
|
215
|
+
label: col.label,
|
|
216
|
+
type: col.type,
|
|
217
|
+
format: col.format,
|
|
218
|
+
renderAs: col.renderAs,
|
|
219
|
+
colorMap: col.colorMap,
|
|
220
|
+
...(col.aggregate ? { aggregation: col.aggregate, showInSummary: true } : {}),
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
// Always regenerate sections from current fields so that live config
|
|
224
|
+
// changes (e.g. field picker updates) are immediately reflected in
|
|
225
|
+
// the preview. This fixes the linkage bug where config panel edits
|
|
226
|
+
// did not update the rendered report.
|
|
227
|
+
if (mapped.fields && Array.isArray(mapped.fields) && mapped.fields.length > 0) {
|
|
228
|
+
const hasSummaryFields = mapped.fields.some((f) => f.showInSummary || f.aggregation);
|
|
229
|
+
const reportType = mapped.reportType || 'tabular';
|
|
230
|
+
const sections = [];
|
|
231
|
+
if (reportType === 'summary' || hasSummaryFields) {
|
|
232
|
+
sections.push({ type: 'summary', title: 'Key Metrics' });
|
|
233
|
+
}
|
|
234
|
+
sections.push({
|
|
235
|
+
type: 'table',
|
|
236
|
+
title: 'Details',
|
|
237
|
+
columns: mapped.fields.map((f) => ({
|
|
238
|
+
name: f.name,
|
|
239
|
+
label: f.label,
|
|
240
|
+
type: f.type,
|
|
241
|
+
format: f.format,
|
|
242
|
+
renderAs: f.renderAs,
|
|
243
|
+
colorMap: f.colorMap,
|
|
244
|
+
})),
|
|
245
|
+
});
|
|
246
|
+
// Generate chart section from chartConfig if configured
|
|
247
|
+
if (mapped.chartConfig?.chartType) {
|
|
248
|
+
sections.push({
|
|
249
|
+
type: 'chart',
|
|
250
|
+
title: 'Chart',
|
|
251
|
+
chart: {
|
|
252
|
+
type: 'chart',
|
|
253
|
+
chartType: mapped.chartConfig.chartType,
|
|
254
|
+
xAxisField: mapped.chartConfig.xAxisField,
|
|
255
|
+
yAxisFields: mapped.chartConfig.yAxisFields,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
// Preserve any user-defined chart sections from the original schema
|
|
260
|
+
if (Array.isArray(src.sections)) {
|
|
261
|
+
const chartSections = src.sections.filter((s) => s.type === 'chart' && !mapped.chartConfig?.chartType);
|
|
262
|
+
sections.push(...chartSections);
|
|
263
|
+
}
|
|
264
|
+
mapped.sections = sections;
|
|
265
|
+
}
|
|
266
|
+
else if (!mapped.sections) {
|
|
267
|
+
// No fields and no sections — leave empty
|
|
268
|
+
mapped.sections = [];
|
|
269
|
+
}
|
|
270
|
+
return mapped;
|
|
271
|
+
};
|
|
272
|
+
// Use live-edited schema for preview (persists after closing panel until metadata refreshes)
|
|
273
|
+
const previewReport = editSchema || reportData;
|
|
274
|
+
const reportForViewer = mapReportForViewer(previewReport);
|
|
275
|
+
const viewerSchema = {
|
|
276
|
+
type: 'report-viewer',
|
|
277
|
+
report: reportForViewer, // The report definition
|
|
278
|
+
data: reportRuntimeData, // Runtime data fetched from the data source
|
|
279
|
+
showToolbar: true,
|
|
280
|
+
allowExport: true,
|
|
281
|
+
loading: dataLoading, // Loading state for data fetching
|
|
282
|
+
};
|
|
283
|
+
return (_jsxs("div", { className: "flex flex-col h-full overflow-hidden bg-background", children: [_jsxs("div", { className: "flex flex-col sm:flex-row justify-between sm:items-center gap-3 sm:gap-4 p-4 sm:p-6 border-b shrink-0", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h1", { className: "text-lg sm:text-xl md:text-2xl font-bold tracking-tight truncate", children: previewReport.title || previewReport.label || 'Report Viewer' }), previewReport.description && (_jsx("p", { className: "text-sm text-muted-foreground mt-1 line-clamp-2", children: previewReport.description }))] }), _jsx("div", { className: "shrink-0 flex items-center gap-1.5", children: _jsxs("button", { type: "button", onClick: handleOpenConfigPanel, className: "inline-flex items-center gap-1.5 rounded-md border border-input bg-background px-2.5 py-1.5 text-xs font-medium text-muted-foreground shadow-sm hover:bg-accent hover:text-accent-foreground", "data-testid": "report-edit-button", children: [_jsx(Pencil, { className: "h-3.5 w-3.5" }), "Edit"] }) })] }), _jsxs("div", { className: "flex-1 overflow-hidden flex flex-col sm:flex-row relative", children: [_jsx("div", { className: "flex-1 min-w-0 overflow-auto p-4 sm:p-6 lg:p-8 bg-muted/5", children: _jsx("div", { className: "max-w-5xl mx-auto shadow-sm border rounded-lg sm:rounded-xl bg-background overflow-hidden min-h-150", children: _jsx(ReportViewer, { schema: viewerSchema }) }) }), _jsx(ReportConfigPanel, { open: configPanelOpen, onClose: handleCloseConfigPanel, config: reportConfig, onSave: handleReportConfigSave, onFieldChange: handleReportFieldChange, availableFields: availableFields }), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'Report Configuration', data: previewReport }] })] })] }));
|
|
284
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SearchResultsPage
|
|
3
|
+
*
|
|
4
|
+
* A dedicated search results page accessible via /apps/:appName/search?q=...
|
|
5
|
+
* Extends the command palette with a full-page search experience, showing
|
|
6
|
+
* objects, dashboards, pages, and reports matching the query.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
export declare function SearchResultsPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* SearchResultsPage
|
|
4
|
+
*
|
|
5
|
+
* A dedicated search results page accessible via /apps/:appName/search?q=...
|
|
6
|
+
* Extends the command palette with a full-page search experience, showing
|
|
7
|
+
* objects, dashboards, pages, and reports matching the query.
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useMemo } from 'react';
|
|
11
|
+
import { useSearchParams, Link, useParams } from 'react-router-dom';
|
|
12
|
+
import { Input, Card, CardContent, Badge, } from '@object-ui/components';
|
|
13
|
+
import { Search, Database, LayoutDashboard, FileText, BarChart3, ArrowLeft, } from 'lucide-react';
|
|
14
|
+
import { useMetadata } from '../providers/MetadataProvider';
|
|
15
|
+
/** Flatten nested navigation groups into a flat list of leaf items */
|
|
16
|
+
function flattenNavigation(items) {
|
|
17
|
+
const result = [];
|
|
18
|
+
for (const item of items) {
|
|
19
|
+
if (item.type === 'group' && item.children) {
|
|
20
|
+
result.push(...flattenNavigation(item.children));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
result.push(item);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
const TYPE_ICONS = {
|
|
29
|
+
object: Database,
|
|
30
|
+
dashboard: LayoutDashboard,
|
|
31
|
+
page: FileText,
|
|
32
|
+
report: BarChart3,
|
|
33
|
+
};
|
|
34
|
+
const TYPE_COLORS = {
|
|
35
|
+
object: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
|
|
36
|
+
dashboard: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200',
|
|
37
|
+
page: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
|
|
38
|
+
report: 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200',
|
|
39
|
+
};
|
|
40
|
+
export function SearchResultsPage() {
|
|
41
|
+
const { appName } = useParams();
|
|
42
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
43
|
+
const queryParam = searchParams.get('q') || '';
|
|
44
|
+
const [query, setQuery] = useState(queryParam);
|
|
45
|
+
const { apps: metadataApps } = useMetadata();
|
|
46
|
+
const apps = metadataApps || [];
|
|
47
|
+
const activeApp = apps.find((a) => a.name === appName) || apps[0];
|
|
48
|
+
const baseUrl = `/apps/${appName}`;
|
|
49
|
+
// Build searchable items from navigation
|
|
50
|
+
const allItems = useMemo(() => {
|
|
51
|
+
if (!activeApp)
|
|
52
|
+
return [];
|
|
53
|
+
const navItems = flattenNavigation(activeApp.navigation || []);
|
|
54
|
+
return navItems.map((item) => {
|
|
55
|
+
let href = '#';
|
|
56
|
+
if (item.type === 'object') {
|
|
57
|
+
href = `${baseUrl}/${item.objectName}`;
|
|
58
|
+
if (item.viewName)
|
|
59
|
+
href += `/view/${item.viewName}`;
|
|
60
|
+
}
|
|
61
|
+
else if (item.type === 'dashboard')
|
|
62
|
+
href = `${baseUrl}/dashboard/${item.dashboardName}`;
|
|
63
|
+
else if (item.type === 'page')
|
|
64
|
+
href = `${baseUrl}/page/${item.pageName}`;
|
|
65
|
+
else if (item.type === 'report')
|
|
66
|
+
href = `${baseUrl}/report/${item.reportName}`;
|
|
67
|
+
return {
|
|
68
|
+
id: item.id,
|
|
69
|
+
label: item.label || item.objectName || item.dashboardName || item.pageName || item.reportName || '',
|
|
70
|
+
href,
|
|
71
|
+
type: item.type,
|
|
72
|
+
description: item.description,
|
|
73
|
+
};
|
|
74
|
+
}).filter((item) => item.href !== '#');
|
|
75
|
+
}, [activeApp, baseUrl]);
|
|
76
|
+
// Filter results
|
|
77
|
+
const results = useMemo(() => {
|
|
78
|
+
if (!query.trim())
|
|
79
|
+
return allItems;
|
|
80
|
+
const lower = query.toLowerCase();
|
|
81
|
+
return allItems.filter(item => item.label.toLowerCase().includes(lower) ||
|
|
82
|
+
item.type.toLowerCase().includes(lower) ||
|
|
83
|
+
(item.description && item.description.toLowerCase().includes(lower)));
|
|
84
|
+
}, [allItems, query]);
|
|
85
|
+
const handleSearch = (value) => {
|
|
86
|
+
setQuery(value);
|
|
87
|
+
setSearchParams(value ? { q: value } : {});
|
|
88
|
+
};
|
|
89
|
+
// Group results by type
|
|
90
|
+
const grouped = useMemo(() => {
|
|
91
|
+
var _a;
|
|
92
|
+
const groups = {};
|
|
93
|
+
for (const r of results) {
|
|
94
|
+
(groups[_a = r.type] || (groups[_a] = [])).push(r);
|
|
95
|
+
}
|
|
96
|
+
return groups;
|
|
97
|
+
}, [results]);
|
|
98
|
+
return (_jsxs("div", { className: "flex flex-col gap-6 p-4 sm:p-6 max-w-4xl mx-auto", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs(Link, { to: baseUrl, className: "flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back"] }), _jsx("h1", { className: "text-xl font-semibold", children: "Search" })] }), _jsxs("div", { className: "relative", children: [_jsx("label", { htmlFor: "search-results-input", className: "sr-only", children: "Search objects, dashboards, pages, reports" }), _jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground", "aria-hidden": "true" }), _jsx(Input, { id: "search-results-input", value: query, onChange: (e) => handleSearch(e.target.value), placeholder: "Search objects, dashboards, pages, reports...", className: "pl-10 h-11 text-base", autoFocus: true })] }), _jsx("div", { className: "text-sm text-muted-foreground", children: query.trim()
|
|
99
|
+
? `${results.length} result${results.length !== 1 ? 's' : ''} for "${query}"`
|
|
100
|
+
: `${allItems.length} items available` }), results.length === 0 ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx(Search, { className: "h-12 w-12 text-muted-foreground/30 mb-4" }), _jsx("p", { className: "text-lg font-medium text-muted-foreground", children: "No results found" }), _jsx("p", { className: "text-sm text-muted-foreground/80 mt-1", children: "Try adjusting your search terms" })] })) : (_jsx("div", { className: "space-y-6", children: Object.entries(grouped).map(([type, items]) => {
|
|
101
|
+
const TypeIcon = TYPE_ICONS[type] || Database;
|
|
102
|
+
return (_jsxs("div", { children: [_jsxs("h2", { className: "text-sm font-medium text-muted-foreground mb-2 flex items-center gap-1.5", children: [_jsx(TypeIcon, { className: "h-4 w-4" }), type.charAt(0).toUpperCase() + type.slice(1), "s", _jsx(Badge, { variant: "secondary", className: "ml-1 text-xs", children: items.length })] }), _jsx("div", { className: "grid gap-2", children: items.map(item => {
|
|
103
|
+
const ItemIcon = TYPE_ICONS[item.type] || Database;
|
|
104
|
+
return (_jsx(Link, { to: item.href, className: "rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", children: _jsx(Card, { className: "hover:bg-accent/50 transition-colors cursor-pointer", children: _jsxs(CardContent, { className: "flex items-center gap-3 p-3", children: [_jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded ${TYPE_COLORS[item.type] || ''}`, children: _jsx(ItemIcon, { className: "h-4 w-4" }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-sm font-medium truncate", children: item.label }), item.description && (_jsx("p", { className: "text-xs text-muted-foreground truncate", children: item.description }))] }), _jsx(Badge, { variant: "outline", className: "text-xs shrink-0", children: item.type })] }) }) }, item.id));
|
|
105
|
+
}) })] }, type));
|
|
106
|
+
}) }))] }));
|
|
107
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewConfigPanel — Schema-Driven
|
|
3
|
+
*
|
|
4
|
+
* Airtable-style right-side configuration panel for inline view editing.
|
|
5
|
+
* Migrated to Schema-Driven architecture using ConfigPanelRenderer +
|
|
6
|
+
* useConfigDraft, replacing ~1600 lines of imperative code with a
|
|
7
|
+
* declarative schema factory.
|
|
8
|
+
*
|
|
9
|
+
* All changes are buffered in a local draft state. Clicking Save commits
|
|
10
|
+
* the draft via onSave; Discard resets to the original activeView.
|
|
11
|
+
*/
|
|
12
|
+
/** Editor panel types that can be opened from clickable rows */
|
|
13
|
+
export type EditorPanelType = 'columns' | 'filter' | 'sort';
|
|
14
|
+
export interface ViewConfigPanelProps {
|
|
15
|
+
/** Whether the panel is open */
|
|
16
|
+
open: boolean;
|
|
17
|
+
/** Close callback */
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
/** Panel mode: "edit" for existing views, "create" for new views */
|
|
20
|
+
mode?: 'create' | 'edit';
|
|
21
|
+
/** The active view definition */
|
|
22
|
+
activeView: {
|
|
23
|
+
id: string;
|
|
24
|
+
label?: string;
|
|
25
|
+
type?: string;
|
|
26
|
+
columns?: string[];
|
|
27
|
+
filter?: any[];
|
|
28
|
+
sort?: any[];
|
|
29
|
+
description?: string;
|
|
30
|
+
showSearch?: boolean;
|
|
31
|
+
showFilters?: boolean;
|
|
32
|
+
showSort?: boolean;
|
|
33
|
+
allowExport?: boolean;
|
|
34
|
+
showDescription?: boolean;
|
|
35
|
+
addRecordViaForm?: boolean;
|
|
36
|
+
exportOptions?: any;
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
};
|
|
39
|
+
/** The object definition */
|
|
40
|
+
objectDef: {
|
|
41
|
+
name: string;
|
|
42
|
+
label?: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
fields?: Record<string, any>;
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
};
|
|
47
|
+
/** Optional record count to display */
|
|
48
|
+
recordCount?: number;
|
|
49
|
+
/** Called when any view config field changes (local draft update) */
|
|
50
|
+
onViewUpdate?: (field: string, value: any) => void;
|
|
51
|
+
/** Called to persist all draft changes */
|
|
52
|
+
onSave?: (draft: Record<string, any>) => void;
|
|
53
|
+
/** Called when create-mode view is created */
|
|
54
|
+
onCreate?: (config: Record<string, any>) => void;
|
|
55
|
+
}
|
|
56
|
+
export declare function ViewConfigPanel({ open, onClose, mode, activeView, objectDef, onViewUpdate, onSave, onCreate }: ViewConfigPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ViewConfigPanel — Schema-Driven
|
|
4
|
+
*
|
|
5
|
+
* Airtable-style right-side configuration panel for inline view editing.
|
|
6
|
+
* Migrated to Schema-Driven architecture using ConfigPanelRenderer +
|
|
7
|
+
* useConfigDraft, replacing ~1600 lines of imperative code with a
|
|
8
|
+
* declarative schema factory.
|
|
9
|
+
*
|
|
10
|
+
* All changes are buffered in a local draft state. Clicking Save commits
|
|
11
|
+
* the draft via onSave; Discard resets to the original activeView.
|
|
12
|
+
*/
|
|
13
|
+
import { useMemo, useEffect, useRef, useCallback } from 'react';
|
|
14
|
+
import { ConfigPanelRenderer, useConfigDraft } from '@object-ui/components';
|
|
15
|
+
import { useObjectTranslation } from '@object-ui/i18n';
|
|
16
|
+
import { buildViewConfigSchema, deriveFieldOptions, toFilterGroup, toSortItems, VIEW_TYPE_LABELS, } from '@object-ui/plugin-view';
|
|
17
|
+
export function ViewConfigPanel({ open, onClose, mode = 'edit', activeView, objectDef, onViewUpdate, onSave, onCreate }) {
|
|
18
|
+
const { t } = useObjectTranslation();
|
|
19
|
+
const panelRef = useRef(null);
|
|
20
|
+
// Default empty view for create mode
|
|
21
|
+
const defaultNewView = useMemo(() => ({
|
|
22
|
+
id: `view_${Date.now()}`,
|
|
23
|
+
label: t('console.objectView.newView'),
|
|
24
|
+
type: 'grid',
|
|
25
|
+
columns: [],
|
|
26
|
+
filter: [],
|
|
27
|
+
sort: [],
|
|
28
|
+
showSearch: true,
|
|
29
|
+
showFilters: true,
|
|
30
|
+
showSort: true,
|
|
31
|
+
}), []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
32
|
+
// Stabilize source reference: only change when view ID changes.
|
|
33
|
+
// This prevents useConfigDraft from resetting on every parent re-render
|
|
34
|
+
// (same behavior as original useEffect with [activeView.id] dependency).
|
|
35
|
+
const stableKey = mode === 'create' ? 'create' : activeView.id;
|
|
36
|
+
const stableActiveView = useMemo(() => ({ ...activeView }), [stableKey]);
|
|
37
|
+
const effectiveActiveView = mode === 'create' ? defaultNewView : stableActiveView;
|
|
38
|
+
// Schema-driven draft state management
|
|
39
|
+
const { draft, isDirty, updateField, discard, undo, redo, canUndo, canRedo } = useConfigDraft(effectiveActiveView, {
|
|
40
|
+
mode,
|
|
41
|
+
onUpdate: onViewUpdate,
|
|
42
|
+
});
|
|
43
|
+
// Focus the panel when it opens for keyboard accessibility
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (open && panelRef.current) {
|
|
46
|
+
panelRef.current.focus();
|
|
47
|
+
}
|
|
48
|
+
}, [open]);
|
|
49
|
+
// Derive field options from objectDef
|
|
50
|
+
const fieldOptions = useMemo(() => deriveFieldOptions(objectDef), [objectDef.fields]);
|
|
51
|
+
// Bridge: filter/sort → builder format
|
|
52
|
+
const filterGroupValue = useMemo(() => toFilterGroup(draft.filter), [draft.filter]);
|
|
53
|
+
const sortItemsValue = useMemo(() => toSortItems(draft.sort), [draft.sort]);
|
|
54
|
+
// Build schema
|
|
55
|
+
const schema = useMemo(() => buildViewConfigSchema({
|
|
56
|
+
t,
|
|
57
|
+
fieldOptions,
|
|
58
|
+
objectDef,
|
|
59
|
+
updateField,
|
|
60
|
+
filterGroupValue,
|
|
61
|
+
sortItemsValue,
|
|
62
|
+
}), [t, fieldOptions, objectDef, updateField, filterGroupValue, sortItemsValue]);
|
|
63
|
+
// Override breadcrumb with dynamic view type
|
|
64
|
+
const viewType = draft.type || 'grid';
|
|
65
|
+
const dynamicSchema = useMemo(() => ({
|
|
66
|
+
...schema,
|
|
67
|
+
breadcrumb: [t('console.objectView.page'), VIEW_TYPE_LABELS[viewType] || viewType],
|
|
68
|
+
}), [schema, t, viewType]);
|
|
69
|
+
// Save/discard handlers with create mode support
|
|
70
|
+
const handleSave = useCallback(() => {
|
|
71
|
+
if (mode === 'create') {
|
|
72
|
+
onCreate?.(draft);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
onSave?.(draft);
|
|
76
|
+
}
|
|
77
|
+
// Clear dirty state after save while preserving draft values
|
|
78
|
+
discard();
|
|
79
|
+
}, [draft, onSave, onCreate, mode, discard]);
|
|
80
|
+
const handleDiscard = useCallback(() => {
|
|
81
|
+
if (mode === 'create') {
|
|
82
|
+
onClose();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
discard();
|
|
86
|
+
}, [discard, mode, onClose]);
|
|
87
|
+
const panelTitle = mode === 'create'
|
|
88
|
+
? t('console.objectView.createView')
|
|
89
|
+
: t('console.objectView.configureView');
|
|
90
|
+
return (_jsx(ConfigPanelRenderer, { open: open, onClose: onClose, schema: dynamicSchema, draft: draft, isDirty: isDirty, onFieldChange: updateField, onSave: handleSave, onDiscard: handleDiscard, onUndo: undo, onRedo: redo, canUndo: canUndo, canRedo: canRedo, undoLabel: t('designer.undo'), redoLabel: t('designer.redo'), objectDef: objectDef, saveLabel: t('console.objectView.save'), discardLabel: t('console.objectView.discard'), panelRef: panelRef, role: "complementary", ariaLabel: panelTitle, tabIndex: -1, testId: "view-config-panel", closeTitle: t('console.objectView.closePanel'), footerTestId: "view-config-footer", saveTestId: "view-config-save", discardTestId: "view-config-discard", className: "transition-all overflow-hidden" }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { ObjectView } from './ObjectView';
|
|
2
|
+
export { RecordDetailView } from './RecordDetailView';
|
|
3
|
+
export { DashboardView } from './DashboardView';
|
|
4
|
+
export { PageView } from './PageView';
|
|
5
|
+
export { ReportView } from './ReportView';
|
|
6
|
+
export { SearchResultsPage } from './SearchResultsPage';
|
|
7
|
+
export { ActionConfirmDialog } from './ActionConfirmDialog';
|
|
8
|
+
export { ActionParamDialog } from './ActionParamDialog';
|
|
9
|
+
export { MetadataToggle, MetadataPanel } from './MetadataInspector';
|
|
10
|
+
export { ViewConfigPanel } from './ViewConfigPanel';
|
|
11
|
+
export { DesignDrawer } from './DesignDrawer';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { ObjectView } from './ObjectView';
|
|
2
|
+
export { RecordDetailView } from './RecordDetailView';
|
|
3
|
+
export { DashboardView } from './DashboardView';
|
|
4
|
+
export { PageView } from './PageView';
|
|
5
|
+
export { ReportView } from './ReportView';
|
|
6
|
+
export { SearchResultsPage } from './SearchResultsPage';
|
|
7
|
+
export { ActionConfirmDialog } from './ActionConfirmDialog';
|
|
8
|
+
export { ActionParamDialog } from './ActionParamDialog';
|
|
9
|
+
export { MetadataToggle, MetadataPanel } from './MetadataInspector';
|
|
10
|
+
export { ViewConfigPanel } from './ViewConfigPanel';
|
|
11
|
+
export { DesignDrawer } from './DesignDrawer';
|