Skip to content

Commit 4251dae

Browse files
authored
Merge pull request #819 from objectstack-ai/copilot/optimize-widget-panel-experience
2 parents 356d017 + c4d423d commit 4251dae

File tree

5 files changed

+495
-113
lines changed

5 files changed

+495
-113
lines changed

apps/console/src/components/DashboardView.tsx

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ function createWidgetId(): string {
5151
return `widget_${Date.now()}_${widgetCounter}`;
5252
}
5353

54+
// ---------------------------------------------------------------------------
55+
// Helpers
56+
// ---------------------------------------------------------------------------
57+
58+
/** Ensure every widget in the schema has a unique id. */
59+
function ensureWidgetIds(schema: DashboardSchema): DashboardSchema {
60+
if (!schema.widgets?.length) return schema;
61+
const needsFix = schema.widgets.some((w) => !w.id);
62+
if (!needsFix) return schema;
63+
return {
64+
...schema,
65+
widgets: schema.widgets.map((w) => (w.id ? w : { ...w, id: createWidgetId() })),
66+
};
67+
}
68+
69+
/** Resolve a human-friendly default title for a new widget type. */
70+
function defaultWidgetTitle(type: string): string {
71+
const entry = WIDGET_TYPES.find((t) => t.type === type);
72+
return entry ? `New ${entry.label}` : 'New Widget';
73+
}
74+
5475
// ---------------------------------------------------------------------------
5576
// Helpers: flatten / unflatten widget config for WidgetConfigPanel
5677
// ---------------------------------------------------------------------------
@@ -120,7 +141,7 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
120141
queueMicrotask(() => setIsLoading(false));
121142
}, [dashboardName]);
122143

123-
const { dashboards } = useMetadata();
144+
const { dashboards, objects: metadataObjects } = useMetadata();
124145
const dashboard = dashboards?.find((d: any) => d.name === dashboardName);
125146

126147
// Local schema state for live preview — initialized from metadata
@@ -142,7 +163,7 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
142163

143164
// ---- Open / close config panel ------------------------------------------
144165
const handleOpenConfigPanel = useCallback(() => {
145-
setEditSchema(dashboard as DashboardSchema);
166+
setEditSchema(ensureWidgetIds(dashboard as DashboardSchema));
146167
setConfigPanelOpen(true);
147168
setConfigVersion((v) => v + 1);
148169
}, [dashboard]);
@@ -159,7 +180,7 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
159180
const id = createWidgetId();
160181
const newWidget: DashboardWidgetSchema = {
161182
id,
162-
title: '',
183+
title: defaultWidgetTitle(type),
163184
type,
164185
layout: {
165186
x: 0,
@@ -290,6 +311,33 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
290311
[selectedWidgetId],
291312
);
292313

314+
// ---- Metadata-driven dropdown options -----------------------------------
315+
const availableObjects = useMemo(() => {
316+
if (!metadataObjects?.length) return undefined;
317+
return metadataObjects.map((obj: any) => ({
318+
value: obj.name,
319+
label: obj.label || obj.name,
320+
}));
321+
}, [metadataObjects]);
322+
323+
const availableFields = useMemo(() => {
324+
const objectName = selectedWidget?.object;
325+
if (!objectName || !metadataObjects?.length) return undefined;
326+
const obj = metadataObjects.find((o: any) => o.name === objectName);
327+
if (!obj?.fields) return undefined;
328+
const fields = obj.fields;
329+
if (Array.isArray(fields)) {
330+
return fields
331+
.filter((f: any) => f.name)
332+
.map((f: any) => ({ value: f.name, label: f.label || f.name }));
333+
}
334+
// fields can be Record<string, FieldMetadata>
335+
return Object.entries(fields).map(([key, f]: [string, any]) => ({
336+
value: key,
337+
label: f.label || key,
338+
}));
339+
}, [selectedWidget?.object, metadataObjects]);
340+
293341
// ---- Loading / not-found guards -----------------------------------------
294342
if (isLoading) {
295343
return <SkeletonDashboard />;
@@ -377,6 +425,8 @@ export function DashboardView({ dataSource }: { dataSource?: any }) {
377425
config={widgetConfig}
378426
onSave={handleWidgetConfigSave}
379427
onFieldChange={handleWidgetFieldChange}
428+
availableObjects={availableObjects}
429+
availableFields={availableFields}
380430
headerExtra={
381431
<Button
382432
size="sm"

0 commit comments

Comments
 (0)