Skip to content

Updates to the pricing page #2067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
34 changes: 34 additions & 0 deletions apps/webapp/app/assets/icons/MoveToTopIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export function MoveToTopIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_17186_103975)">
<path
d="M12 21L12 9"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3 3L21 3"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.5 11.5L12 7L7.5 11.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_17186_103975">
<rect width="24" height="24" fill="currentColor" />
</clipPath>
</defs>
</svg>
);
}
41 changes: 41 additions & 0 deletions apps/webapp/app/assets/icons/MoveUpIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export function MoveUpIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_17177_110851)">
<path
d="M12 21L12 13"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3 3L21 3"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3 7L21 7"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M16.5 15.5L12 11L7.5 15.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_17177_110851">
<rect width="24" height="24" fill="currentColor" />
</clipPath>
</defs>
</svg>
);
}
6 changes: 6 additions & 0 deletions apps/webapp/app/components/Shortcuts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ function ShortcutContent() {
</Paragraph>
<ShortcutKey shortcut={{ key: "9" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Jump to root run">
<ShortcutKey shortcut={{ key: "t" }} variant="medium/bright" />
</Shortcut>
<Shortcut name="Jump to parent run">
<ShortcutKey shortcut={{ key: "p" }} variant="medium/bright" />
</Shortcut>
</div>
<div className="space-y-3">
<Header3>Schedules page</Header3>
Expand Down
58 changes: 53 additions & 5 deletions apps/webapp/app/components/primitives/TextLink.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Link } from "@remix-run/react";
import { cn } from "~/utils/cn";
import { Icon, type RenderIcon } from "./Icon";
import { useRef } from "react";
import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
import { ShortcutKey } from "./ShortcutKey";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./Tooltip";

const variations = {
primary:
Expand All @@ -17,6 +21,9 @@ type TextLinkProps = {
trailingIconClassName?: string;
variant?: keyof typeof variations;
children: React.ReactNode;
shortcut?: ShortcutDefinition;
hideShortcutKey?: boolean;
tooltip?: React.ReactNode;
} & React.AnchorHTMLAttributes<HTMLAnchorElement>;

export function TextLink({
Expand All @@ -27,20 +34,61 @@ export function TextLink({
trailingIcon,
trailingIconClassName,
variant = "primary",
shortcut,
hideShortcutKey,
tooltip,
...props
}: TextLinkProps) {
const innerRef = useRef<HTMLAnchorElement>(null);
const classes = variations[variant];
return to ? (
<Link to={to} className={cn(classes, className)} {...props}>

if (shortcut) {
useShortcutKeys({
shortcut: shortcut,
action: () => {
if (innerRef.current) {
innerRef.current.click();
}
},
});
}
Comment on lines +45 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid conditional hook calls – they break the Rules of Hooks

useShortcutKeys is invoked only when shortcut is truthy.
If the component first renders with shortcut={undefined} and later re-renders with a shortcut the hook order will change, throwing Invariant Violation: Rendered fewer hooks than expected.

Unconditionally call the hook and gate the feature inside the hook’s own options instead:

- if (shortcut) {
-   useShortcutKeys({
-     shortcut: shortcut,
-     action: () => {
-       if (innerRef.current) {
-         innerRef.current.click();
-       }
-     },
-   });
- }
+ useShortcutKeys(
+   shortcut
+     ? {
+         shortcut,
+         action: () => innerRef.current?.click(),
+       }
+     : undefined // hook still called, but no-op when undefined
+ );
🤖 Prompt for AI Agents
In apps/webapp/app/components/primitives/TextLink.tsx around lines 45 to 54, the
hook useShortcutKeys is called conditionally based on the shortcut prop, which
violates the Rules of Hooks and can cause runtime errors. To fix this, call
useShortcutKeys unconditionally every render and move the conditional logic
inside the hook's options or implementation so that the shortcut feature is
enabled or disabled internally without changing the hook call order.


const renderShortcutKey = () =>
shortcut &&
!hideShortcutKey && <ShortcutKey className="ml-1.5" shortcut={shortcut} variant="small" />;

const linkContent = (
<>
{children}{" "}
{trailingIcon && <Icon icon={trailingIcon} className={cn("size-4", trailingIconClassName)} />}
{shortcut && !tooltip && renderShortcutKey()}
</>
);

const linkElement = to ? (
<Link ref={innerRef} to={to} className={cn(classes, className)} {...props}>
{linkContent}
</Link>
) : href ? (
<a href={href} className={cn(classes, className)} {...props}>
{children}{" "}
{trailingIcon && <Icon icon={trailingIcon} className={cn("size-4", trailingIconClassName)} />}
<a ref={innerRef} href={href} className={cn(classes, className)} {...props}>
{linkContent}
</a>
) : (
<span>Need to define a path or href</span>
);

if (tooltip) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>{linkElement}</TooltipTrigger>
<TooltipContent className="text-dimmed flex items-center gap-3 py-1.5 pl-2.5 pr-3 text-xs">
{tooltip} {shortcut && renderShortcutKey()}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

return linkElement;
}
11 changes: 9 additions & 2 deletions apps/webapp/app/presenters/v3/RunPresenter.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ export class RunPresenter {
createdAt: true,
},
},
parentTaskRun: {
select: {
friendlyId: true,
taskIdentifier: true,
spanId: true,
createdAt: true,
},
},
runtimeEnvironment: {
select: {
id: true,
Expand Down Expand Up @@ -109,6 +117,7 @@ export class RunPresenter {
completedAt: run.completedAt,
logsDeletedAt: showDeletedLogs ? null : run.logsDeletedAt,
rootTaskRun: run.rootTaskRun,
parentTaskRun: run.parentTaskRun,
environment: {
id: run.runtimeEnvironment.id,
organizationId: run.runtimeEnvironment.organizationId,
Expand Down Expand Up @@ -199,8 +208,6 @@ export class RunPresenter {
trace: {
rootSpanStatus,
events: events,
parentRunFriendlyId:
tree?.id === traceSummary.rootSpan.id ? undefined : traceSummary.rootSpan.runId,
duration: totalDuration,
rootStartedAt: tree?.data.startTime,
startedAt: run.startedAt,
Expand Down
Loading