feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
"use client" ;
import React , { useState , useCallback , useMemo , useRef , useEffect } from "react" ;
import {
useReactTable ,
getCoreRowModel ,
getSortedRowModel ,
getFilteredRowModel ,
getPaginationRowModel ,
flexRender ,
type ColumnDef ,
type SortingState ,
type ColumnFiltersState ,
type VisibilityState ,
type Row ,
type OnChangeFn ,
type PaginationState ,
} from "@tanstack/react-table" ;
import {
DndContext ,
closestCenter ,
type DragEndEvent ,
PointerSensor ,
useSensor ,
useSensors ,
} from "@dnd-kit/core" ;
import {
SortableContext ,
horizontalListSortingStrategy ,
useSortable ,
arrayMove ,
} from "@dnd-kit/sortable" ;
import { CSS } from "@dnd-kit/utilities" ;
import { rankItem } from "@tanstack/match-sorter-utils" ;
/* ─── Types ─── */
export type RowAction < TData > = {
label : string ;
onClick ? : ( row : TData ) = > void ;
icon? : React.ReactNode ;
variant ? : "default" | "destructive" ;
} ;
export type DataTableProps < TData , TValue > = {
columns : ColumnDef < TData , TValue > [ ] ;
data : TData [ ] ;
loading? : boolean ;
// search
searchPlaceholder? : string ;
enableGlobalFilter? : boolean ;
// sorting
enableSorting? : boolean ;
// row selection
enableRowSelection? : boolean ;
rowSelection? : Record < string , boolean > ;
onRowSelectionChange? : OnChangeFn < Record < string , boolean > > ;
bulkActions? : React.ReactNode ;
// column features
enableColumnReordering? : boolean ;
onColumnReorder ? : ( newOrder : string [ ] ) = > void ;
initialColumnVisibility? : VisibilityState ;
// pagination
pageSize? : number ;
// actions
onRefresh ? : ( ) = > void ;
onAdd ? : ( ) = > void ;
addButtonLabel? : string ;
onRowClick ? : ( row : TData , index : number ) = > void ;
rowActions ? : ( row : TData ) = > RowAction < TData > [ ] ;
// toolbar
toolbarExtra? : React.ReactNode ;
title? : string ;
titleIcon? : React.ReactNode ;
// sticky
stickyFirstColumn? : boolean ;
2026-02-19 14:59:34 -08:00
// server-side pagination
serverPagination ? : {
totalCount : number ;
page : number ;
pageSize : number ;
onPageChange : ( page : number ) = > void ;
onPageSizeChange : ( size : number ) = > void ;
} ;
// server-side search callback (replaces client-side fuzzy filter)
onServerSearch ? : ( query : string ) = > void ;
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
} ;
/* ─── Fuzzy filter ─── */
function fuzzyFilter (
row : Row < unknown > ,
columnId : string ,
filterValue : string ,
) {
const result = rankItem ( row . getValue ( columnId ) , filterValue ) ;
return result . passed ;
}
/* ─── Sortable header cell (DnD) ─── */
function SortableHeader ( {
id ,
children ,
style ,
className ,
} : {
id : string ;
children : React.ReactNode ;
style? : React.CSSProperties ;
className? : string ;
} ) {
const {
attributes ,
listeners ,
setNodeRef ,
transform ,
transition ,
isDragging ,
} = useSortable ( { id } ) ;
const dragStyle : React.CSSProperties = {
. . . style ,
transform : CSS.Translate.toString ( transform ) ,
transition ,
opacity : isDragging ? 0.5 : 1 ,
cursor : "grab" ,
} ;
return (
< th
ref = { setNodeRef }
style = { dragStyle }
className = { className }
{ . . . attributes }
{ . . . listeners }
>
{ children }
< / th >
) ;
}
/* ─── Sort icon ─── */
function SortIcon ( { direction } : { direction : "asc" | "desc" | false } ) {
if ( ! direction ) {
return (
< svg width = "12" height = "12" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" style = { { opacity : 0.25 } } >
< path d = "m7 15 5 5 5-5" / > < path d = "m7 9 5-5 5 5" / >
< / svg >
) ;
}
return (
< svg width = "12" height = "12" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" >
{ direction === "asc" ? < path d = "m5 12 7-7 7 7" / > : < path d = "m19 12-7 7-7-7" / > }
< / svg >
) ;
}
/* ─── Main component ─── */
export function DataTable < TData , TValue > ( {
columns ,
data ,
loading = false ,
searchPlaceholder = "Search..." ,
enableGlobalFilter = true ,
enableSorting = true ,
enableRowSelection = false ,
rowSelection : externalRowSelection ,
onRowSelectionChange ,
bulkActions ,
enableColumnReordering = false ,
onColumnReorder ,
initialColumnVisibility ,
pageSize : defaultPageSize = 100 ,
onRefresh ,
onAdd ,
addButtonLabel = "+ Add" ,
onRowClick ,
rowActions ,
toolbarExtra ,
title ,
titleIcon ,
stickyFirstColumn : stickyFirstProp = true ,
2026-02-19 14:59:34 -08:00
serverPagination ,
onServerSearch ,
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
} : DataTableProps < TData , TValue > ) {
const [ sorting , setSorting ] = useState < SortingState > ( [ ] ) ;
const [ globalFilter , setGlobalFilter ] = useState ( "" ) ;
const [ columnFilters , setColumnFilters ] = useState < ColumnFiltersState > ( [ ] ) ;
const [ columnVisibility , setColumnVisibility ] = useState < VisibilityState > ( initialColumnVisibility ? ? { } ) ;
2026-02-17 00:36:01 -08:00
// Sync column visibility when the prop changes (e.g. loading a saved view)
useEffect ( ( ) = > {
if ( initialColumnVisibility ) {
setColumnVisibility ( initialColumnVisibility ) ;
}
} , [ initialColumnVisibility ] ) ;
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
const [ internalRowSelection , setInternalRowSelection ] = useState < Record < string , boolean > > ( { } ) ;
const [ showColumnsMenu , setShowColumnsMenu ] = useState ( false ) ;
const [ stickyFirstColumn , setStickyFirstColumn ] = useState ( stickyFirstProp ) ;
const [ isScrolled , setIsScrolled ] = useState ( false ) ;
const [ pagination , setPagination ] = useState < PaginationState > ( { pageIndex : 0 , pageSize : defaultPageSize } ) ;
const columnsMenuRef = useRef < HTMLDivElement > ( null ) ;
const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
const rowSelectionState = externalRowSelection !== undefined ? externalRowSelection : internalRowSelection ;
// Extract column ID from ColumnDef
const getColumnId = useCallback ( ( c : ColumnDef < TData , TValue > ) : string = > {
if ( "id" in c && typeof c . id === "string" ) { return c . id ; }
if ( "accessorKey" in c && typeof c . accessorKey === "string" ) { return c . accessorKey ; }
return "" ;
} , [ ] ) ;
// Column order for DnD — include "select" at start and "actions" at end
// so TanStack doesn't push them to the end of the table
const buildColumnOrder = useCallback (
( dataCols : ColumnDef < TData , TValue > [ ] ) = > {
const dataOrder = dataCols . map ( getColumnId ) ;
const order : string [ ] = [ ] ;
if ( enableRowSelection ) { order . push ( "select" ) ; }
order . push ( . . . dataOrder ) ;
if ( rowActions ) { order . push ( "actions" ) ; }
return order ;
} ,
[ getColumnId , enableRowSelection , rowActions ] ,
) ;
const [ columnOrder , setColumnOrder ] = useState < string [ ] > ( ( ) = >
buildColumnOrder ( columns ) ,
) ;
// Update column order when columns change
useEffect ( ( ) = > {
setColumnOrder ( buildColumnOrder ( columns ) ) ;
} , [ columns , buildColumnOrder ] ) ;
// DnD sensors
const sensors = useSensors (
useSensor ( PointerSensor , { activationConstraint : { distance : 5 } } ) ,
) ;
const handleDragEnd = useCallback (
( event : DragEndEvent ) = > {
const { active , over } = event ;
if ( over && active . id !== over . id ) {
setColumnOrder ( ( old ) = > {
const oldIndex = old . indexOf ( active . id as string ) ;
const newIndex = old . indexOf ( over . id as string ) ;
const newOrder = arrayMove ( old , oldIndex , newIndex ) ;
onColumnReorder ? . ( newOrder ) ;
return newOrder ;
} ) ;
}
} ,
[ onColumnReorder ] ,
) ;
// Scroll tracking for sticky column shadow
const handleScroll = useCallback ( ( e : React.UIEvent < HTMLDivElement > ) = > {
setIsScrolled ( e . currentTarget . scrollLeft > 0 ) ;
} , [ ] ) ;
// Close columns menu on click outside
useEffect ( ( ) = > {
function handleClick ( e : MouseEvent ) {
if ( columnsMenuRef . current && ! columnsMenuRef . current . contains ( e . target as Node ) ) {
setShowColumnsMenu ( false ) ;
}
}
if ( showColumnsMenu ) {
document . addEventListener ( "mousedown" , handleClick ) ;
return ( ) = > document . removeEventListener ( "mousedown" , handleClick ) ;
}
} , [ showColumnsMenu ] ) ;
// Build selection column
const selectionColumn : ColumnDef < TData > | null = enableRowSelection
? {
id : "select" ,
header : ( { table } ) = > (
< input
type = "checkbox"
checked = { table . getIsAllPageRowsSelected ( ) }
onChange = { table . getToggleAllPageRowsSelectedHandler ( ) }
className = "w-3.5 h-3.5 rounded accent-[var(--color-accent)] cursor-pointer"
/ >
) ,
cell : ( { row } ) = > (
< input
type = "checkbox"
checked = { row . getIsSelected ( ) }
onChange = { row . getToggleSelectedHandler ( ) }
onClick = { ( e ) = > e . stopPropagation ( ) }
className = "w-3.5 h-3.5 rounded accent-[var(--color-accent)] cursor-pointer"
/ >
) ,
size : 40 ,
enableSorting : false ,
enableHiding : false ,
}
: null ;
// Build actions column
const actionsColumn : ColumnDef < TData > | null = rowActions
? {
id : "actions" ,
header : ( ) = > null ,
cell : ( { row } ) = > (
< RowActionsMenu
row = { row . original }
actions = { rowActions ( row . original ) }
/ >
) ,
size : 48 ,
enableSorting : false ,
enableHiding : false ,
}
: null ;
const allColumns = useMemo ( ( ) = > {
const cols : ColumnDef < TData , TValue > [ ] = [ ] ;
if ( selectionColumn ) { cols . push ( selectionColumn as ColumnDef < TData , TValue > ) ; }
cols . push ( . . . columns ) ;
if ( actionsColumn ) { cols . push ( actionsColumn as ColumnDef < TData , TValue > ) ; }
return cols ;
} , [ columns , selectionColumn , actionsColumn ] ) ;
2026-02-19 14:59:34 -08:00
// Server-side pagination state derived from props
const serverPaginationState = serverPagination
? { pageIndex : serverPagination.page - 1 , pageSize : serverPagination.pageSize }
: undefined ;
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
const table = useReactTable ( {
data ,
columns : allColumns ,
state : {
sorting ,
globalFilter ,
columnFilters ,
columnVisibility ,
rowSelection : rowSelectionState ,
columnOrder : enableColumnReordering ? columnOrder : undefined ,
2026-02-19 14:59:34 -08:00
pagination : serverPaginationState ? ? pagination ,
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
} ,
onSortingChange : setSorting ,
onGlobalFilterChange : setGlobalFilter ,
onColumnFiltersChange : setColumnFilters ,
onColumnVisibilityChange : setColumnVisibility ,
onRowSelectionChange : ( updater ) = > {
if ( onRowSelectionChange ) {
onRowSelectionChange ( updater ) ;
} else {
setInternalRowSelection ( updater ) ;
}
} ,
2026-02-19 14:59:34 -08:00
onPaginationChange : serverPagination
? ( updater ) = > {
const newVal = typeof updater === "function"
? updater ( serverPaginationState ! )
: updater ;
if ( newVal . pageSize !== serverPagination . pageSize ) {
serverPagination . onPageSizeChange ( newVal . pageSize ) ;
} else if ( newVal . pageIndex !== serverPagination . page - 1 ) {
serverPagination . onPageChange ( newVal . pageIndex + 1 ) ;
}
}
: setPagination ,
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
getCoreRowModel : getCoreRowModel ( ) ,
getSortedRowModel : enableSorting ? getSortedRowModel ( ) : undefined ,
2026-02-19 14:59:34 -08:00
getFilteredRowModel : serverPagination ? undefined : getFilteredRowModel ( ) ,
getPaginationRowModel : serverPagination ? undefined : getPaginationRowModel ( ) ,
. . . ( serverPagination ? {
manualPagination : true ,
pageCount : Math.ceil ( serverPagination . totalCount / serverPagination . pageSize ) ,
} : { } ) ,
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
enableRowSelection ,
enableSorting ,
globalFilterFn : fuzzyFilter ,
columnResizeMode : "onChange" ,
} ) ;
const selectedCount = Object . keys ( rowSelectionState ) . filter ( ( k ) = > rowSelectionState [ k ] ) . length ;
const visibleColumns = table . getVisibleFlatColumns ( ) . filter ( ( c ) = > c . id !== "select" && c . id !== "actions" ) ;
// ─── Render ───
return (
< div className = "flex flex-col h-full" >
{ /* Toolbar */ }
< div
className = "flex items-center gap-2 px-4 py-2.5 flex-shrink-0 flex-wrap"
style = { { borderBottom : "1px solid var(--color-border)" } }
>
{ title && (
< div className = "flex items-center gap-2 mr-2" >
{ titleIcon }
< span className = "text-sm font-semibold" style = { { color : "var(--color-text)" } } >
{ title }
< / span >
< / div >
) }
{ /* Search */ }
{ enableGlobalFilter && (
< div className = "relative flex-1 min-w-[180px] max-w-[320px]" >
< svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" className = "absolute left-3 top-1/2 -translate-y-1/2" style = { { color : "var(--color-text-muted)" } } >
< circle cx = "11" cy = "11" r = "8" / > < path d = "m21 21-4.3-4.3" / >
< / svg >
< input
type = "text"
value = { globalFilter }
2026-02-19 14:59:34 -08:00
onChange = { ( e ) = > {
setGlobalFilter ( e . target . value ) ;
onServerSearch ? . ( e . target . value ) ;
} }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
placeholder = { searchPlaceholder }
className = "w-full pl-9 pr-3 py-1.5 text-xs rounded-full outline-none"
style = { {
background : "var(--color-surface-hover)" ,
color : "var(--color-text)" ,
border : "1px solid var(--color-border)" ,
} }
/ >
{ globalFilter && (
< button
type = "button"
2026-02-19 14:59:34 -08:00
onClick = { ( ) = > { setGlobalFilter ( "" ) ; onServerSearch ? . ( "" ) ; } }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
className = "absolute right-2.5 top-1/2 -translate-y-1/2"
style = { { color : "var(--color-text-muted)" } }
>
< svg width = "12" height = "12" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" > < path d = "M18 6 6 18" / > < path d = "m6 6 12 12" / > < / svg >
< / button >
) }
< / div >
) }
{ /* Bulk actions */ }
{ selectedCount > 0 && bulkActions && (
< div className = "flex items-center gap-2" >
< span className = "text-xs font-medium" style = { { color : "var(--color-text-muted)" } } >
{ selectedCount } selected
< / span >
{ bulkActions }
< / div >
) }
< div className = "flex-1" / >
{ toolbarExtra }
{ /* Refresh */ }
{ onRefresh && (
< button
type = "button"
onClick = { onRefresh }
className = "p-1.5 rounded-lg"
style = { { color : "var(--color-text-muted)" } }
title = "Refresh"
>
< svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" >
< path d = "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" / > < path d = "M21 3v5h-5" / > < path d = "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" / > < path d = "M3 21v-5h5" / >
< / svg >
< / button >
) }
{ /* Columns menu */ }
< div className = "relative" ref = { columnsMenuRef } >
< button
type = "button"
onClick = { ( ) = > setShowColumnsMenu ( ( v ) = > ! v ) }
className = "flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-medium"
style = { {
color : "var(--color-text-muted)" ,
border : "1px solid var(--color-border)" ,
background : showColumnsMenu ? "var(--color-surface-hover)" : "transparent" ,
} }
>
< svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" >
< rect width = "18" height = "18" x = "3" y = "3" rx = "2" / > < path d = "M9 3v18" / > < path d = "M15 3v18" / >
< / svg >
Columns
< / button >
{ showColumnsMenu && (
< div
className = "absolute right-0 top-full mt-1 z-50 min-w-[200px] rounded-xl overflow-hidden py-1"
style = { {
background : "var(--color-surface)" ,
border : "1px solid var(--color-border)" ,
boxShadow : "var(--shadow-lg)" ,
} }
>
{ /* Sticky first col toggle */ }
< label
className = "flex items-center gap-2 px-3 py-2 text-xs cursor-pointer"
style = { { color : "var(--color-text-muted)" , borderBottom : "1px solid var(--color-border)" } }
>
< input
type = "checkbox"
checked = { stickyFirstColumn }
onChange = { ( ) = > setStickyFirstColumn ( ( v ) = > ! v ) }
className = "w-3.5 h-3.5 rounded accent-[var(--color-accent)]"
/ >
Freeze first column
< / label >
{ visibleColumns . length === 0 ? (
< div className = "px-3 py-2 text-xs" style = { { color : "var(--color-text-muted)" } } >
No toggleable columns
< / div >
) : (
table . getAllLeafColumns ( )
. filter ( ( c ) = > c . id !== "select" && c . id !== "actions" && c . getCanHide ( ) )
. map ( ( column ) = > (
< label
key = { column . id }
className = "flex items-center gap-2 px-3 py-1.5 text-xs cursor-pointer"
style = { { color : "var(--color-text)" } }
>
< input
type = "checkbox"
checked = { column . getIsVisible ( ) }
onChange = { column . getToggleVisibilityHandler ( ) }
className = "w-3.5 h-3.5 rounded accent-[var(--color-accent)]"
/ >
{ typeof column . columnDef . header === "string"
? column . columnDef . header
2026-02-17 00:36:01 -08:00
: String ( ( column . columnDef . meta as Record < string , string > | undefined ) ? . label ? ? column . id ) }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
< / label >
) )
) }
< / div >
) }
< / div >
{ /* Add button */ }
{ onAdd && (
< button
type = "button"
onClick = { onAdd }
className = "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium"
style = { {
background : "var(--color-accent)" ,
color : "white" ,
} }
>
{ addButtonLabel }
< / button >
) }
< / div >
{ /* Table */ }
< div
ref = { scrollContainerRef }
2026-02-16 00:30:13 -08:00
className = "flex-1 overflow-auto min-w-0"
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
onScroll = { handleScroll }
>
{ loading ? (
< LoadingSkeleton columnCount = { allColumns . length } / >
) : data . length === 0 ? (
< div className = "flex flex-col items-center justify-center py-20 gap-3" >
< svg width = "48" height = "48" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "1.5" style = { { color : "var(--color-text-muted)" , opacity : 0.4 } } >
< rect width = "18" height = "18" x = "3" y = "3" rx = "2" / > < path d = "M3 9h18" / > < path d = "M3 15h18" / > < path d = "M9 3v18" / >
< / svg >
< p className = "text-sm" style = { { color : "var(--color-text-muted)" } } > No data < / p >
< / div >
) : (
< DndContext sensors = { sensors } collisionDetection = { closestCenter } onDragEnd = { handleDragEnd } >
< table className = "w-full text-sm" style = { { borderCollapse : "separate" , borderSpacing : 0 } } >
< thead >
{ table . getHeaderGroups ( ) . map ( ( headerGroup ) = > (
< tr key = { headerGroup . id } >
< SortableContext items = { columnOrder } strategy = { horizontalListSortingStrategy } >
{ headerGroup . headers . map ( ( header , colIdx ) = > {
const isFirstData = colIdx === ( enableRowSelection ? 1 : 0 ) ;
const isSticky = stickyFirstColumn && isFirstData ;
const isSelectCol = header . id === "select" ;
const isActionsCol = header . id === "actions" ;
const canSort = header . column . getCanSort ( ) ;
const headerStyle : React.CSSProperties = {
borderColor : "var(--color-border)" ,
background : "var(--color-surface)" ,
position : "sticky" ,
top : 0 ,
zIndex : isSticky || isSelectCol ? 31 : 30 ,
. . . ( isSticky ? { left : enableRowSelection ? 40 : 0 , boxShadow : isScrolled ? "4px 0 8px -2px rgba(0,0,0,0.08)" : "none" } : { } ) ,
. . . ( isSelectCol ? { left : 0 , position : "sticky" , zIndex : 31 , width : 40 } : { } ) ,
width : header.getSize ( ) ,
} ;
const content = header . isPlaceholder
? null
: flexRender ( header . column . columnDef . header , header . getContext ( ) ) ;
if ( enableColumnReordering && ! isSelectCol && ! isActionsCol ) {
return (
< SortableHeader
key = { header . id }
id = { header . id }
style = { headerStyle }
className = "text-left px-3 py-2.5 font-medium text-xs uppercase tracking-wider whitespace-nowrap border-b select-none"
>
< span
className = { ` flex items-center gap-1 ${ canSort ? "cursor-pointer" : "" } ` }
onClick = { canSort ? header . column . getToggleSortingHandler ( ) : undefined }
>
{ content }
{ canSort && < SortIcon direction = { header . column . getIsSorted ( ) } / > }
< / span >
< / SortableHeader >
) ;
}
return (
< th
key = { header . id }
style = { headerStyle }
className = "text-left px-3 py-2.5 font-medium text-xs uppercase tracking-wider whitespace-nowrap border-b select-none"
>
< span
className = { ` flex items-center gap-1 ${ canSort ? "cursor-pointer" : "" } ` }
onClick = { canSort ? header . column . getToggleSortingHandler ( ) : undefined }
style = { { color : "var(--color-text-muted)" } }
>
{ content }
{ canSort && < SortIcon direction = { header . column . getIsSorted ( ) } / > }
< / span >
< / th >
) ;
} ) }
< / SortableContext >
< / tr >
) ) }
< / thead >
< tbody >
{ table . getRowModel ( ) . rows . map ( ( row , rowIdx ) = > {
const isSelected = row . getIsSelected ( ) ;
return (
< tr
key = { row . id }
className = { ` transition-colors duration-75 ${ onRowClick ? "cursor-pointer" : "" } ` }
style = { {
background : isSelected
? "var(--color-accent-light)"
: rowIdx % 2 === 0
? "transparent"
: "var(--color-surface)" ,
} }
onClick = { ( ) = > onRowClick ? . ( row . original , rowIdx ) }
onMouseEnter = { ( e ) = > {
if ( ! isSelected )
{ ( e . currentTarget as HTMLElement ) . style . background = "var(--color-surface-hover)" ; }
} }
onMouseLeave = { ( e ) = > {
if ( ! isSelected )
{ ( e . currentTarget as HTMLElement ) . style . background =
rowIdx % 2 === 0 ? "transparent" : "var(--color-surface)" ; }
} }
>
{ row . getVisibleCells ( ) . map ( ( cell , colIdx ) = > {
const isFirstData = colIdx === ( enableRowSelection ? 1 : 0 ) ;
const isSticky = stickyFirstColumn && isFirstData ;
const isSelectCol = cell . column . id === "select" ;
const cellStyle : React.CSSProperties = {
borderColor : "var(--color-border)" ,
. . . ( isSticky
? {
position : "sticky" as const ,
left : enableRowSelection ? 40 : 0 ,
zIndex : 20 ,
background : isSelected
? "var(--color-accent-light)"
: "var(--color-bg)" ,
boxShadow : isScrolled ? "4px 0 8px -2px rgba(0,0,0,0.08)" : "none" ,
}
: { } ) ,
. . . ( isSelectCol
? {
position : "sticky" as const ,
left : 0 ,
zIndex : 20 ,
background : isSelected
? "var(--color-accent-light)"
: "var(--color-bg)" ,
width : 40 ,
}
: { } ) ,
} ;
return (
< td
key = { cell . id }
className = "px-3 py-2 border-b whitespace-nowrap"
style = { cellStyle }
>
{ flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
< / td >
) ;
} ) }
< / tr >
) ;
} ) }
< / tbody >
< / table >
< / DndContext >
) }
< / div >
{ /* Pagination footer */ }
{ ! loading && data . length > 0 && (
< div
className = "flex items-center justify-between px-4 py-2 text-xs flex-shrink-0"
style = { {
borderTop : "1px solid var(--color-border)" ,
color : "var(--color-text-muted)" ,
} }
>
< span >
2026-02-19 14:59:34 -08:00
{ serverPagination
? ` Showing ${ ( serverPagination . page - 1 ) * serverPagination . pageSize + 1 } – ${ Math . min ( serverPagination . page * serverPagination . pageSize , serverPagination . totalCount ) } of ${ serverPagination . totalCount } results `
: ` Showing ${ table . getRowModel ( ) . rows . length } of ${ data . length } results ` }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
{ selectedCount > 0 && ` ( ${ selectedCount } selected) ` }
< / span >
< div className = "flex items-center gap-2" >
< span > Rows per page < / span >
< select
2026-02-19 14:59:34 -08:00
value = { serverPagination ? serverPagination.pageSize : pagination.pageSize }
onChange = { ( e ) = > {
const newSize = Number ( e . target . value ) ;
if ( serverPagination ) {
serverPagination . onPageSizeChange ( newSize ) ;
} else {
setPagination ( ( p ) = > ( { . . . p , pageSize : newSize , pageIndex : 0 } ) ) ;
}
} }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
className = "px-1.5 py-0.5 rounded-md text-xs outline-none"
style = { {
background : "var(--color-surface-hover)" ,
color : "var(--color-text)" ,
border : "1px solid var(--color-border)" ,
} }
>
{ [ 20 , 50 , 100 , 250 , 500 ] . map ( ( size ) = > (
< option key = { size } value = { size } > { size } < / option >
) ) }
< / select >
< span >
2026-02-19 14:59:34 -08:00
Page { serverPagination ? serverPagination.page : pagination.pageIndex + 1 } of { table . getPageCount ( ) }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
< / span >
< div className = "flex gap-0.5" >
2026-02-19 14:59:34 -08:00
{ serverPagination ? (
< >
< PaginationButton onClick = { ( ) = > serverPagination . onPageChange ( 1 ) } disabled = { serverPagination . page <= 1 } label = "«" / >
< PaginationButton onClick = { ( ) = > serverPagination . onPageChange ( serverPagination . page - 1 ) } disabled = { serverPagination . page <= 1 } label = "‹" / >
< PaginationButton onClick = { ( ) = > serverPagination . onPageChange ( serverPagination . page + 1 ) } disabled = { serverPagination . page >= Math . ceil ( serverPagination . totalCount / serverPagination . pageSize ) } label = "›" / >
< PaginationButton onClick = { ( ) = > serverPagination . onPageChange ( Math . ceil ( serverPagination . totalCount / serverPagination . pageSize ) ) } disabled = { serverPagination . page >= Math . ceil ( serverPagination . totalCount / serverPagination . pageSize ) } label = "»" / >
< / >
) : (
< >
< PaginationButton onClick = { ( ) = > setPagination ( ( p ) = > ( { . . . p , pageIndex : 0 } ) ) } disabled = { ! table . getCanPreviousPage ( ) } label = "«" / >
< PaginationButton onClick = { ( ) = > table . previousPage ( ) } disabled = { ! table . getCanPreviousPage ( ) } label = "‹" / >
< PaginationButton onClick = { ( ) = > table . nextPage ( ) } disabled = { ! table . getCanNextPage ( ) } label = "›" / >
< PaginationButton onClick = { ( ) = > setPagination ( ( p ) = > ( { . . . p , pageIndex : table.getPageCount ( ) - 1 } ) ) } disabled = { ! table . getCanNextPage ( ) } label = "»" / >
< / >
) }
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
< / div >
< / div >
< / div >
) }
< / div >
) ;
}
/* ─── Sub-components ─── */
function PaginationButton ( { onClick , disabled , label } : { onClick : ( ) = > void ; disabled : boolean ; label : string } ) {
return (
< button
type = "button"
onClick = { onClick }
disabled = { disabled }
className = "w-6 h-6 rounded flex items-center justify-center text-xs disabled:opacity-30"
style = { { color : "var(--color-text-muted)" , border : "1px solid var(--color-border)" } }
// biome-ignore lint: using html entity label
dangerouslySetInnerHTML = { { __html : label } }
/ >
) ;
}
function RowActionsMenu < TData > ( { row , actions } : { row : TData ; actions : RowAction < TData > [ ] } ) {
const [ open , setOpen ] = useState ( false ) ;
const ref = useRef < HTMLDivElement > ( null ) ;
useEffect ( ( ) = > {
function handleClick ( e : MouseEvent ) {
if ( ref . current && ! ref . current . contains ( e . target as Node ) ) {
setOpen ( false ) ;
}
}
if ( open ) {
document . addEventListener ( "mousedown" , handleClick ) ;
return ( ) = > document . removeEventListener ( "mousedown" , handleClick ) ;
}
} , [ open ] ) ;
return (
< div className = "relative" ref = { ref } >
< button
type = "button"
onClick = { ( e ) = > { e . stopPropagation ( ) ; setOpen ( ( v ) = > ! v ) ; } }
className = "p-1 rounded-md"
style = { { color : "var(--color-text-muted)" } }
>
< svg width = "14" height = "14" viewBox = "0 0 24 24" fill = "currentColor" > < circle cx = "12" cy = "5" r = "1.5" / > < circle cx = "12" cy = "12" r = "1.5" / > < circle cx = "12" cy = "19" r = "1.5" / > < / svg >
< / button >
{ open && (
< div
className = "absolute right-0 top-full mt-1 z-50 min-w-[140px] rounded-xl overflow-hidden py-1"
style = { {
background : "var(--color-surface)" ,
border : "1px solid var(--color-border)" ,
boxShadow : "var(--shadow-lg)" ,
} }
>
{ actions . map ( ( action , i ) = > (
< button
key = { i }
type = "button"
onClick = { ( e ) = > {
e . stopPropagation ( ) ;
action . onClick ? . ( row ) ;
setOpen ( false ) ;
} }
className = "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-left"
style = { {
color : action.variant === "destructive" ? "var(--color-error)" : "var(--color-text)" ,
} }
>
{ action . icon }
{ action . label }
< / button >
) ) }
< / div >
) }
< / div >
) ;
}
function LoadingSkeleton ( { columnCount } : { columnCount : number } ) {
return (
< div className = "p-4 space-y-2" >
{ Array . from ( { length : 12 } ) . map ( ( _ , i ) = > (
< div key = { i } className = "flex gap-3" >
2026-02-17 00:38:09 -08:00
{ Array . from ( { length : Math.min ( columnCount , 6 ) } ) . map ( ( _col , j ) = > (
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
< div
key = { j }
className = "h-8 rounded-lg animate-pulse flex-1"
style = { { background : "var(--color-surface-hover)" , animationDelay : ` ${ j * 50 } ms ` } }
/ >
) ) }
< / div >
) ) }
< / div >
) ;
}