fix(webapp): scope smart-column sample, suppress columns in embedded tables, fix duplicate import

- Fix oxlint duplicate-import error (merge ListedRun into the existing runsRepository.server import).
- Suppress URL-driven smart columns in embedded run tables that don't hydrate the source fields (schedule inspector, waitpoint, webhook) via an enableSmartColumns={false} prop, so they never render a permanently-empty column.
- Scope the 'Add smart column' sample to the host page's runs: task/scheduled/agent pass their task slug, errors passes the error id (plus rootOnly=false), so the preview shows the shape of the runs the user will actually see instead of arbitrary environment runs.
This commit is contained in:
Eric Allam
2026-08-18 11:22:21 +01:00
parent 58b282631e
commit b996490eb3
11 changed files with 47 additions and 9 deletions
@@ -34,6 +34,12 @@ type AddSmartColumnDialogProps = {
onOpenChange: (open: boolean) => void;
onSubmit: (def: SmartColumnDef) => void;
currentSearch: string;
/**
* Extra filters merged into the sample request so the preview samples the
* runs the host page actually lists (e.g. its task or error), for pages that
* carry that scope in the route path rather than the query string.
*/
sampleFilters?: Record<string, string>;
};
const SOURCE_CARDS: { value: SmartColumnSource; label: string; description: string }[] = [
@@ -55,6 +61,7 @@ export function AddSmartColumnDialog({
onOpenChange,
onSubmit,
currentSearch,
sampleFilters,
}: AddSmartColumnDialogProps) {
const organization = useOrganization();
const project = useProject();
@@ -78,10 +85,17 @@ export function AddSmartColumnDialog({
setSampleIndex(0);
}, [open, editing]);
const sampleFiltersKey = sampleFilters ? JSON.stringify(sampleFilters) : "";
const sampleUrl = useMemo(() => {
const base = `/resources/orgs/${organization.slug}/projects/${project.slug}/env/${environment.slug}/runs/smart-column-sample`;
return currentSearch ? `${base}?${currentSearch.replace(/^\?/, "")}` : base;
}, [organization.slug, project.slug, environment.slug, currentSearch]);
const params = new URLSearchParams(currentSearch.replace(/^\?/, ""));
if (sampleFilters) {
for (const [key, val] of Object.entries(sampleFilters)) params.set(key, val);
}
const qs = params.toString();
return qs ? `${base}?${qs}` : base;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [organization.slug, project.slug, environment.slug, currentSearch, sampleFiltersKey]);
useEffect(() => {
if (open && sample.state === "idle") {
@@ -33,7 +33,11 @@ function keyFor(col: ResolvedColumn): string {
type SmartEditTarget = { index: number; def: SmartColumnDef };
export function RunsDisplayOptions() {
export function RunsDisplayOptions({
sampleFilters,
}: {
sampleFilters?: Record<string, string>;
} = {}) {
const environment = useEnvironment();
const { isManagedCloud } = useFeatures();
const location = useOptimisticLocation();
@@ -201,6 +205,7 @@ export function RunsDisplayOptions() {
}}
onSubmit={submitSmart}
currentSearch={location.search}
sampleFilters={sampleFilters}
/>
</>
);
@@ -91,6 +91,13 @@ type RunsTableProps = {
showTopBorder?: boolean;
stickyHeader?: boolean;
childrenStatusesBasePath?: string;
/**
* Whether URL-driven smart columns render here. Default true; embedded run
* tables whose loader does not hydrate payload/metadata/output (schedule
* inspector, waitpoint, webhook) pass false so they never show a column they
* cannot fill.
*/
enableSmartColumns?: boolean;
/**
* Display-only write:runs flags from the caller's loader. Default true so
* callers that don't pass them (and OSS, where the ability is permissive)
@@ -573,6 +580,7 @@ export function TaskRunsTable({
showTopBorder = true,
stickyHeader = false,
childrenStatusesBasePath,
enableSmartColumns = true,
canCancelRuns = true,
canReplayRuns = true,
}: RunsTableProps) {
@@ -610,7 +618,10 @@ export function TaskRunsTable({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [colsParam, hideParam, scKey, isManagedCloud, isDevelopment]);
const visibleColumns = layout.visible;
const visibleColumns = useMemo(
() => (enableSmartColumns ? layout.visible : layout.visible.filter((c) => c.kind !== "smart")),
[layout, enableSmartColumns]
);
const referencedSources = useMemo(() => visibleSmartSources(visibleColumns), [visibleColumns]);
const sourcesByRunId = useMemo(() => {
@@ -184,6 +184,7 @@ export function ScheduleInspector({
<div className="flex flex-col gap-1">
<Header3 className="pb-1 pl-3">Last 5 runs</Header3>
<TaskRunsTable
enableSmartColumns={false}
total={schedule.runs.length}
hasFilters={false}
filters={{
@@ -339,7 +339,7 @@ export default function Page() {
</Suspense>
) : (
<>
<RunsDisplayOptions />
<RunsDisplayOptions sampleFilters={{ tasks: agent.slug, rootOnly: "false" }} />
<Suspense fallback={null}>
<TypedAwait resolve={runList} errorElement={null}>
{(list) => (list ? <ListPagination list={list} /> : null)}
@@ -537,7 +537,12 @@ function ErrorGroupDetail({
>
Bulk replay
</PermissionLink>
<RunsDisplayOptions />
<RunsDisplayOptions
sampleFilters={{
errorId: ErrorId.toFriendlyId(fingerprint),
rootOnly: "false",
}}
/>
<ListPagination list={runList} />
</div>
)}
@@ -372,7 +372,7 @@ export default function Page() {
onClick={() => showNewRunsRef.current()}
/>
) : null}
<RunsDisplayOptions />
<RunsDisplayOptions sampleFilters={{ tasks: task.slug, rootOnly: "false" }} />
<Suspense fallback={null}>
<TypedAwait resolve={runList} errorElement={null}>
{(list) => (list ? <ListPagination list={list} /> : null)}
@@ -269,7 +269,7 @@ export default function Page() {
onClick={() => showNewRunsRef.current()}
/>
) : null}
<RunsDisplayOptions />
<RunsDisplayOptions sampleFilters={{ tasks: task.slug, rootOnly: "false" }} />
<Suspense fallback={null}>
<TypedAwait resolve={runList} errorElement={null}>
{(list) => (list ? <ListPagination list={list} /> : null)}
@@ -136,6 +136,7 @@ export default function Page() {
<InfoIconTooltip content="These runs have been blocked by this waitpoint." />
</div>
<TaskRunsTable
enableSmartColumns={false}
total={waitpoint.connectedRuns.length}
hasFilters={false}
filters={{
@@ -487,6 +487,7 @@ function WebhookContentArea({
list ? (
<div className="h-full overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
<TaskRunsTable
enableSmartColumns={false}
total={list.runs.length}
hasFilters={list.hasFilters}
filters={list.filters}
@@ -3,6 +3,7 @@ import { ErrorId, RunId } from "@trigger.dev/core/v3/isomorphic";
import {
type FilterRunsOptions,
type IRunsRepository,
type ListedRun,
type ListRunsOptions,
type RunIdsPage,
type RunListInputOptions,
@@ -16,7 +17,6 @@ import { runStore } from "~/v3/runStore.server";
import { type PrismaClientOrTransaction } from "~/db.server";
import { boundedIn, type Prisma } from "@trigger.dev/database";
import { type ListedRun } from "./runsRepository.server";
type RunCursorRow = { runId: string; createdAt: number };
/**