Skip to content

Commit 81f2353

Browse files
committed
feat(webapp): Disable animations for finished spans in Runs table, improve UI/UX of adjacent Runs feature
1 parent 187286f commit 81f2353

File tree

2 files changed

+56
-20
lines changed
  • apps/webapp/app/routes
    • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam
    • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index

2 files changed

+56
-20
lines changed

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,10 @@ const resizableSettings = {
140140
type TraceEvent = NonNullable<SerializeFrom<typeof loader>["trace"]>["events"][0];
141141

142142
type RunsListNavigation = {
143-
runs: Array<{ friendlyId: string }>;
143+
runs: Array<{ friendlyId: string; spanId: string }>;
144144
pagination: { next?: string; previous?: string };
145-
prevPageLastRun?: { friendlyId: string; cursor: string };
146-
nextPageFirstRun?: { friendlyId: string; cursor: string };
145+
prevPageLastRun?: { friendlyId: string; spanId: string; cursor: string };
146+
nextPageFirstRun?: { friendlyId: string; spanId: string; cursor: string };
147147
};
148148

149149
async function getRunsListFromTableState({
@@ -204,6 +204,7 @@ async function getRunsListFromTableState({
204204
if (prevPageResult.runs.length > 0) {
205205
runsList.prevPageLastRun = {
206206
friendlyId: prevPageResult.runs[0].friendlyId,
207+
spanId: prevPageResult.runs[0].spanId,
207208
cursor: currentPageResult.pagination.previous,
208209
};
209210
}
@@ -222,6 +223,7 @@ async function getRunsListFromTableState({
222223
if (nextPageResult.runs.length > 0) {
223224
runsList.nextPageFirstRun = {
224225
friendlyId: nextPageResult.runs[0].friendlyId,
226+
spanId: nextPageResult.runs[0].spanId,
225227
cursor: currentPageResult.pagination.next,
226228
};
227229
}
@@ -296,7 +298,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
296298
type LoaderData = SerializeFrom<typeof loader>;
297299

298300
export default function Page() {
299-
const { run, trace, resizable, maximumLiveReloadingSetting, runsList } = useLoaderData<typeof loader>();
301+
const { run, trace, maximumLiveReloadingSetting, runsList } = useLoaderData<typeof loader>();
300302
const organization = useOrganization();
301303
const project = useProject();
302304
const environment = useEnvironment();
@@ -308,8 +310,10 @@ export default function Page() {
308310
const tableState = decodeURIComponent(value("tableState") ?? "");
309311
const tableStateSearchParams = new URLSearchParams(tableState);
310312
const filters = getRunFiltersFromSearchParams(tableStateSearchParams);
313+
const tabParam = value("tab") ?? undefined;
314+
const spanParam = value("span") ?? undefined;
311315

312-
const [previousRunPath, nextRunPath] = useAdjacentRunPaths({organization, project, environment, tableState, run, runsList});
316+
const [previousRunPath, nextRunPath] = useAdjacentRunPaths({organization, project, environment, tableState, run, runsList, tabParam, useSpan: !!spanParam});
313317

314318
return (
315319
<>
@@ -940,7 +944,6 @@ function TimelineView({
940944
scale,
941945
rootSpanStatus,
942946
rootStartedAt,
943-
parentRef,
944947
timelineScrollRef,
945948
virtualizer,
946949
events,
@@ -1127,7 +1130,8 @@ function TimelineView({
11271130
"-ml-[0.5px] h-[0.5625rem] w-px rounded-none",
11281131
eventBackgroundClassName(node.data)
11291132
)}
1130-
layoutId={`${node.id}-${event.name}`}
1133+
layoutId={node.data.isPartial ? `${node.id}-${event.name}` : undefined}
1134+
animate={!node.data.isPartial ? false : undefined}
11311135
/>
11321136
)}
11331137
</Timeline.Point>
@@ -1145,7 +1149,8 @@ function TimelineView({
11451149
"-ml-[0.1562rem] size-[0.3125rem] rounded-full border bg-background-bright",
11461150
eventBorderClassName(node.data)
11471151
)}
1148-
layoutId={`${node.id}-${event.name}`}
1152+
layoutId={node.data.isPartial ? `${node.id}-${event.name}` : undefined}
1153+
animate={!node.data.isPartial ? false : undefined}
11491154
/>
11501155
)}
11511156
</Timeline.Point>
@@ -1164,7 +1169,8 @@ function TimelineView({
11641169
>
11651170
<motion.div
11661171
className={cn("h-px w-full", eventBackgroundClassName(node.data))}
1167-
layoutId={`mark-${node.id}`}
1172+
layoutId={node.data.isPartial ? `mark-${node.id}` : undefined}
1173+
animate={!node.data.isPartial ? false : undefined}
11681174
/>
11691175
</Timeline.Span>
11701176
) : null}
@@ -1201,7 +1207,8 @@ function TimelineView({
12011207
"-ml-0.5 size-3 rounded-full border-2 border-background-bright",
12021208
eventBackgroundClassName(node.data)
12031209
)}
1204-
layoutId={node.id}
1210+
layoutId={node.data.isPartial ? node.id : undefined}
1211+
animate={!node.data.isPartial ? false : undefined}
12051212
/>
12061213
)}
12071214
</Timeline.Point>
@@ -1444,7 +1451,8 @@ function SpanWithDuration({
14441451
fadeLeft ? "rounded-r-sm bg-gradient-to-r from-black/50 to-transparent" : "rounded-sm"
14451452
)}
14461453
style={{ backgroundSize: "20px 100%", backgroundRepeat: "no-repeat" }}
1447-
layoutId={node.id}
1454+
layoutId={node.data.isPartial ? node.id : undefined}
1455+
animate={!node.data.isPartial ? false : undefined}
14481456
>
14491457
{node.data.isPartial && (
14501458
<div
@@ -1457,10 +1465,12 @@ function SpanWithDuration({
14571465
"sticky left-0 z-10 transition-opacity group-hover:opacity-100",
14581466
!showDuration && "opacity-0"
14591467
)}
1468+
animate={!node.data.isPartial ? false : undefined}
14601469
>
14611470
<motion.div
14621471
className="whitespace-nowrap rounded-sm px-1 py-0.5 text-xxs text-text-bright text-shadow-custom"
1463-
layout="position"
1472+
layout={node.data.isPartial ? "position" : undefined}
1473+
animate={!node.data.isPartial ? false : undefined}
14641474
>
14651475
{formatDurationMilliseconds(props.durationMs, {
14661476
style: "short",
@@ -1543,12 +1553,11 @@ function KeyboardShortcuts({
15431553
expandAllBelowDepth,
15441554
collapseAllBelowDepth,
15451555
toggleExpandLevel,
1546-
setShowDurations,
15471556
}: {
15481557
expandAllBelowDepth: (depth: number) => void;
15491558
collapseAllBelowDepth: (depth: number) => void;
15501559
toggleExpandLevel: (depth: number) => void;
1551-
setShowDurations: (show: (show: boolean) => boolean) => void;
1560+
setShowDurations?: (show: (show: boolean) => boolean) => void;
15521561
}) {
15531562
return (
15541563
<>
@@ -1666,13 +1675,17 @@ function useAdjacentRunPaths({
16661675
tableState,
16671676
run,
16681677
runsList,
1678+
tabParam,
1679+
useSpan
16691680
}: {
16701681
organization: { slug: string };
16711682
project: { slug: string };
16721683
environment: { slug: string };
16731684
tableState: string;
1674-
run: { friendlyId: string };
1685+
run: { friendlyId: string, spanId: string };
16751686
runsList: RunsListNavigation | null;
1687+
tabParam?: string;
1688+
useSpan?: boolean;
16761689
}): [string | null, string | null] {
16771690
if (!runsList || runsList.runs.length === 0) {
16781691
return [null, null];
@@ -1685,7 +1698,7 @@ function useAdjacentRunPaths({
16851698
}
16861699

16871700
// Determine previous run: use prevPageLastRun if at first position, otherwise use previous run in list
1688-
let previousRun: { friendlyId: string } | null = null;
1701+
let previousRun: { friendlyId: string; spanId: string } | null = null;
16891702
const previousRunTableState = new URLSearchParams(tableState);
16901703
if (currentIndex > 0) {
16911704
previousRun = runsList.runs[currentIndex - 1];
@@ -1697,7 +1710,7 @@ function useAdjacentRunPaths({
16971710
}
16981711

16991712
// Determine next run: use nextPageFirstRun if at last position, otherwise use next run in list
1700-
let nextRun: { friendlyId: string } | null = null;
1713+
let nextRun: { friendlyId: string; spanId: string } | null = null;
17011714
const nextRunTableState = new URLSearchParams(tableState);
17021715
if (currentIndex < runsList.runs.length - 1) {
17031716
nextRun = runsList.runs[currentIndex + 1];
@@ -1710,12 +1723,24 @@ function useAdjacentRunPaths({
17101723

17111724
const previousURLSearchParams = new URLSearchParams();
17121725
previousURLSearchParams.set("tableState", previousRunTableState.toString());
1726+
if (previousRun && useSpan) {
1727+
previousURLSearchParams.set("span", previousRun.spanId);
1728+
}
1729+
if (tabParam && useSpan) {
1730+
previousURLSearchParams.set("tab", tabParam);
1731+
}
17131732
const previousRunPath = previousRun
17141733
? v3RunPath(organization, project, environment, previousRun, previousURLSearchParams)
17151734
: null;
17161735

17171736
const nextURLSearchParams = new URLSearchParams();
17181737
nextURLSearchParams.set("tableState", nextRunTableState.toString());
1738+
if (nextRun && useSpan) {
1739+
nextURLSearchParams.set("span", nextRun.spanId);
1740+
}
1741+
if (tabParam && useSpan) {
1742+
nextURLSearchParams.set("tab", tabParam);
1743+
}
17191744
const nextRunPath = nextRun
17201745
? v3RunPath(organization, project, environment, nextRun, nextURLSearchParams)
17211746
: null;

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs._index/route.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
v3CreateBulkActionPath,
5656
v3ProjectPath,
5757
v3TestPath,
58+
v3TestTaskPath,
5859
} from "~/utils/pathBuilder";
5960
import { ListPagination } from "../../components/ListPagination";
6061
import { CreateBulkActionInspector } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.bulkaction";
@@ -235,7 +236,13 @@ function RunsList({
235236
list.possibleTasks.length === 0 ? (
236237
<CreateFirstTaskInstructions />
237238
) : (
238-
<RunTaskInstructions />
239+
<RunTaskInstructions
240+
task={
241+
list.filters.tasks.length === 1
242+
? list.possibleTasks.find((t) => t.slug === list.filters.tasks[0])
243+
: undefined
244+
}
245+
/>
239246
)
240247
) : (
241248
<div className={cn("grid h-full max-h-full grid-rows-[auto_1fr] overflow-hidden")}>
@@ -339,7 +346,7 @@ function CreateFirstTaskInstructions() {
339346
);
340347
}
341348

342-
function RunTaskInstructions() {
349+
function RunTaskInstructions({ task }: { task?: { slug: string } }) {
343350
const organization = useOrganization();
344351
const project = useProject();
345352
const environment = useEnvironment();
@@ -352,7 +359,11 @@ function RunTaskInstructions() {
352359
Perform a test run with a payload directly from the dashboard.
353360
</Paragraph>
354361
<LinkButton
355-
to={v3TestPath(organization, project, environment)}
362+
to={
363+
task
364+
? v3TestTaskPath(organization, project, environment, { taskIdentifier: task.slug })
365+
: v3TestPath(organization, project, environment)
366+
}
356367
variant="secondary/medium"
357368
LeadingIcon={BeakerIcon}
358369
leadingIconClassName="text-lime-500"

0 commit comments

Comments
 (0)