refactor(webapp): remove redundant React fragments (#4683)
## Summary Remove redundant React fragments from dashboard components, leaving their rendered output unchanged while simplifying component trees. Base: [#4682](https://github.com/triggerdotdev/trigger.dev/pull/4682)
This commit is contained in:
@@ -12,21 +12,17 @@ export function FormError({
|
||||
id?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{children && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className={cn("flex items-start gap-0.5", className)}
|
||||
>
|
||||
<ErrorIcon className="h-4 w-4 shrink-0 justify-start text-rose-500" />
|
||||
<Paragraph id={id} variant="extra-small" className="text-rose-500">
|
||||
{children}
|
||||
</Paragraph>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
return children ? (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className={cn("flex items-start gap-0.5", className)}
|
||||
>
|
||||
<ErrorIcon className="h-4 w-4 shrink-0 justify-start text-rose-500" />
|
||||
<Paragraph id={id} variant="extra-small" className="text-rose-500">
|
||||
{children}
|
||||
</Paragraph>
|
||||
</motion.div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export function Icon(props: IconProps) {
|
||||
}
|
||||
|
||||
if (React.isValidElement(props.icon)) {
|
||||
return <>{props.icon}</>;
|
||||
return props.icon;
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -1187,38 +1187,36 @@ function ResultsChart({
|
||||
accessory?: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<ResizablePanelGroup className="overflow-hidden">
|
||||
<ResizablePanel id="chart-results">
|
||||
<div className="h-full overflow-hidden bg-background-bright">
|
||||
<QueryWidget
|
||||
className="border-0"
|
||||
title={
|
||||
<QueryTitle
|
||||
isTitleLoading={isTitleLoading}
|
||||
title={queryTitle}
|
||||
onRename={onRenameTitle}
|
||||
/>
|
||||
}
|
||||
query={query}
|
||||
data={{
|
||||
rows,
|
||||
columns,
|
||||
}}
|
||||
config={{
|
||||
type: "chart",
|
||||
...chartConfig,
|
||||
}}
|
||||
accessory={accessory}
|
||||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="chart-split" />
|
||||
<ResizablePanel id="chart-config" min="50px" default="200px">
|
||||
<ChartConfigPanel columns={columns} config={chartConfig} onChange={onChartConfigChange} />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</>
|
||||
<ResizablePanelGroup className="overflow-hidden">
|
||||
<ResizablePanel id="chart-results">
|
||||
<div className="h-full overflow-hidden bg-background-bright">
|
||||
<QueryWidget
|
||||
className="border-0"
|
||||
title={
|
||||
<QueryTitle
|
||||
isTitleLoading={isTitleLoading}
|
||||
title={queryTitle}
|
||||
onRename={onRenameTitle}
|
||||
/>
|
||||
}
|
||||
query={query}
|
||||
data={{
|
||||
rows,
|
||||
columns,
|
||||
}}
|
||||
config={{
|
||||
type: "chart",
|
||||
...chartConfig,
|
||||
}}
|
||||
accessory={accessory}
|
||||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="chart-split" />
|
||||
<ResizablePanel id="chart-config" min="50px" default="200px">
|
||||
<ChartConfigPanel columns={columns} config={chartConfig} onChange={onChartConfigChange} />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1266,42 +1264,40 @@ function ResultsBigNumber({
|
||||
}, [columns]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResizablePanelGroup className="overflow-hidden">
|
||||
<ResizablePanel id="bignumber-results">
|
||||
<div className="h-full overflow-hidden bg-background-bright">
|
||||
<QueryWidget
|
||||
className="border-0"
|
||||
title={
|
||||
<QueryTitle
|
||||
isTitleLoading={isTitleLoading}
|
||||
title={queryTitle}
|
||||
onRename={onRenameTitle}
|
||||
/>
|
||||
}
|
||||
query={query}
|
||||
data={{
|
||||
rows,
|
||||
columns,
|
||||
}}
|
||||
config={{
|
||||
type: "bignumber",
|
||||
...bigNumberConfig,
|
||||
}}
|
||||
accessory={accessory}
|
||||
/>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="bignumber-split" />
|
||||
<ResizablePanel id="bignumber-config" min="50px" default="200px">
|
||||
<BigNumberConfigPanel
|
||||
columns={columns}
|
||||
config={bigNumberConfig}
|
||||
onChange={onBigNumberConfigChange}
|
||||
<ResizablePanelGroup className="overflow-hidden">
|
||||
<ResizablePanel id="bignumber-results">
|
||||
<div className="h-full overflow-hidden bg-background-bright">
|
||||
<QueryWidget
|
||||
className="border-0"
|
||||
title={
|
||||
<QueryTitle
|
||||
isTitleLoading={isTitleLoading}
|
||||
title={queryTitle}
|
||||
onRename={onRenameTitle}
|
||||
/>
|
||||
}
|
||||
query={query}
|
||||
data={{
|
||||
rows,
|
||||
columns,
|
||||
}}
|
||||
config={{
|
||||
type: "bignumber",
|
||||
...bigNumberConfig,
|
||||
}}
|
||||
accessory={accessory}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="bignumber-split" />
|
||||
<ResizablePanel id="bignumber-config" min="50px" default="200px">
|
||||
<BigNumberConfigPanel
|
||||
columns={columns}
|
||||
config={bigNumberConfig}
|
||||
onChange={onBigNumberConfigChange}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -594,86 +594,84 @@ export function SpanTimeline({
|
||||
const visibleEvents = events ?? [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="min-w-fit max-w-80">
|
||||
{visibleEvents.map((event, index) => {
|
||||
// Store previous date to compare
|
||||
const prevDate = index === 0 ? null : visibleEvents[index - 1].timestamp;
|
||||
<div className="min-w-fit max-w-80">
|
||||
{visibleEvents.map((event, index) => {
|
||||
// Store previous date to compare
|
||||
const prevDate = index === 0 ? null : visibleEvents[index - 1].timestamp;
|
||||
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
<RunTimelineEvent
|
||||
title={event.name}
|
||||
subtitle={<DateTimeAccurate date={event.timestamp} previousDate={prevDate} />}
|
||||
variant={event.markerVariant}
|
||||
state={state}
|
||||
helpText={event.helpText}
|
||||
style={style}
|
||||
/>
|
||||
<RunTimelineLine
|
||||
title={
|
||||
index === visibleEvents.length - 1
|
||||
? // Last event - calculate duration until span start time
|
||||
formatDuration(event.timestamp, startTime)
|
||||
: // Calculate duration until next event
|
||||
formatDuration(event.timestamp, visibleEvents[index + 1].timestamp)
|
||||
}
|
||||
variant={event.lineVariant}
|
||||
state={state}
|
||||
style={style}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
<RunTimelineEvent
|
||||
title="Started"
|
||||
subtitle={
|
||||
<DateTimeAccurate
|
||||
date={startTime}
|
||||
previousDate={
|
||||
visibleEvents.length > 0 ? visibleEvents[visibleEvents.length - 1].timestamp : null
|
||||
}
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
<RunTimelineEvent
|
||||
title={event.name}
|
||||
subtitle={<DateTimeAccurate date={event.timestamp} previousDate={prevDate} />}
|
||||
variant={event.markerVariant}
|
||||
state={state}
|
||||
helpText={event.helpText}
|
||||
style={style}
|
||||
/>
|
||||
}
|
||||
variant={"start-cap-thick"}
|
||||
<RunTimelineLine
|
||||
title={
|
||||
index === visibleEvents.length - 1
|
||||
? // Last event - calculate duration until span start time
|
||||
formatDuration(event.timestamp, startTime)
|
||||
: // Calculate duration until next event
|
||||
formatDuration(event.timestamp, visibleEvents[index + 1].timestamp)
|
||||
}
|
||||
variant={event.lineVariant}
|
||||
state={state}
|
||||
style={style}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
<RunTimelineEvent
|
||||
title="Started"
|
||||
subtitle={
|
||||
<DateTimeAccurate
|
||||
date={startTime}
|
||||
previousDate={
|
||||
visibleEvents.length > 0 ? visibleEvents[visibleEvents.length - 1].timestamp : null
|
||||
}
|
||||
/>
|
||||
}
|
||||
variant={"start-cap-thick"}
|
||||
state={state}
|
||||
helpText={getHelpTextForEvent("Started")}
|
||||
style={style}
|
||||
/>
|
||||
{state === "inprogress" ? (
|
||||
<RunTimelineLine
|
||||
title={<LiveTimer startTime={startTime} />}
|
||||
state={state}
|
||||
helpText={getHelpTextForEvent("Started")}
|
||||
variant="normal"
|
||||
style={style}
|
||||
/>
|
||||
{state === "inprogress" ? (
|
||||
) : (
|
||||
<>
|
||||
<RunTimelineLine
|
||||
title={<LiveTimer startTime={startTime} />}
|
||||
state={state}
|
||||
title={formatDuration(
|
||||
startTime,
|
||||
new Date(startTime.getTime() + nanosecondsToMilliseconds(duration))
|
||||
)}
|
||||
state={isError ? "error" : undefined}
|
||||
variant="normal"
|
||||
style={style}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<RunTimelineLine
|
||||
title={formatDuration(
|
||||
startTime,
|
||||
new Date(startTime.getTime() + nanosecondsToMilliseconds(duration))
|
||||
)}
|
||||
state={isError ? "error" : undefined}
|
||||
variant="normal"
|
||||
style={style}
|
||||
/>
|
||||
<RunTimelineEvent
|
||||
title="Finished"
|
||||
subtitle={
|
||||
<DateTimeAccurate
|
||||
date={new Date(startTime.getTime() + nanosecondsToMilliseconds(duration))}
|
||||
previousDate={startTime}
|
||||
/>
|
||||
}
|
||||
state={isError ? "error" : undefined}
|
||||
variant="end-cap-thick"
|
||||
helpText={getHelpTextForEvent("Finished")}
|
||||
style={style}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
<RunTimelineEvent
|
||||
title="Finished"
|
||||
subtitle={
|
||||
<DateTimeAccurate
|
||||
date={new Date(startTime.getTime() + nanosecondsToMilliseconds(duration))}
|
||||
previousDate={startTime}
|
||||
/>
|
||||
}
|
||||
state={isError ? "error" : undefined}
|
||||
variant="end-cap-thick"
|
||||
helpText={getHelpTextForEvent("Finished")}
|
||||
style={style}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,9 +87,7 @@ export function WaitpointDetailTable({
|
||||
<div>
|
||||
<div className="flex w-full flex-wrap items-center justify-between gap-1">
|
||||
{waitpoint.completedAfter ? (
|
||||
<>
|
||||
<DateTimeAccurate date={waitpoint.completedAfter} />
|
||||
</>
|
||||
<DateTimeAccurate date={waitpoint.completedAfter} />
|
||||
) : (
|
||||
"–"
|
||||
)}
|
||||
@@ -127,9 +125,8 @@ export function WaitpointDetailTable({
|
||||
{waitpoint.completedAt ? <DateTimeAccurate date={waitpoint.completedAt} /> : "–"}
|
||||
</Property.Value>
|
||||
</Property.Item>
|
||||
{waitpoint.status === "WAITING" ? null : waitpoint.status === "TIMED_OUT" ? (
|
||||
<></>
|
||||
) : waitpoint.output ? (
|
||||
{waitpoint.status === "WAITING" ? null : waitpoint.status ===
|
||||
"TIMED_OUT" ? null : waitpoint.output ? (
|
||||
<PacketDisplay title="Output" data={waitpoint.output} dataType={waitpoint.outputType} />
|
||||
) : waitpoint.completedAfter ? null : (
|
||||
"Completed with no output"
|
||||
|
||||
+14
-16
@@ -18,22 +18,20 @@ export default function Project() {
|
||||
const isImpersonating = useIsImpersonating();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-[auto_1fr] overflow-hidden">
|
||||
<DevPresenceProvider enabled={environment.type === "DEVELOPMENT"}>
|
||||
<SideMenu
|
||||
user={{ ...user, isImpersonating }}
|
||||
project={project}
|
||||
environment={environment}
|
||||
organization={organization}
|
||||
organizations={organizations}
|
||||
/>
|
||||
<MainBody>
|
||||
<Outlet />
|
||||
</MainBody>
|
||||
</DevPresenceProvider>
|
||||
</div>
|
||||
</>
|
||||
<div className="grid grid-cols-[auto_1fr] overflow-hidden">
|
||||
<DevPresenceProvider enabled={environment.type === "DEVELOPMENT"}>
|
||||
<SideMenu
|
||||
user={{ ...user, isImpersonating }}
|
||||
project={project}
|
||||
environment={environment}
|
||||
organization={organization}
|
||||
organizations={organizations}
|
||||
/>
|
||||
<MainBody>
|
||||
<Outlet />
|
||||
</MainBody>
|
||||
</DevPresenceProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,19 +160,17 @@ function Statuses() {
|
||||
filter={(item, search) => item.title.toLowerCase().includes(search.toLowerCase())}
|
||||
shortcut={{ key: "s" }}
|
||||
>
|
||||
{(matches, { shortcutsEnabled }) => (
|
||||
<>
|
||||
{matches?.map((item, index) => (
|
||||
<SelectItem
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
shortcut={shortcutFromIndex(index, { shortcutsEnabled })}
|
||||
>
|
||||
<TaskRunStatusCombo status={item.value} iconClassName="animate-none" />
|
||||
</SelectItem>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{(matches, { shortcutsEnabled }) =>
|
||||
matches?.map((item, index) => (
|
||||
<SelectItem
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
shortcut={shortcutFromIndex(index, { shortcutsEnabled })}
|
||||
>
|
||||
<TaskRunStatusCombo status={item.value} iconClassName="animate-none" />
|
||||
</SelectItem>
|
||||
))
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user