@object-ui/app-shell 3.3.2 → 4.0.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.
@@ -17,7 +17,7 @@ import { SkeletonDashboard } from '../skeletons';
17
17
  import { useMetadata } from '../providers/MetadataProvider';
18
18
  import { resolveI18nLabel } from '../utils';
19
19
  import { useAdapter } from '../providers/AdapterProvider';
20
- import { useObjectTranslation } from '@object-ui/i18n';
20
+ import { useObjectTranslation, useObjectLabel } from '@object-ui/i18n';
21
21
  // ---------------------------------------------------------------------------
22
22
  // Widget type palette for the add-widget toolbar
23
23
  // ---------------------------------------------------------------------------
@@ -105,6 +105,7 @@ export function DashboardView({ dataSource }) {
105
105
  const { showDebug } = useMetadataInspector();
106
106
  const adapter = useAdapter();
107
107
  const { t } = useObjectTranslation();
108
+ const { dashboardLabel, dashboardDescription } = useObjectLabel();
108
109
  const [isLoading, setIsLoading] = useState(true);
109
110
  const [configPanelOpen, setConfigPanelOpen] = useState(false);
110
111
  const [selectedWidgetId, setSelectedWidgetId] = useState(null);
@@ -120,13 +121,28 @@ export function DashboardView({ dataSource }) {
120
121
  });
121
122
  }, []);
122
123
  const modalHandler = useCallback((schema) => new Promise((resolve) => {
123
- // Normalize string schema (e.g. action.target = 'opportunity') to a
124
- // ModalForm-compatible descriptor so header `modal` actions like
125
- // { actionType: 'modal', actionUrl: 'opportunity' } open the create
126
- // form for that object.
127
- const normalized = typeof schema === 'string'
128
- ? { objectName: schema, mode: 'create' }
129
- : schema;
124
+ // Normalize string schema (e.g. action.target = 'opportunity' or
125
+ // 'create_opportunity') to a ModalForm-compatible descriptor so header
126
+ // `modal` actions like { actionType: 'modal', actionUrl: 'create_opportunity' }
127
+ // open the create form for that object. Supports the conventional
128
+ // `<verb>_<object>` form (create_/new_/add_/edit_/update_) emitted by
129
+ // server-driven dashboard schemas.
130
+ let normalized;
131
+ if (typeof schema === 'string') {
132
+ const m = schema.match(/^(create|new|add|edit|update)_(.+)$/);
133
+ if (m) {
134
+ const verb = m[1];
135
+ const objectName = m[2];
136
+ const mode = verb === 'edit' || verb === 'update' ? 'edit' : 'create';
137
+ normalized = { objectName, mode };
138
+ }
139
+ else {
140
+ normalized = { objectName: schema, mode: 'create' };
141
+ }
142
+ }
143
+ else {
144
+ normalized = schema;
145
+ }
130
146
  setModalState({ schema: normalized, resolve });
131
147
  }), []);
132
148
  const scriptHandlers = useMemo(() => ({
@@ -336,7 +352,13 @@ export function DashboardView({ dataSource }) {
336
352
  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(LayoutDashboard, { className: "h-6 w-6 text-muted-foreground" }) }), _jsx(EmptyTitle, { children: "Dashboard Not Found" }), _jsxs(EmptyDescription, { children: ["The dashboard \"", dashboardName, "\" could not be found. It may have been removed or renamed."] })] }) }));
337
353
  }
338
354
  const previewSchema = editSchema || dashboard;
339
- 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: resolveI18nLabel(dashboard.label, t) || dashboard.name }), dashboard.description && (_jsx("p", { className: "text-sm text-muted-foreground mt-1 line-clamp-2", children: resolveI18nLabel(dashboard.description, t) }))] }), _jsxs("div", { className: "shrink-0 flex items-center gap-1.5", children: [configPanelOpen && (_jsx("div", { className: "flex items-center gap-1 mr-2", role: "toolbar", "aria-label": "Add widgets", "data-testid": "dashboard-widget-toolbar", children: WIDGET_TYPES.map(({ type, label, Icon }) => (_jsxs("button", { type: "button", "data-testid": `dashboard-add-${type}`, onClick: () => addWidget(type), className: "inline-flex items-center gap-1 rounded-md border border-input bg-background px-2 py-1.5 text-[11px] font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", title: `Add ${label}`, "aria-label": `Add ${label} widget`, children: [_jsx(Plus, { className: "h-3 w-3" }), _jsx(Icon, { className: "h-3 w-3" })] }, type))) })), _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": "dashboard-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-2 sm:p-4 md:p-6", children: _jsx(DashboardRenderer, { schema: previewSchema, dataSource: dataSource, designMode: configPanelOpen, selectedWidgetId: selectedWidgetId, onWidgetClick: setSelectedWidgetId, modalHandler: modalHandler, scriptHandlers: scriptHandlers }) }), selectedWidget ? (_jsx(WidgetConfigPanel, { open: configPanelOpen, onClose: handleCloseConfigPanel, config: widgetConfig, onSave: handleWidgetConfigSave, onFieldChange: handleWidgetFieldChange, availableObjects: availableObjects, availableFields: availableFields, headerExtra: _jsx(Button, { size: "sm", variant: "ghost", onClick: () => removeWidget(selectedWidgetId), className: "h-7 w-7 p-0 text-destructive hover:text-destructive", "data-testid": "widget-delete-button", title: "Delete widget", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }, selectedWidgetId)) : (_jsx(DashboardConfigPanel, { open: configPanelOpen, onClose: handleCloseConfigPanel, config: dashboardConfig, onSave: handleDashboardConfigSave, onFieldChange: handleDashboardFieldChange })), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'Dashboard Configuration', data: previewSchema }] })] }), modalState && modalState.schema?.objectName ? (_jsx(ModalForm, { schema: {
355
+ 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: dashboardLabel({ name: dashboard.name, label: resolveI18nLabel(dashboard.label, t) }) || dashboard.name }), (() => {
356
+ const desc = dashboardDescription({
357
+ name: dashboard.name,
358
+ description: resolveI18nLabel(dashboard.description, t),
359
+ });
360
+ return desc ? (_jsx("p", { className: "text-sm text-muted-foreground mt-1 line-clamp-2", children: desc })) : null;
361
+ })()] }), _jsxs("div", { className: "shrink-0 flex items-center gap-1.5", children: [configPanelOpen && (_jsx("div", { className: "flex items-center gap-1 mr-2", role: "toolbar", "aria-label": "Add widgets", "data-testid": "dashboard-widget-toolbar", children: WIDGET_TYPES.map(({ type, label, Icon }) => (_jsxs("button", { type: "button", "data-testid": `dashboard-add-${type}`, onClick: () => addWidget(type), className: "inline-flex items-center gap-1 rounded-md border border-input bg-background px-2 py-1.5 text-[11px] font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", title: `Add ${label}`, "aria-label": `Add ${label} widget`, children: [_jsx(Plus, { className: "h-3 w-3" }), _jsx(Icon, { className: "h-3 w-3" })] }, type))) })), _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": "dashboard-edit-button", children: [_jsx(Pencil, { className: "h-3.5 w-3.5" }), t('common.edit', { defaultValue: '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-2 sm:p-4 md:p-6", children: _jsx(DashboardRenderer, { schema: previewSchema, dataSource: dataSource, designMode: configPanelOpen, selectedWidgetId: selectedWidgetId, onWidgetClick: setSelectedWidgetId, modalHandler: modalHandler, scriptHandlers: scriptHandlers }) }), selectedWidget ? (_jsx(WidgetConfigPanel, { open: configPanelOpen, onClose: handleCloseConfigPanel, config: widgetConfig, onSave: handleWidgetConfigSave, onFieldChange: handleWidgetFieldChange, availableObjects: availableObjects, availableFields: availableFields, headerExtra: _jsx(Button, { size: "sm", variant: "ghost", onClick: () => removeWidget(selectedWidgetId), className: "h-7 w-7 p-0 text-destructive hover:text-destructive", "data-testid": "widget-delete-button", title: "Delete widget", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }, selectedWidgetId)) : (_jsx(DashboardConfigPanel, { open: configPanelOpen, onClose: handleCloseConfigPanel, config: dashboardConfig, onSave: handleDashboardConfigSave, onFieldChange: handleDashboardFieldChange })), _jsx(MetadataPanel, { open: showDebug, sections: [{ title: 'Dashboard Configuration', data: previewSchema }] })] }), modalState && modalState.schema?.objectName ? (_jsx(ModalForm, { schema: {
340
362
  type: 'object-form',
341
363
  formType: 'modal',
342
364
  objectName: modalState.schema.objectName,