Merge remote-tracking branch 'origin/react-window-splitter' into electricsql-run

# Conflicts:
#	apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.$runParam/route.tsx
This commit is contained in:
Matt Aitken
2024-08-29 17:48:24 +01:00
14 changed files with 1557 additions and 69 deletions
+5
View File
@@ -580,6 +580,11 @@ class TaskCoordinator {
return;
}
if (message.version === "v2") {
completeWithoutCheckpoint(true);
return;
}
const { canCheckpoint, willSimulate } = await this.#checkpointer.init();
const willCheckpointAndRestore = canCheckpoint || willSimulate;
@@ -1,7 +1,7 @@
import { cn } from "~/utils/cn";
const inlineCode =
"px-1 py-0.5 rounded border border-charcoal-700 bg-charcoal-800 text-charcoal-200 font-mono";
"px-1 py-0.5 rounded border border-charcoal-700 bg-charcoal-800 text-charcoal-200 font-mono text-wrap";
const variants = {
"extra-extra-small": "text-xxs",
@@ -1,32 +1,32 @@
"use client";
import * as ResizablePrimitive from "react-resizable-panels";
import React from "react";
import { PanelGroup, Panel, PanelResizer } from "react-window-splitter";
import { cn } from "~/utils/cn";
const ResizablePanelGroup = ({
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
const ResizablePanelGroup = ({ className, ...props }: React.ComponentProps<typeof PanelGroup>) => (
<PanelGroup
className={cn("flex w-full data-[panel-group-direction=vertical]:flex-col", className)}
autosaveStrategy="cookie"
{...props}
/>
);
const ResizablePanel = ResizablePrimitive.Panel;
const ResizablePanel = Panel;
const ResizableHandle = ({
withHandle,
withHandle = true,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
}: React.ComponentProps<typeof PanelResizer> & {
withHandle?: boolean;
}) => (
<ResizablePrimitive.PanelResizeHandle
<PanelResizer
className={cn(
"focus-visible:ring-ring group relative flex w-0.75 items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 hover:w-0.75 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-offset-1 [&[data-panel-group-direction=vertical]>div]:rotate-90",
"focus-visible:ring-ring group relative flex w-0.75 items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 hover:w-0.75 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary/50 focus-visible:ring-offset-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
size="3px"
{...props}
>
<div className="absolute left-[0.0625rem] top-0 h-full w-px bg-grid-bright transition group-hover:left-0 group-hover:w-0.75 group-hover:bg-lavender-500" />
@@ -37,7 +37,9 @@ const ResizableHandle = ({
))}
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
</PanelResizer>
);
export { ResizableHandle, ResizablePanel, ResizablePanelGroup };
export type ResizableSnapshot = React.ComponentProps<typeof PanelGroup>["snapshot"];
@@ -6,6 +6,7 @@ import { displayableEnvironment } from "~/models/runtimeEnvironment.server";
import { getAllTaskIdentifiers } from "~/models/task.server";
import { isCancellableRunStatus, isFinalRunStatus } from "~/v3/taskStatus";
import { BasePresenter } from "./basePresenter.server";
import { getAllTaskIdentifiers } from "~/models/task.server";
export type RunListOptions = {
userId?: string;
@@ -104,8 +104,8 @@ export default function Page() {
<PageTitle title="Deployments" />
</NavBar>
<PageBody scrollable={false}>
<ResizablePanelGroup direction="horizontal" className="h-full max-h-full">
<ResizablePanel order={1} minSize={20} defaultSize={60}>
<ResizablePanelGroup orientation="horizontal" className="h-full max-h-full">
<ResizablePanel id="deployments-main" min="100px">
{hasDeployments ? (
<div className="flex flex-col gap-4 p-3">
<Table>
@@ -211,8 +211,8 @@ export default function Page() {
{deploymentParam && (
<>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={20} defaultSize={40}>
<ResizableHandle id="deployments-handle" />
<ResizablePanel id="deployments-inspector" min="100px" max="600px">
<Outlet />
</ResizablePanel>
</>
@@ -177,8 +177,8 @@ export default function Page() {
</PageAccessories>
</NavBar>
<PageBody scrollable={false}>
<ResizablePanelGroup direction="horizontal" className="h-full max-h-full">
<ResizablePanel order={1} minSize={20} defaultSize={60}>
<ResizablePanelGroup orientation="horizontal" className="h-full max-h-full">
<ResizablePanel id="schedules-main" min={"100px"}>
<div className="max-h-full overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
{possibleTasks.length === 0 ? (
<CreateScheduledTaskInstructions />
@@ -250,8 +250,8 @@ export default function Page() {
</ResizablePanel>
{(isShowingNewPane || isShowingSchedule) && (
<>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={20} defaultSize={40}>
<ResizableHandle id="schedules-handle" />
<ResizablePanel id="schedules-inspector" min="100px" default="500px">
<Outlet />
</ResizablePanel>
</>
@@ -180,8 +180,8 @@ function StandardTaskForm({ task, runs }: { task: TestTask["task"]; runs: Standa
onSubmit={(e) => submitForm(e)}
>
<input type="hidden" name="triggerSource" value={"STANDARD"} />
<ResizablePanelGroup direction="horizontal">
<ResizablePanel order={1} minSize={30} defaultSize={60}>
<ResizablePanelGroup orientation="horizontal">
<ResizablePanel id="test-task-main" min="100px" default="60%">
<div className="h-full bg-charcoal-900">
<JSONEditor
defaultValue={defaultJson}
@@ -207,8 +207,8 @@ function StandardTaskForm({ task, runs }: { task: TestTask["task"]; runs: Standa
/>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={20} defaultSize={40}>
<ResizableHandle id="test-task-handle" />
<ResizablePanel id="test-task-inspector" min="100px">
<RecentPayloads
runs={runs}
selectedId={selectedCodeSampleId}
@@ -308,8 +308,8 @@ function ScheduledTaskForm({
{...conform.input(environmentId, { type: "hidden" })}
value={task.environment.id}
/>
<ResizablePanelGroup direction="horizontal">
<ResizablePanel order={1} minSize={30} defaultSize={60}>
<ResizablePanelGroup orientation="horizontal">
<ResizablePanel id="test-task-main" min="100px" default="60%">
<div className="p-3">
<Fieldset>
<InputGroup>
@@ -402,8 +402,8 @@ function ScheduledTaskForm({
</Fieldset>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={20} defaultSize={40}>
<ResizableHandle id="test-task-handle" />
<ResizablePanel id="test-task-inspector" min="100px">
<RecentPayloads
runs={runs}
selectedId={selectedCodeSampleId}
@@ -85,8 +85,8 @@ export default function Page() {
</NavBar>
<PageBody scrollable={false}>
<div className={cn("grid h-full max-h-full grid-cols-1")}>
<ResizablePanelGroup direction="horizontal" className="h-full max-h-full">
<ResizablePanel order={1} minSize={20} defaultSize={30}>
<ResizablePanelGroup orientation="horizontal" className="h-full max-h-full">
<ResizablePanel id="test-selector" min="100px" default="30%">
<div className="grid h-full max-h-full grid-rows-[5.625rem_1fr] overflow-hidden">
<div className="mx-3 flex flex-col gap-1 border-b border-grid-dimmed">
<div className="flex h-10 items-center">
@@ -117,7 +117,7 @@ export default function Page() {
<Spinner />
</div>
) : hasSelectedEnvironment ? (
<div className="grid grid-rows-[2.5rem_1fr] overflow-hidden">
<div className="grid grid-rows-[2.5rem_1fr] overflow-hidden">
<div className="mx-3 flex items-center border-b border-grid-dimmed">
<Header2>Select a task</Header2>
</div>
@@ -135,8 +135,8 @@ export default function Page() {
)}
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel order={2} minSize={30} defaultSize={70}>
<ResizableHandle id="test-handle" />
<ResizablePanel id="test-main" min="225px">
<Outlet key={taskParam} />
</ResizablePanel>
</ResizablePanelGroup>
@@ -157,7 +157,7 @@ function TaskSelector({
return (
<div className="divide-y divide-charcoal-800 overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
<div className="px-2 pb-2">
<div className="p-2">
<Input
placeholder="Search tasks"
variant="medium"
@@ -0,0 +1,24 @@
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "~/components/primitives/Resizable";
export default function Story() {
return (
<div className="h-full">
<ResizablePanelGroup>
<ResizablePanel id={"1-left"} className="bg-sky-500" />
<ResizableHandle id="1-split" />
<ResizablePanel
id={"1-right"}
default="100px"
min="100px"
max="600px"
className="bg-teal-500"
isStaticAtRest
/>
</ResizablePanelGroup>
</div>
);
}
@@ -72,6 +72,10 @@ const stories: Story[] = [
name: "Radio group",
slug: "radio-group",
},
{
name: "Resizable",
slug: "resizable",
},
{
name: "Segemented control",
slug: "segmented-control",
@@ -0,0 +1,39 @@
import { parse } from "cookie";
import { type ResizableSnapshot } from "~/components/primitives/Resizable";
import { logger } from "./logger.server";
export async function getResizableSnapshot(
request: Request,
id: string
): Promise<ResizableSnapshot | undefined> {
try {
const cookieHeader = request.headers.get("Cookie");
if (!cookieHeader) {
return undefined;
}
const cookies = parse(cookieHeader);
const cookieValue = cookies[id];
if (cookieValue) {
try {
const parsedValue = JSON.parse(cookieValue) as any;
if (typeof parsedValue === "object" && "status" in parsedValue) {
return parsedValue as ResizableSnapshot;
}
} catch (parseError) {
logger.error("getResizableSnapshot() error parsing cookie value:", {
parseError,
cookieValue,
});
}
}
return undefined;
} catch (error) {
logger.error("getResizableSnapshot() error:", {
error,
});
return undefined;
}
}
@@ -1,31 +0,0 @@
import { z } from "zod";
const ResizableConfig = z
.object({ layout: z.array(z.number()).optional() })
.default({ layout: undefined });
type ResizableConfig = z.infer<typeof ResizableConfig>;
function getCookieValue(cookieHeader: string | null, cookieName: string): ResizableConfig {
const cookieValue = cookieHeader?.split(`${cookieName}=`)[1]?.split(";")[0];
if (!cookieValue) {
return { layout: undefined };
}
try {
const json = JSON.parse(cookieValue);
return ResizableConfig.parse(json);
} catch (e) {
return { layout: undefined };
}
}
//run page
const runResizableName = "resizable-panels:run";
export async function getResizableRunSettings(request: Request): Promise<ResizableConfig> {
const cookieHeader = request.headers.get("Cookie");
return getCookieValue(cookieHeader, runResizableName);
}
export async function setResizableRunSettings(document: Document, layout: number[]) {
document.cookie = `${runResizableName}=${JSON.stringify({ layout })}`;
}
+3
View File
@@ -108,6 +108,7 @@
"class-variance-authority": "^0.5.2",
"clsx": "^1.2.1",
"compression": "^1.7.4",
"cookie": "^0.6.0",
"cron-parser": "^4.9.0",
"cronstrue": "^2.21.0",
"cross-env": "^7.0.3",
@@ -151,6 +152,7 @@
"react-resizable-panels": "^2.0.9",
"react-stately": "^3.29.1",
"react-use": "^17.4.0",
"react-window-splitter": "^0.4.0",
"recharts": "^2.12.6",
"regression": "^2.0.1",
"remix-auth": "^3.6.0",
@@ -191,6 +193,7 @@
"@total-typescript/ts-reset": "^0.4.2",
"@types/bcryptjs": "^2.4.2",
"@types/compression": "^1.7.2",
"@types/cookie": "^0.6.0",
"@types/eslint": "^8.4.6",
"@types/express": "^4.17.13",
"@types/humanize-duration": "^3.27.1",
+1444 -3
View File
File diff suppressed because it is too large Load Diff