mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(tables): right-align run/stop in embedded toolbar; workflow cells format like normal cells (#4806)
* fix(tables): right-align run/stop in the embedded table toolbar Add a right-aligned `trailing` slot to ResourceOptionsBar and move the embedded mothership table's run/stop control into it, so Filter + Sort stay left-aligned and run/stop sits opposite on the right. No-op for the search-bearing consumers (logs, resource list), which don't pass `trailing`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): workflow-output cells format values like normal cells Workflow-output columns short-circuited in resolveCellRender and rendered their value as plain text, so a sim-resource URL / external URL / JSON / date produced by a workflow never got the chip, favicon link, or typed formatting a normal cell gets. Factor value formatting into a shared `resolveValueKind` helper used by both the workflow-value branch and the plain-cell branch; the workflow branch keeps the typewriter reveal for plain streaming text via a `typewriter` flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tables): detect resource/URL links on workflow output regardless of column type Workflow output columns default to `json` (columnTypeForLeaf), so routing their values through the type-based formatter (a) gated chip/URL promotion behind `column.type === 'string'` — a URL produced by a json-typed output never became a chip — and (b) JSON.stringify'd plain string values, adding quotes and losing the typewriter reveal. Detect links (sim-resource chip / favicon URL) on the value string directly for workflow outputs, falling back to the plain `value` kind; plain cells keep the type-based formatting. Addresses Greptile P2 on #4806. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
640b7e12c5
commit
b4787dd173
+13
-1
@@ -73,6 +73,10 @@ interface ResourceOptionsBarProps {
|
||||
filterActive?: boolean
|
||||
filterTags?: FilterTag[]
|
||||
extras?: ReactNode
|
||||
/** Right-aligned slot. Unlike `extras` (which sits with the left controls),
|
||||
* `trailing` is pushed to the far right via `justify-between` — used for the
|
||||
* table's run/stop control opposite the left-aligned filter/sort. */
|
||||
trailing?: ReactNode
|
||||
}
|
||||
|
||||
export const ResourceOptionsBar = memo(function ResourceOptionsBar({
|
||||
@@ -83,9 +87,16 @@ export const ResourceOptionsBar = memo(function ResourceOptionsBar({
|
||||
filterActive,
|
||||
filterTags,
|
||||
extras,
|
||||
trailing,
|
||||
}: ResourceOptionsBarProps) {
|
||||
const hasContent =
|
||||
search || sort || filter || onFilterToggle || extras || (filterTags && filterTags.length > 0)
|
||||
search ||
|
||||
sort ||
|
||||
filter ||
|
||||
onFilterToggle ||
|
||||
extras ||
|
||||
trailing ||
|
||||
(filterTags && filterTags.length > 0)
|
||||
if (!hasContent) return null
|
||||
|
||||
return (
|
||||
@@ -143,6 +154,7 @@ export const ResourceOptionsBar = memo(function ResourceOptionsBar({
|
||||
) : null}
|
||||
{sort && <SortDropdown config={sort} />}
|
||||
</div>
|
||||
{trailing && <div className='flex shrink-0 items-center gap-1.5'>{trailing}</div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
+47
-16
@@ -77,7 +77,13 @@ export function resolveCellRender({
|
||||
// Value wins over pending-upstream: a finished column stays finished even
|
||||
// while other blocks in the group are still running. An empty string is not
|
||||
// a value — it falls through so a completed enrichment can show "Not found".
|
||||
if (!isEmpty) return { kind: 'value', text: stringifyValue(value) }
|
||||
// A value that's wholly a resource/URL string renders as a chip/link (any
|
||||
// column type — workflow output is free-form); otherwise the plain `value`
|
||||
// kind keeps the typewriter reveal for streaming text.
|
||||
if (!isEmpty) {
|
||||
const text = stringifyValue(value)
|
||||
return resolveLinkKind(text, currentWorkspaceId) ?? { kind: 'value', text }
|
||||
}
|
||||
|
||||
if (inFlight && !(groupHasBlockErrors && !blockRunning)) {
|
||||
// A `pending` cell whose jobId starts with `paused-` is mid-pause
|
||||
@@ -109,21 +115,7 @@ export function resolveCellRender({
|
||||
if (column.type === 'date') return { kind: 'date', text: String(value) }
|
||||
if (column.type === 'string') {
|
||||
const text = stringifyValue(value)
|
||||
if (currentWorkspaceId) {
|
||||
const resource = extractSimResourceInfo(text)
|
||||
if (resource && resource.workspaceId === currentWorkspaceId) {
|
||||
return {
|
||||
kind: 'sim-resource',
|
||||
workspaceId: resource.workspaceId,
|
||||
resourceType: resource.resourceType,
|
||||
resourceId: resource.resourceId,
|
||||
href: resource.href,
|
||||
}
|
||||
}
|
||||
}
|
||||
const urlInfo = extractUrlInfo(text)
|
||||
if (urlInfo) return { kind: 'url', text, href: urlInfo.href, domain: urlInfo.domain }
|
||||
return { kind: 'text', text }
|
||||
return resolveLinkKind(text, currentWorkspaceId) ?? { kind: 'text', text }
|
||||
}
|
||||
return { kind: 'text', text: stringifyValue(value) }
|
||||
}
|
||||
@@ -134,6 +126,45 @@ function stringifyValue(value: unknown): string {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
|
||||
/** Returns a `sim-resource` cell kind when `text` is a URL pointing to a
|
||||
* resource in the current workspace, else null. Shared by plain string cells
|
||||
* and workflow-output value cells so both surface in-workspace resource links
|
||||
* as tagged chips. */
|
||||
function resolveSimResourceKind(
|
||||
text: string,
|
||||
currentWorkspaceId: string | undefined
|
||||
): Extract<CellRenderKind, { kind: 'sim-resource' }> | null {
|
||||
if (!currentWorkspaceId) return null
|
||||
const resource = extractSimResourceInfo(text)
|
||||
if (!resource || resource.workspaceId !== currentWorkspaceId) return null
|
||||
return {
|
||||
kind: 'sim-resource',
|
||||
workspaceId: resource.workspaceId,
|
||||
resourceType: resource.resourceType,
|
||||
resourceId: resource.resourceId,
|
||||
href: resource.href,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Promotes a cell value that is wholly a resource/URL string to a chip
|
||||
* (in-workspace resource) or a favicon link, else null. Shared by plain string
|
||||
* cells and workflow-output value cells. Workflow outputs apply this regardless
|
||||
* of `column.type` (their type defaults to `json`, so gating on `string` would
|
||||
* miss URL outputs); a stringified object never matches the whole-string URL
|
||||
* check, so it stays JSON/text.
|
||||
*/
|
||||
function resolveLinkKind(
|
||||
text: string,
|
||||
currentWorkspaceId: string | undefined
|
||||
): Extract<CellRenderKind, { kind: 'sim-resource' } | { kind: 'url' }> | null {
|
||||
const simKind = resolveSimResourceKind(text, currentWorkspaceId)
|
||||
if (simKind) return simKind
|
||||
const urlInfo = extractUrlInfo(text)
|
||||
if (urlInfo) return { kind: 'url', text, href: urlInfo.href, domain: urlInfo.domain }
|
||||
return null
|
||||
}
|
||||
|
||||
const BARE_DOMAIN_RE = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/
|
||||
|
||||
function extractUrlInfo(text: string): { href: string; domain: string } | null {
|
||||
|
||||
@@ -478,14 +478,14 @@ export function Table({
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{/* Sort + filter render in both modes. In embedded (mothership) mode there's
|
||||
no ResourceHeader, so the run/stop control rides in the options bar's
|
||||
`extras` slot — keeping the bar populated whether or not a run is live. */}
|
||||
{/* Sort + filter render in both modes (left-aligned). In embedded (mothership)
|
||||
mode there's no ResourceHeader, so the run/stop control rides in the options
|
||||
bar's right-aligned `trailing` slot — opposite the left-aligned filter/sort. */}
|
||||
<ResourceOptionsBar
|
||||
sort={sortConfig}
|
||||
onFilterToggle={() => setFilterOpen((prev) => !prev)}
|
||||
filterActive={filterOpen || !!queryOptions.filter}
|
||||
extras={
|
||||
trailing={
|
||||
embedded && selection.totalRunning > 0 ? (
|
||||
<RunStatusControl
|
||||
running={selection.totalRunning}
|
||||
|
||||
Reference in New Issue
Block a user