Repository navigation
v0.27.0
@kanzo-tech/ui · @kanzo-tech/graph · @kanzo-tech/mosaic
The Mosaic stack is ^0.32.0, and npm install @kanzo-tech/ui works. mosaic-core 0.29 published
a workspace:^ peer range that npm refuses to install; every @uwdata/mosaic-* and vgplot range
here — peers and the optional analytics peers — is now ^0.32.0. DuckDB-WASM stays at
1.33.1-dev57.0, the release mosaic-core 0.32 pins. Raise your own @uwdata/* installs to 0.32:
npm i @uwdata/mosaic-core@^0.32.0 @uwdata/mosaic-sql@^0.32.0 @uwdata/vgplot@^0.32.0 @uwdata/mosaic-plot@^0.32.0What changes for your code with 0.32:
- A failed query still reaches
onFailureas it was thrown. mosaic-core now hands a client's
queryErroraQueryErrorwrapping the original, with the SQL appended to its message. The charts,
the inputs,ChartStatand the graph unwrap it, soonFailurereceives the original error with its
codeand message intact. AMosaicClientof your own does the same withqueryFailure(error), new
on@kanzo-tech/mosaicand@kanzo-tech/ui/analytics. coordinator.query(sql, { type: "json" })answers an Arrow table — thetypeoption is gone.
Read rows withtable.toArray().- A connector of your own answers Arrow as IPC bytes, which mosaic-core decodes; one that returned
a decoded table fails with "IPC data batch was not a Uint8Array". clausePoints(fields, [])is a clause that drops every row, not a retraction. Passundefinedto
retract one.ChartFilterdoes so when the last value is unticked.
@kanzo-tech/graph
GraphSelect, and a selection source that names no host. SelectionSource is the canvas's own
gestures — "marquee", "lasso", "node" — and "external" for a selection you set through
select. "order" and "ask" are gone, and select(vertices) without a source is now
"external" (it was "node").
If you passed "order", "ask" or any source of your own to select, pass "external" and keep
the label: the label is what tells your selections apart.
GraphSelect is the toggle a panel offers — these vertices, on the canvas:
<GraphSelect label="Contracts past due" load={() => idsOf(rule)}>
…the body you click…
</GraphSelect>load runs when it is pressed; pressed is the live selection being "external" with this label,
so a lasso elsewhere releases it; a rejected load reaches the root's onFailure as thrown. If you
built this toggle yourself over useGraphContext().select and useGraphState, delete it.
An unbound graph — x and y left to the layout — draws again. Under cosmos.gl 3.4 every such graph
opened blank, whatever its size: the simulation was turned on before the render that uploads
the positions, cosmos.gl dropped that upload, and each layout tick threw Cannot destructure property 'device' of 'texture' from the camera's fitView. The layout now starts after that render, at any size.
The camera reads positions back only once the device is up and they have been rendered, and if a read
fails anyway the graph reports it instead of throwing every frame: onFailure receives a GraphError
with the new code graph/no-positions (the read's error as its cause) and the status is failed. A
host that switches over GraphError["code"] has one more case to show.
@kanzo-tech/ui
Problem draws any thrown value as a Diagnostic. Pass what your catch holds; it reads the
shape every coded error here shares — code (area/kind), title, message, data, cause, and
severity, help and related where present — and nests the causes below it. Your words for a
code come from one function:
<DiagnosticList>
<Problem copy={(code, data) => registry[code]} error={error}>
<Button onClick={retry} size="sm" variant="outline">Try again</Button>
</Problem>
</DiagnosticList>copy returns { title?, detail?, link?: { label, href }, page? } or undefined; a rewritten
detail keeps the error's own row one level down. Each row's details trigger is named
Details: <title>; translations changes that and the severity words.
If you mapped errors onto Diagnostic parts yourself, you can delete that code.
useQueryRows(query) on @kanzo-tech/ui/analytics: a statement's rows, suspending until they
land. It reads the provider's coordinator, answers rows as objects keyed by column, and shares one
answer per statement across every component that asks it. A failure is thrown, as it was thrown, to
the nearest error boundary, and the boundary's retry asks again.
const columns = useQueryRows<{ column_name: string }>(`DESCRIBE ${table}`);It does not follow the crossfilter — it is for a schema, a catalog, a lookup; anything that should
move with the brush stays useChartQuery. If you wrapped coordinator.query in a suspense cache of
your own (TanStack's useSuspenseQuery, say), this replaces it.
@kanzo-tech/mosaic
engine().query answers in a background tab. It went through the coordinator's queue, which
batches Arrow requests behind requestAnimationFrame — and a hidden tab never paints one, so a
corpus opened while the tab was in the background (fossil's open: the secret, the attach, the
views) waited forever with no error, and a host's statement could sit behind a batch of chart
queries. It now goes straight to the connection and is decoded as the coordinator decodes. Charts
still batch as before. A refused statement still rejects with DuckDB's own error. Nothing to change
in your code.
@kanzo-tech/auth
ticketStore bounds every adapter call itself, and accountUrl links Keycloak's account console.
- Every
read,writeanddeleteaticketStoremakes on its adapter now ends at 30 s, rejecting
assession/silent(data.after: 30000), whichrelyingPartyreports assession/unavailable
with that as the cause. If your adapter raced its own driver calls against a timeout, delete that:
an adapter is the three driver calls. Keep the driver's connect timeout and no-offline-queue
settings, which make a store that is down refuse at once. accountUrl(issuer, page?)returns{issuer}/account, or one of its pages —
AccountPage:"","account-security/signing-in","account-security/device-activity". If you
built that URL yourself, use this.