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:
@@ -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={{
|
||||
|
||||
+1
-1
@@ -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)}
|
||||
|
||||
+6
-1
@@ -537,7 +537,12 @@ function ErrorGroupDetail({
|
||||
>
|
||||
Bulk replay…
|
||||
</PermissionLink>
|
||||
<RunsDisplayOptions />
|
||||
<RunsDisplayOptions
|
||||
sampleFilters={{
|
||||
errorId: ErrorId.toFriendlyId(fingerprint),
|
||||
rootOnly: "false",
|
||||
}}
|
||||
/>
|
||||
<ListPagination list={runList} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
+1
-1
@@ -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)}
|
||||
|
||||
+1
-1
@@ -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)}
|
||||
|
||||
+1
@@ -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={{
|
||||
|
||||
+1
@@ -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 };
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user