Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .changeset/adr-0047-interface-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@object-ui/app-shell": minor
"@object-ui/plugin-list": minor
"@object-ui/plugin-grid": minor
"@object-ui/data-objectstack": minor
---

feat: ADR-0047 — interface pages, visualization switcher, and Airtable-parity filters

End-user interface/list pages reach full rendering and authoring parity:

- **Spec tabs + visualization switcher** — `ObjectView` now forwards
`viewDef.tabs` (stored/served but never rendered) and `viewDef.appearance`
(`allowedVisualizations` whitelist), turning on the dormant `ViewSwitcher` when
more than one type is whitelisted; effective options = author whitelist ∩
capability-resolvable types (kanban needs `groupBy`, calendar a date field, …).
`ListView` accepts the canonical `ViewFilterRule[]` tab-filter shape.
- **User filters** — render only when `userFilters` is explicitly configured;
selections (dropdown values + active tab) mirror into `uf_*` URL params and
restore on load, so filtered lists survive reload and are shareable.
- **Toolbar polish** — the visualization switcher becomes a compact right-side
"Grid ▾" dropdown inside the tool cluster (no extra row); filter tabs and
dropdown filters are mutually exclusive.
- **Studio authoring** — a usable, schema-driven interface-page inspector
(collapsible sections honoured, array-of-enum → multi-select, a None/Tabs/
Dropdown `filter-mode` selector where None maps to ABSENCE of `userFilters`),
and the Design/Preview tabs render the live list via `InterfaceListPage`
(including a non-empty grid when the source view is hollow).
21 changes: 21 additions & 0 deletions .changeset/adr-0048-app-shell-package-routing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@object-ui/app-shell": minor
---

feat(app-shell): ADR-0048 (option A) — package-id app routing + prefer-local resolution

Apps are now routed by their canonical package id rather than name:

- **Resolution layer** — new `appRoute` helpers: `appRouteSegment(app)`
(canonical link segment = package id, name fallback) and
`matchAppBySegment(apps, seg)` (prefers `_packageId`, falls back to `name`).
`AppContent` selects the active app via `matchAppBySegment`, so
`/apps/<packageId>` resolves while `/apps/<appName>` keeps working (a per-tenant
alias / legacy URL).
- **Emission layer** — nav generates `/apps/<packageId>` links across app
switching (AppSwitcher/AppSidebar/CommandPalette), sidebar base paths,
create/edit-app, and the hidden-app switch, all via `appRouteSegment(app)`.
- **Prefer-local resolution** — `preferLocal(list, name, ownerPackageId)` resolves
a bare metadata name to the item whose `_packageId` matches the active app's
package (falling back to first match), wired at PageView/DashboardView/
ReportView and AppHeader so two installed packages can ship the same bare name.
19 changes: 19 additions & 0 deletions .changeset/ai-workspace-console-ux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
"@object-ui/app-shell": minor
---

feat(console/ai): AI workspace UX — date-grouped conversations, draggable split, keyboard shortcuts

ChatGPT/Claude-parity polish for the console AI workspace:

- **Date-grouped conversations** — the flat conversations list groups into
recency sections (Today / Yesterday / Previous 7 days / Previous 30 days /
Older) with calendar-day boundaries, via a pure exported
`groupConversationsByDate()`.
- **Draggable chat ↔ preview split** — a draggable, double-click-to-reset divider
between chat and the Live Canvas preview; width persists to `localStorage`,
clamped so neither pane collapses (chat ≥ 360px, preview ≥ 420px), keyboard-
accessible (`role="separator"`, ←/→ resize).
- **Collapsible conversations list** — auto-tucks when the preview opens, with a
manual toggle.
- **Keyboard shortcuts** — ⌘⇧O new chat, ⌘⇧S toggle the conversations list.
15 changes: 15 additions & 0 deletions .changeset/app-shell-ai-current-object-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@object-ui/app-shell": patch
---

fix(app-shell): send the current-page object to the AI assistant context

The floating console assistant forwarded only `appName` + the full objects list,
never the object the user is actually viewing — so asking it to "analyse this
object" (especially in a non-English prompt) gave the agent nothing to anchor on
and it replied that it couldn't find the object. The current object/record are
now derived from the route (mirroring `useTrackRouteAsRecent`'s URL layout,
tolerant of a `_console` shell prefix) and passed as `context.objectName` /
`context.recordId`, so the backend injects that object's schema into the system
prompt and scopes data queries to it. Pairs with the framework current-object
resolution fix.
16 changes: 16 additions & 0 deletions .changeset/app-shell-newtab-fast-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@object-ui/app-shell": minor
"@object-ui/core": minor
---

feat(app-shell): zero-roundtrip `newTabUrl` fast path for `opensInNewTab` actions

Actions that declare `newTabUrl` (a path template with a `{recordId}` placeholder
whose target endpoint performs all auth/authz itself) now drive the pre-opened
popup straight to that URL on click, skipping the action POST entirely — applied
to both server-action paths (list rows via `useConsoleActionRuntime`, record
header via `RecordDetailView`). The popup paints the existing spinner page until
the (possibly slow) endpoint commits its redirect; the URL is resolved absolute
because `about:blank` gives a bare-relative href no reliable base. The
popup-blocked toast fallback is unchanged. Removes one full round trip of
white-screen latency from every such Open click.
17 changes: 17 additions & 0 deletions .changeset/chatbot-data-chart-inline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@object-ui/plugin-chatbot": minor
---

feat(plugin-chatbot): render AI data-query charts inline (`data-chart`)

Companion to the framework `visualize_data` tool: the data-query assistant can
now answer with a CHART rendered right in the assistant bubble.

- `mapMessages.ts` — `extractCharts()` lifts every `data-chart` custom stream
part onto `ChatMessage.charts` (defensive narrowing; preserves multiple charts
in order), mirroring the existing `data-build-progress` → `buildProgress` path.
- `ChatbotEnhanced.tsx` — renders each chart via `<SchemaRenderer schema={{
type:'chart', … }}/>` (decoupled — no hard dep on `plugin-charts`), giving the
chart a definite `width: min(520px, 80vw)` so recharts' `ResponsiveContainer`
measures a stable non-zero width inside the `w-fit` bubble (otherwise the
circular width dependency leaves bars unpainted).
21 changes: 21 additions & 0 deletions .changeset/chatbot-turn-liveness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@object-ui/plugin-chatbot": minor
---

feat(plugin-chatbot): honest liveness indicator on running AI turns

AI app builds run 1–3 min with long quiet gaps (LLM thinking, sample-data
generation) where a static spinner is indistinguishable from a dropped
connection. The chat now shows a Claude-Code-style liveness indicator driven by
REAL observed stream activity, not a free-running clock:

- `useTurnLiveness(active, activityKey)` stamps the moment real data arrives (a
streamed token / tool delta / `data-build-progress` update) and measures
seconds-since-last-byte.
- `LivenessIndicator` renders three honest states — *receiving* (emerald pulse +
m:ss, bytes arrived recently), *waiting* (request in flight, nothing back yet),
and *stalled* (amber + "no response for Ns", genuinely silent past 6s).
- The build panel prefers the server's monotonic `seq` keep-alive heartbeat as
its activity key (falling back to the content signature on older runtimes), so
a long quiet seed-generation window reads as honestly *receiving* rather than
flipping to amber.
18 changes: 18 additions & 0 deletions .changeset/gantt-navigation-year-scale-pdf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@object-ui/plugin-gantt": minor
---

feat(gantt): year scale, navigation, saved layout, and PDF export (follow-up to #1672)

- **Year scale** — new `year` granularity (one column per year, with a "20XXs"
decade group band above); ResourceWorkload follows the same column width/label.
- **Navigation** — toolbar gains *This week* / *This month* jump buttons (beside
the existing *Today*), scrolling the timeline to the current week/month start.
- **Saved layout** — `persistLayoutKey` / `onLayoutChange` plus a "Save layout"
button snapshot the current granularity + zoom + collapsed task columns to
`localStorage` (`gantt-layout:<object>:<view>`) and restore on next load (an
explicit `viewMode` prop still wins). `ObjectGantt` derives the key from the
data object by default; `persistLayout: false` opts out.
- **PDF export** — rasterizes the whole chart SVG to JPEG embedded in a
zero-dependency single-page PDF (DCTDecode), alongside PNG export
(`buildExportSvg` shared by both).
18 changes: 18 additions & 0 deletions .changeset/gantt-tooltip-parent-stretch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
"@object-ui/plugin-gantt": minor
---

feat(gantt): configurable hover tooltip + live parent-stretch (follow-up to #1672)

- **Configurable tooltip** — a view declares `tooltipFields` on its gantt config
(field names, or `{ field, label }` to override the label); `ObjectGantt`
resolves each against the record (select options → label, lookups → embedded
record name, dates/numbers/currency/percent through the shared `@object-ui/
fields` formatters) and feeds `GanttView` a `task.fields` array that replaces
the default hover detail.
- **Live parent-stretch** — a summary bar's displayed range rolls up from its
children live, so dragging a child past the parent's edge stretches the parent.
- Also replaces six prebuilt-CSS utilities the components stylesheet never emits
(connector dot `-right-2` was occluding the progress label, resize-handle
width, progress-fill radius, grid z-index, `sm:` variants) with inline styles
/ a scoped media query so the chart renders correctly in consuming apps.
16 changes: 16 additions & 0 deletions .changeset/plugin-list-select-schema-gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@object-ui/plugin-list": patch
---

fix(plugin-list): gate speculative `$select` fields by the object's real schema

A list view auto-includes view-binding fields (kanban `groupBy`, calendar/gantt/
timeline dates, gallery image, timeline status/priority) in `$select` so
alternate view modes render populated. These were added unconditionally on the
assumption that "the projection ignores unknown names" — but some backends
(notably the cloud multi-tenant runtime) reject an unknown `$select` column with
an EMPTY result set, so a single phantom field zeroed the whole list (an AI-built
`product` view requesting `status`/`due_date`/`image` showed "no data" though
rows existed). The speculative additions now go through `addSpeculative()`, which
keeps only fields present in the object schema; user-declared columns and expand
roots are untouched.
13 changes: 13 additions & 0 deletions .changeset/plugin-report-dataset-matrix-totals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@object-ui/plugin-report": minor
---

feat(plugin-report): server-supplied totals in dataset matrix reports

Pairs with the framework's server-side `queryDataset` totals. The matrix renderer
now requests `totals: { groupings: [rows, columns, []] }` and renders the
returned pre-aggregated rows — a trailing Total column per measure (row
subtotals), a trailing Total row (column subtotals), and the grand total at their
intersection — matched to pivot headers via the same `bucketId` logic. A response
without totals (older server) renders exactly as before; the client never
re-aggregates (ADR-0021).