From 690f6932fa8bb69dea91f0056d1c45f193f58536 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 15:00:45 +0100 Subject: [PATCH 01/35] Improvements to the shortcut keys --- .../app/components/primitives/ShortcutKey.tsx | 13 +++++++++++-- .../app/components/stories/Shortcuts.stories.tsx | 4 ++++ apps/webapp/app/hooks/useShortcutKeys.tsx | 13 +++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/apps/webapp/app/components/primitives/ShortcutKey.tsx b/apps/webapp/app/components/primitives/ShortcutKey.tsx index ff5d4f5f70..4e29a73dbc 100644 --- a/apps/webapp/app/components/primitives/ShortcutKey.tsx +++ b/apps/webapp/app/components/primitives/ShortcutKey.tsx @@ -23,7 +23,7 @@ export function ShortcutKey({ shortcut, variant, className }: ShortcutKeyProps) const isMac = platform === "mac"; let relevantShortcut = "mac" in shortcut ? (isMac ? shortcut.mac : shortcut.windows) : shortcut; const modifiers = relevantShortcut.modifiers ?? []; - const character = relevantShortcut.key; + const character = keyString(relevantShortcut.key, isMac); return ( @@ -35,6 +35,15 @@ export function ShortcutKey({ shortcut, variant, className }: ShortcutKeyProps) ); } +function keyString(key: String, isMac: boolean) { + switch (key) { + case "enter": + return isMac ? "↵" : key; + default: + return key; + } +} + function modifierString(modifier: Modifier, isMac: boolean) { switch (modifier) { case "alt": @@ -42,7 +51,7 @@ function modifierString(modifier: Modifier, isMac: boolean) { case "ctrl": return isMac ? "⌃" : "Ctrl+"; case "meta": - return isMac ? "⌘" : "⊞"; + return isMac ? "⌘" : "⊞+"; case "shift": return isMac ? "⇧" : "Shift+"; } diff --git a/apps/webapp/app/components/stories/Shortcuts.stories.tsx b/apps/webapp/app/components/stories/Shortcuts.stories.tsx index a5ed28866a..95e2a63393 100644 --- a/apps/webapp/app/components/stories/Shortcuts.stories.tsx +++ b/apps/webapp/app/components/stories/Shortcuts.stories.tsx @@ -24,6 +24,7 @@ const shortcuts: ShortcutDefinition[] = [ { key: "f", modifiers: ["meta"] }, { key: "k", modifiers: ["meta"] }, { key: "del", modifiers: ["ctrl", "alt"] }, + { key: "enter", modifiers: ["meta"] }, ]; function Collection() { @@ -67,6 +68,9 @@ function Set({ platform }: { platform: "mac" | "windows" }) { + ))} diff --git a/apps/webapp/app/hooks/useShortcutKeys.tsx b/apps/webapp/app/hooks/useShortcutKeys.tsx index ccbebf618e..03103dd3c3 100644 --- a/apps/webapp/app/hooks/useShortcutKeys.tsx +++ b/apps/webapp/app/hooks/useShortcutKeys.tsx @@ -1,8 +1,7 @@ -import { useEffect, useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { useOperatingSystem } from "~/components/primitives/OperatingSystemProvider"; -export type Modifier = "alt" | "ctrl" | "meta" | "shift"; +export type Modifier = "alt" | "ctrl" | "meta" | "shift" | "mod"; export type Shortcut = { key: string; @@ -24,7 +23,13 @@ type useShortcutKeysProps = { export function useShortcutKeys({ shortcut, action, disabled = false }: useShortcutKeysProps) { const keys = createKeysFromShortcut(shortcut); - useHotkeys(keys, action, { enabled: !disabled }); + useHotkeys( + keys, + (event, hotkeysEvent) => { + action(event); + }, + { enabled: !disabled } + ); } function createKeysFromShortcut(shortcut: ShortcutDefinition) { @@ -34,5 +39,5 @@ function createKeysFromShortcut(shortcut: ShortcutDefinition) { const modifiers = relevantShortcut.modifiers; const character = relevantShortcut.key; - return modifiers ? modifiers.map((k) => k).join("+") + "+" : "" + character; + return modifiers ? modifiers.map((k) => k).join("+") + "+" + character : character; } From 2903a54d42c2da1fe9a62d36c826df66c99a7e83 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 15:45:55 +0100 Subject: [PATCH 02/35] Updated code mirror theme to the new dark mode style --- apps/webapp/app/components/code/codeMirrorTheme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/components/code/codeMirrorTheme.ts b/apps/webapp/app/components/code/codeMirrorTheme.ts index 0492b80b93..40b31c31ab 100644 --- a/apps/webapp/app/components/code/codeMirrorTheme.ts +++ b/apps/webapp/app/components/code/codeMirrorTheme.ts @@ -17,7 +17,7 @@ export function darkTheme(): Extension { violet = "#c678dd", darkBackground = "#21252b", highlightBackground = "rgba(71,85,105,0.2)", - background = "#0f172a", + background = "rgba(255,255,255,0)", tooltipBackground = "#353a42", selection = "rgb(71 85 105)", cursor = "#528bff"; From c09ffb4cc6f83ddfdad73fce9486a1b4ef218523 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 15:46:13 +0100 Subject: [PATCH 03/35] Removed the old test page help panel copy --- .../helpContent/HelpContentText.tsx | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/apps/webapp/app/components/helpContent/HelpContentText.tsx b/apps/webapp/app/components/helpContent/HelpContentText.tsx index 8e9a45871c..ce057dae48 100644 --- a/apps/webapp/app/components/helpContent/HelpContentText.tsx +++ b/apps/webapp/app/components/helpContent/HelpContentText.tsx @@ -79,37 +79,6 @@ export function HowToRunYourJob() { ); } -export function HowToRunATest() { - return ( - <> - - - Select the environment you’d like the test to run against. - - - - - - Write your own payload specific to your Job. Some Triggers also provide example payloads - that you can select from. This will populate the code editor below. - - - - - - When you’re happy with the payload, click Run test. - - - Learn more about running tests. - - - ); -} - export function HowToConnectAnIntegration() { return ( <> From 033db9820693ab2f3f0797268fb4afde7a6c9cad Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 15:51:14 +0100 Subject: [PATCH 04/35] WIP new structure for the test page --- .../route.tsx | 238 +++++++++--------- 1 file changed, 124 insertions(+), 114 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index 21917e7bfe..bc75efc0e9 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -1,5 +1,6 @@ import { conform, useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; +import { ArrowTopRightOnSquareIcon, ArrowUpRightIcon } from "@heroicons/react/20/solid"; import { PopoverTrigger } from "@radix-ui/react-popover"; import { Form, useActionData, useSubmit } from "@remix-run/react"; import { ActionFunction, LoaderArgs, json } from "@remix-run/server-runtime"; @@ -8,15 +9,13 @@ import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { z } from "zod"; import { JSONEditor } from "~/components/code/JSONEditor"; import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel"; -import { HowToRunATest } from "~/components/helpContent/HelpContentText"; import { BreadcrumbLink } from "~/components/navigation/NavBar"; import { Button, ButtonContent } from "~/components/primitives/Buttons"; import { Callout } from "~/components/primitives/Callout"; import { FormError } from "~/components/primitives/FormError"; -import { Help, HelpContent, HelpTrigger } from "~/components/primitives/Help"; +import { Header2 } from "~/components/primitives/Headers"; import { Input } from "~/components/primitives/Input"; import { InputGroup } from "~/components/primitives/InputGroup"; -import { Label } from "~/components/primitives/Label"; import { Popover, PopoverContent } from "~/components/primitives/Popover"; import { Select, @@ -26,6 +25,7 @@ import { SelectTrigger, SelectValue, } from "~/components/primitives/Select"; +import { TextLink } from "~/components/primitives/TextLink"; import { redirectBackWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server"; import { TestJobPresenter } from "~/presenters/TestJobPresenter.server"; import { TestJobService } from "~/services/jobs/testJob.server"; @@ -170,120 +170,130 @@ export default function Page() { } return ( - - {(open) => ( -
-
-
submitForm(e)} +
+
+ submitForm(e)} + > + +
+ (currentJson.current = v)} + height="100%" + min-height="100%" + max-height="100%" + autoFocus + placeholder="Use your schema to enter valid JSON or add one of the example payloads then click 'Run test'" + className="h-full" + /> +
+
+
+ -
-
- - - - - {selectedEnvironment && selectedEnvironment.examples.length > 0 && ( - setIsExamplePopoverOpen(open)} - > - - - Insert an example - - - - - {selectedEnvironment?.examples.map((example) => ( - - ))} - - - )} -
- -
- - -
- (currentJson.current = v)} - minHeight="150px" - /> -
-
- - {selectedEnvironment?.hasAuthResolver && ( - - - setCurrentAccountId(e.target.value)} - /> - {accountId.error} - + Learn more about running tests +
+
+ {payload.error ? ( + {payload.error} + ) : ( +
)} -
- {payload.error ? ( - {payload.error} - ) : ( -
- )} - +
- - - -
- )} - + +
+
); } + +// This is the panel that shows if you have an auth resolver + +{ + /* {selectedEnvironment?.hasAuthResolver && ( + + + setCurrentAccountId(e.target.value)} + /> + {accountId.error} + + )} */ +} + +//This is the example popover button + +{ + /*
+ {selectedEnvironment && selectedEnvironment.examples.length > 0 && ( + setIsExamplePopoverOpen(open)} + > + + + Insert an example + + + + + {selectedEnvironment?.examples.map((example) => ( + + ))} + + + )} +
*/ +} From 810507cd36ec738db35508b1b25a7a987c188bf5 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 17:22:56 +0100 Subject: [PATCH 05/35] Added some of the side panel options for examples and account ID --- .../route.tsx | 124 ++++++++---------- 1 file changed, 52 insertions(+), 72 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index bc75efc0e9..5024ea218a 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -173,27 +173,63 @@ export default function Page() {
submitForm(e)} > - -
- (currentJson.current = v)} - height="100%" - min-height="100%" - max-height="100%" - autoFocus - placeholder="Use your schema to enter valid JSON or add one of the example payloads then click 'Run test'" - className="h-full" - /> +
+ +
+ (currentJson.current = v)} + height="100%" + min-height="100%" + max-height="100%" + autoFocus + placeholder="Use your schema to enter valid JSON or add one of the example payloads then click 'Run test'" + className="h-full" + /> +
+
+
+ Example payloads + {selectedEnvironment && selectedEnvironment.examples.length > 0 && ( +
+ {selectedEnvironment?.examples.map((example) => ( + + ))} +
+ )} + Recent payloads + Account ID + {selectedEnvironment?.hasAuthResolver && ( + + setCurrentAccountId(e.target.value)} + /> + {accountId.error} + + )}
- +
); } - -// This is the panel that shows if you have an auth resolver - -{ - /* {selectedEnvironment?.hasAuthResolver && ( - - - setCurrentAccountId(e.target.value)} - /> - {accountId.error} - - )} */ -} - -//This is the example popover button - -{ - /*
- {selectedEnvironment && selectedEnvironment.examples.length > 0 && ( - setIsExamplePopoverOpen(open)} - > - - - Insert an example - - - - - {selectedEnvironment?.examples.map((example) => ( - - ))} - - - )} -
*/ -} From 09bdaa9d3c5c4d8df75ed4b89fe06b2092029338 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Fri, 29 Sep 2023 18:09:34 +0100 Subject: [PATCH 06/35] =?UTF-8?q?Conditionally=20hide=20the=20side=20panel?= =?UTF-8?q?=20components=20if=20they=E2=80=99re=20blank?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../route.tsx | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index 5024ea218a..5b9f9ef364 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -1,7 +1,5 @@ -import { conform, useForm } from "@conform-to/react"; +import { useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; -import { ArrowTopRightOnSquareIcon, ArrowUpRightIcon } from "@heroicons/react/20/solid"; -import { PopoverTrigger } from "@radix-ui/react-popover"; import { Form, useActionData, useSubmit } from "@remix-run/react"; import { ActionFunction, LoaderArgs, json } from "@remix-run/server-runtime"; import { useCallback, useRef, useState } from "react"; @@ -10,13 +8,12 @@ import { z } from "zod"; import { JSONEditor } from "~/components/code/JSONEditor"; import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel"; import { BreadcrumbLink } from "~/components/navigation/NavBar"; -import { Button, ButtonContent } from "~/components/primitives/Buttons"; +import { Button } from "~/components/primitives/Buttons"; import { Callout } from "~/components/primitives/Callout"; import { FormError } from "~/components/primitives/FormError"; import { Header2 } from "~/components/primitives/Headers"; import { Input } from "~/components/primitives/Input"; import { InputGroup } from "~/components/primitives/InputGroup"; -import { Popover, PopoverContent } from "~/components/primitives/Popover"; import { Select, SelectContent, @@ -30,7 +27,6 @@ import { redirectBackWithErrorMessage, redirectWithSuccessMessage } from "~/mode import { TestJobPresenter } from "~/presenters/TestJobPresenter.server"; import { TestJobService } from "~/services/jobs/testJob.server"; import { requireUserId } from "~/services/session.server"; -import { cn } from "~/utils/cn"; import { Handle } from "~/utils/handle"; import { JobParamsSchema, jobRunDashboardPath, trimTrailingSlash } from "~/utils/pathBuilder"; @@ -195,10 +191,10 @@ export default function Page() { />
-
- Example payloads +
{selectedEnvironment && selectedEnvironment.examples.length > 0 && ( -
+
+ Example payloads {selectedEnvironment?.examples.map((example) => (
From 1be7df36daee7c729c4245ede1873f8d54e9488e Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Sun, 1 Oct 2023 18:00:49 +0100 Subject: [PATCH 07/35] Example with selected state working --- .../app/presenters/TestJobPresenter.server.ts | 15 ++++-- .../route.tsx | 52 +++++++++++++------ 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/apps/webapp/app/presenters/TestJobPresenter.server.ts b/apps/webapp/app/presenters/TestJobPresenter.server.ts index 3028199e2b..55dea6cdb8 100644 --- a/apps/webapp/app/presenters/TestJobPresenter.server.ts +++ b/apps/webapp/app/presenters/TestJobPresenter.server.ts @@ -4,6 +4,7 @@ import { PrismaClient, prisma } from "~/db.server"; import { Job } from "~/models/job.server"; import { Organization } from "~/models/organization.server"; import { Project } from "~/models/project.server"; +import { EventExample } from "@trigger.dev/core"; export class TestJobPresenter { #prismaClient: PrismaClient; @@ -97,6 +98,15 @@ export class TestJobPresenter { throw new Error("Job not found"); } + //collect together the examples, we don't care about the environments + const examples: EventExample[] = job.aliases.flatMap((alias) => + alias.version.examples.map((example) => ({ + ...example, + icon: example.icon ?? undefined, + payload: JSON.stringify(example.payload, exampleReplacer, 2), + })) + ); + return { environments: job.aliases.map((alias) => ({ id: alias.environment.id, @@ -104,14 +114,11 @@ export class TestJobPresenter { slug: alias.environment.slug, userId: alias.environment.orgMember?.userId, versionId: alias.version.id, - examples: alias.version.examples.map((example) => ({ - ...example, - payload: JSON.stringify(example.payload, exampleReplacer, 2), - })), hasAuthResolver: alias.version.integrations.some( (i) => i.integration.authSource === "RESOLVER" ), })), + examples, hasTestRuns: job._count.runs > 0, }; } diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index 5b9f9ef364..97313bfee8 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -2,7 +2,7 @@ import { useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; import { Form, useActionData, useSubmit } from "@remix-run/react"; import { ActionFunction, LoaderArgs, json } from "@remix-run/server-runtime"; -import { useCallback, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { z } from "zod"; import { JSONEditor } from "~/components/code/JSONEditor"; @@ -35,14 +35,14 @@ export const loader = async ({ request, params }: LoaderArgs) => { const { organizationSlug, projectParam, jobParam } = JobParamsSchema.parse(params); const presenter = new TestJobPresenter(); - const { environments, hasTestRuns } = await presenter.call({ + const { environments, hasTestRuns, examples } = await presenter.call({ userId, organizationSlug, projectSlug: projectParam, jobSlug: jobParam, }); - return typedjson({ environments, hasTestRuns }); + return typedjson({ environments, hasTestRuns, examples }); }; const schema = z.object({ @@ -112,23 +112,27 @@ export const handle: Handle = { const startingJson = "{\n\n}"; export default function Page() { + const { environments, hasTestRuns, examples } = useTypedLoaderData(); + + //form submission const submit = useSubmit(); const lastSubmission = useActionData(); - const [isExamplePopoverOpen, setIsExamplePopoverOpen] = useState(false); - const { environments, hasTestRuns } = useTypedLoaderData(); - const [defaultJson, setDefaultJson] = useState(startingJson); - const currentJson = useRef(defaultJson); - const [selectedEnvironmentId, setSelectedEnvironmentId] = useState(environments[0].id); - const [currentAccountId, setCurrentAccountId] = useState(undefined); + //examples + const [selectedExampleId, setSelectedExampleId] = useState(examples.at(0)?.id); + const selectedExample = examples.find((e) => e.id === selectedExampleId); - const selectedEnvironment = environments.find((e) => e.id === selectedEnvironmentId); - - const insertCode = useCallback((code: string) => { + const [defaultJson, setDefaultJson] = useState(selectedExample?.payload ?? startingJson); + const setCode = useCallback((code: string) => { setDefaultJson(code); - setIsExamplePopoverOpen(false); }, []); + const [selectedEnvironmentId, setSelectedEnvironmentId] = useState(environments[0].id); + const selectedEnvironment = environments.find((e) => e.id === selectedEnvironmentId); + + const currentJson = useRef(defaultJson); + const [currentAccountId, setCurrentAccountId] = useState(undefined); + const submitForm = useCallback( (e: React.FormEvent) => { submit( @@ -181,7 +185,17 @@ export default function Page() { defaultValue={defaultJson} readOnly={false} basicSetup - onChange={(v) => (currentJson.current = v)} + onChange={(v) => { + currentJson.current = v; + + //deselect the example if it's been edited + if (selectedExampleId) { + if (v !== selectedExample?.payload) { + setSelectedExampleId(undefined); + } + } + }} + // key={selectedExampleId ?? "not-example"} height="100%" min-height="100%" max-height="100%" @@ -192,16 +206,20 @@ export default function Page() {
- {selectedEnvironment && selectedEnvironment.examples.length > 0 && ( + {examples.length > 0 && (
Example payloads - {selectedEnvironment?.examples.map((example) => ( + {examples.map((example) => ( + ))} +
+ )}
{selectedEnvironment?.hasAuthResolver && ( From 817ed79d3d5d595cc9c7689f6f5f9301c111b727 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Mon, 2 Oct 2023 18:51:53 +0100 Subject: [PATCH 10/35] =?UTF-8?q?Select=20a=20recent=20payload=20if=20ther?= =?UTF-8?q?e=E2=80=99s=20no=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../route.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index 31778d3df9..c5cc26f0b1 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -119,7 +119,9 @@ export default function Page() { const lastSubmission = useActionData(); //examples - const [selectedCodeSampleId, setSelectedCodeSampleId] = useState(examples.at(0)?.id); + const [selectedCodeSampleId, setSelectedCodeSampleId] = useState( + examples.at(0)?.id ?? runs.at(0)?.id + ); const selectedCodeSample = examples.find((e) => e.id === selectedCodeSampleId)?.payload ?? runs.find((r) => r.id === selectedCodeSampleId)?.payload; @@ -207,7 +209,7 @@ export default function Page() { />
-
+
{examples.length > 0 && (
Example payloads From b38cfd5c242990714523ac09c5172c249e61ed5d Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Mon, 2 Oct 2023 19:22:37 +0100 Subject: [PATCH 11/35] Created Icon and DetailCell components --- .../app/components/primitives/DetailCell.tsx | 31 ++++++++++++++++ .../webapp/app/components/primitives/Icon.tsx | 37 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 apps/webapp/app/components/primitives/DetailCell.tsx create mode 100644 apps/webapp/app/components/primitives/Icon.tsx diff --git a/apps/webapp/app/components/primitives/DetailCell.tsx b/apps/webapp/app/components/primitives/DetailCell.tsx new file mode 100644 index 0000000000..09cd0f7fcc --- /dev/null +++ b/apps/webapp/app/components/primitives/DetailCell.tsx @@ -0,0 +1,31 @@ +import { IconInBox, RenderIcon } from "./Icon"; +import { Paragraph } from "./Paragraph"; + +type DetailCellProps = { + leadingIcon?: RenderIcon; + trailingIcon?: RenderIcon; + label: string; + description?: string; +}; + +export function DetailCell({ leadingIcon, trailingIcon, label, description }: DetailCellProps) { + return ( +
+ +
+ + {label} + +
+
+ +
+
+ ); +} diff --git a/apps/webapp/app/components/primitives/Icon.tsx b/apps/webapp/app/components/primitives/Icon.tsx new file mode 100644 index 0000000000..61ea492bf6 --- /dev/null +++ b/apps/webapp/app/components/primitives/Icon.tsx @@ -0,0 +1,37 @@ +import { IconNamesOrString, NamedIcon } from "./NamedIcon"; +import { cn } from "~/utils/cn"; + +export type RenderIcon = IconNamesOrString | React.ComponentType; + +type IconProps = { + icon?: RenderIcon; + className?: string; +}; + +/** Use this icon to either render a passed in React component, or a NamedIcon/CompanyIcon */ +export function Icon(props: IconProps) { + if (typeof props.icon === "string") { + return } />; + } + + const Icon = props.icon; + + if (!Icon) { + return <>; + } + + return ; +} + +export function IconInBox({ boxClassName, ...props }: IconProps & { boxClassName?: string }) { + return ( +
+ +
+ ); +} From 88e71164a41b65ce44422e94fb0b18e48f7cd9cb Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Mon, 2 Oct 2023 19:31:46 +0100 Subject: [PATCH 12/35] The integrations now use the DetailCell --- .../app/components/primitives/DetailCell.tsx | 37 +++++++++++++++---- .../webapp/app/components/primitives/Icon.tsx | 2 +- .../route.tsx | 27 ++++---------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/webapp/app/components/primitives/DetailCell.tsx b/apps/webapp/app/components/primitives/DetailCell.tsx index 09cd0f7fcc..3446c022aa 100644 --- a/apps/webapp/app/components/primitives/DetailCell.tsx +++ b/apps/webapp/app/components/primitives/DetailCell.tsx @@ -1,18 +1,38 @@ -import { IconInBox, RenderIcon } from "./Icon"; +import { cn } from "~/utils/cn"; +import { Icon, IconInBox, RenderIcon } from "./Icon"; import { Paragraph } from "./Paragraph"; type DetailCellProps = { leadingIcon?: RenderIcon; + leadingIconClassName?: string; trailingIcon?: RenderIcon; + trailingIconClassName?: string; label: string; description?: string; + className?: string; }; -export function DetailCell({ leadingIcon, trailingIcon, label, description }: DetailCellProps) { +export function DetailCell({ + leadingIcon, + leadingIconClassName, + trailingIcon, + trailingIconClassName, + label, + description, + className, +}: DetailCellProps) { return ( -
- -
+
+ +
-
diff --git a/apps/webapp/app/components/primitives/Icon.tsx b/apps/webapp/app/components/primitives/Icon.tsx index 61ea492bf6..470d4cc809 100644 --- a/apps/webapp/app/components/primitives/Icon.tsx +++ b/apps/webapp/app/components/primitives/Icon.tsx @@ -31,7 +31,7 @@ export function IconInBox({ boxClassName, ...props }: IconProps & { boxClassName boxClassName )} > - +
); } diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx index 1c653370a0..09fa3716e5 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx @@ -13,6 +13,7 @@ import { BreadcrumbLink } from "~/components/navigation/NavBar"; import { LinkButton } from "~/components/primitives/Buttons"; import { Callout } from "~/components/primitives/Callout"; import { DateTime } from "~/components/primitives/DateTime"; +import { DetailCell } from "~/components/primitives/DetailCell"; import { Header2 } from "~/components/primitives/Headers"; import { Help, HelpContent, HelpTrigger } from "~/components/primitives/Help"; import { Input } from "~/components/primitives/Input"; @@ -482,25 +483,13 @@ function AddIntegrationConnection({ icon?: string; }) { return ( -
- - - {name} - -
- {isIntegration && } - -
-
+ ); } From f39577a41b2093a5705eae942b67f6ef7864d1be Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Tue, 3 Oct 2023 11:34:03 +0100 Subject: [PATCH 13/35] Use DetailCell on the integrations page --- .../app/components/primitives/DetailCell.tsx | 6 +- .../route.tsx | 63 +++---------------- 2 files changed, 14 insertions(+), 55 deletions(-) diff --git a/apps/webapp/app/components/primitives/DetailCell.tsx b/apps/webapp/app/components/primitives/DetailCell.tsx index 3446c022aa..14c88005ed 100644 --- a/apps/webapp/app/components/primitives/DetailCell.tsx +++ b/apps/webapp/app/components/primitives/DetailCell.tsx @@ -8,6 +8,7 @@ type DetailCellProps = { trailingIcon?: RenderIcon; trailingIconClassName?: string; label: string; + labelSize?: "small" | "base"; description?: string; className?: string; }; @@ -18,13 +19,14 @@ export function DetailCell({ trailingIcon, trailingIconClassName, label, + labelSize = "small", description, className, }: DetailCellProps) { return (
@@ -34,7 +36,7 @@ export function DetailCell({ />
{label} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx index 09fa3716e5..2784ed5dfe 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx @@ -210,10 +210,13 @@ function PossibleIntegrationsList({ - } @@ -222,10 +225,13 @@ function PossibleIntegrationsList({ Create an Integration -
@@ -493,55 +499,6 @@ function AddIntegrationConnection({ ); } -function ExternalIntegrationLink({ - name, - label, - trailingIcon, -}: { - name: string; - label: string; - trailingIcon: string; -}) { - return ( - - - - {label} - -
- -
-
- ); -} - export function IntegrationIcon() { return ; } - -function InfoLink({ text }: { text: string }) { - return ( -
- - - {text} - -
- -
-
- ); -} From 55a38eacc939a379f3054947397d14df142806e4 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Tue, 3 Oct 2023 12:12:37 +0100 Subject: [PATCH 14/35] Added support for description to DetailCell. With proper variants now --- .../app/components/primitives/DetailCell.tsx | 47 +++++++++++++++++-- .../components/stories/DetailCell.stories.tsx | 45 ++++++++++++++++++ .../route.tsx | 4 +- 3 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 apps/webapp/app/components/stories/DetailCell.stories.tsx diff --git a/apps/webapp/app/components/primitives/DetailCell.tsx b/apps/webapp/app/components/primitives/DetailCell.tsx index 14c88005ed..7e6766dce6 100644 --- a/apps/webapp/app/components/primitives/DetailCell.tsx +++ b/apps/webapp/app/components/primitives/DetailCell.tsx @@ -2,15 +2,38 @@ import { cn } from "~/utils/cn"; import { Icon, IconInBox, RenderIcon } from "./Icon"; import { Paragraph } from "./Paragraph"; +const variations = { + small: { + label: { + variant: "small" as const, + className: "m-0 leading-[1.1rem]", + }, + description: { + variant: "extra-small" as const, + className: "m-0", + }, + }, + base: { + label: { + variant: "base" as const, + className: "m-0 leading-[1.1rem] ", + }, + description: { + variant: "small" as const, + className: "m-0", + }, + }, +}; + type DetailCellProps = { leadingIcon?: RenderIcon; leadingIconClassName?: string; trailingIcon?: RenderIcon; trailingIconClassName?: string; label: string; - labelSize?: "small" | "base"; description?: string; className?: string; + variant?: keyof typeof variations; }; export function DetailCell({ @@ -19,10 +42,12 @@ export function DetailCell({ trailingIcon, trailingIconClassName, label, - labelSize = "small", description, className, + variant = "small", }: DetailCellProps) { + const variation = variations[variant]; + return (
{label} + {description && ( + + {description} + + )}
; + +export const Basic: Story = { + render: () => , +}; + +function Examples() { + return ( +
+ + + +
+ ); +} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx index 2784ed5dfe..dd59686795 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route.tsx @@ -214,7 +214,7 @@ function PossibleIntegrationsList({ leadingIcon="plus" leadingIconClassName="text-dimmed" label="Request an API and we'll add it to the list as an Integration" - labelSize="base" + variant="base" trailingIcon="chevron-right" trailingIconClassName="text-slate-700 group-hover:text-bright" /> @@ -229,7 +229,7 @@ function PossibleIntegrationsList({ leadingIcon="integration" leadingIconClassName="text-dimmed" label="Learn how to create your own API Integrations" - labelSize="base" + variant="base" trailingIcon="external-link" trailingIconClassName="text-slate-700 group-hover:text-bright" /> From c08c695a00c86ac16386c0f93f0132ef748b6e43 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 13:20:01 +0100 Subject: [PATCH 15/35] =?UTF-8?q?DateTimeAccurate=20and=20formatDateTimeAc?= =?UTF-8?q?curate=20weren=E2=80=99t=20displaying=20correctly.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fractionalSecondDigits isn’t in the types, but is supported for 92.5% of users --- apps/webapp/app/components/primitives/DateTime.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/webapp/app/components/primitives/DateTime.tsx b/apps/webapp/app/components/primitives/DateTime.tsx index fcc9478cb0..a9d618b862 100644 --- a/apps/webapp/app/components/primitives/DateTime.tsx +++ b/apps/webapp/app/components/primitives/DateTime.tsx @@ -63,16 +63,17 @@ export const DateTimeAccurate = ({ date, timeZone = "UTC" }: DateTimeProps) => { }; function formatDateTimeAccurate(date: Date, timeZone: string, locales: string[]): string { - const milliseconds = `00${date.getMilliseconds()}`.slice(-3); - const formattedDateTime = new Intl.DateTimeFormat(locales, { + year: "numeric", month: "short", - day: "2-digit", + day: "numeric", hour: "numeric", - minute: "2-digit", - second: "2-digit", + minute: "numeric", + second: "numeric", timeZone, + // @ts-ignore this works in 92.5% of browsers https://caniuse.com/mdn-javascript_builtins_intl_datetimeformat_datetimeformat_options_parameter_options_fractionalseconddigits_parameter + fractionalSecondDigits: 3, }).format(date); - return `${formatDateTime}.${milliseconds}`; + return formattedDateTime; } From 912c600f9698390be24de11e56352440b2e4a9de Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 13:21:52 +0100 Subject: [PATCH 16/35] DetailCell now allows label and description to be React components --- apps/webapp/app/components/primitives/DetailCell.tsx | 4 ++-- apps/webapp/app/components/stories/DetailCell.stories.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/webapp/app/components/primitives/DetailCell.tsx b/apps/webapp/app/components/primitives/DetailCell.tsx index 7e6766dce6..ff3fd22e88 100644 --- a/apps/webapp/app/components/primitives/DetailCell.tsx +++ b/apps/webapp/app/components/primitives/DetailCell.tsx @@ -30,8 +30,8 @@ type DetailCellProps = { leadingIconClassName?: string; trailingIcon?: RenderIcon; trailingIconClassName?: string; - label: string; - description?: string; + label: string | React.ReactNode; + description?: string | React.ReactNode; className?: string; variant?: keyof typeof variations; }; diff --git a/apps/webapp/app/components/stories/DetailCell.stories.tsx b/apps/webapp/app/components/stories/DetailCell.stories.tsx index c0c09ed7b4..7f70e01a16 100644 --- a/apps/webapp/app/components/stories/DetailCell.stories.tsx +++ b/apps/webapp/app/components/stories/DetailCell.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { DetailCell } from "../primitives/DetailCell"; import { ClockIcon, CodeBracketIcon } from "@heroicons/react/24/outline"; +import { DateTime, DateTimeAccurate } from "../primitives/DateTime"; const meta: Meta = { title: "Primitives/DetailCells", @@ -35,7 +36,7 @@ function Examples() { } description="Run #42 complete" trailingIcon="plus" trailingIconClassName="text-slate-500 group-hover:text-bright" From 625b8ee54c238b460f8d2aba9eef707abb49834d Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 13:22:12 +0100 Subject: [PATCH 17/35] Using the DetailCell on the Test page --- .../route.tsx | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index c5cc26f0b1..dd28d4b00e 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -1,8 +1,9 @@ import { useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; +import { ClockIcon, CodeBracketIcon } from "@heroicons/react/24/outline"; import { Form, useActionData, useSubmit } from "@remix-run/react"; import { ActionFunction, LoaderArgs, json } from "@remix-run/server-runtime"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useRef, useState } from "react"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { z } from "zod"; import { JSONEditor } from "~/components/code/JSONEditor"; @@ -10,6 +11,8 @@ import { EnvironmentLabel } from "~/components/environments/EnvironmentLabel"; import { BreadcrumbLink } from "~/components/navigation/NavBar"; import { Button } from "~/components/primitives/Buttons"; import { Callout } from "~/components/primitives/Callout"; +import { DateTime } from "~/components/primitives/DateTime"; +import { DetailCell } from "~/components/primitives/DetailCell"; import { FormError } from "~/components/primitives/FormError"; import { Header2 } from "~/components/primitives/Headers"; import { Input } from "~/components/primitives/Input"; @@ -23,6 +26,7 @@ import { SelectValue, } from "~/components/primitives/Select"; import { TextLink } from "~/components/primitives/TextLink"; +import { runStatusTitle } from "~/components/runs/RunStatuses"; import { redirectBackWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server"; import { TestJobPresenter } from "~/presenters/TestJobPresenter.server"; import { TestJobService } from "~/services/jobs/testJob.server"; @@ -214,21 +218,26 @@ export default function Page() {
Example payloads {examples.map((example) => ( - + + ))}
)} @@ -241,21 +250,29 @@ export default function Page() { ) : (
{runs.map((run) => ( - + } + description={`Run #${run.number} ${runStatusTitle( + run.status + ).toLocaleLowerCase()}`} + trailingIcon={run.id === selectedCodeSampleId ? "check" : "plus"} + trailingIconClassName={ + run.id === selectedCodeSampleId + ? "text-green-500 group-hover:text-green-400" + : "text-slate-500 group-hover:text-bright" + } + /> + ))}
)} From ebd0fb094fdb58338d94351ed59da6fc99bca443 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 15:24:56 +0100 Subject: [PATCH 18/35] Styled the CodeMirror scrollbars to match elsewhere --- .../webapp/app/components/code/JSONEditor.tsx | 5 +- .../app/components/code/codeMirrorTheme.ts | 48 ++++++++++++++- .../route.tsx | 58 ++++++++++++------- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/apps/webapp/app/components/code/JSONEditor.tsx b/apps/webapp/app/components/code/JSONEditor.tsx index 4b635904a1..7636fbcb2c 100644 --- a/apps/webapp/app/components/code/JSONEditor.tsx +++ b/apps/webapp/app/components/code/JSONEditor.tsx @@ -84,10 +84,7 @@ export function JSONEditor(opts: JSONEditorProps) { return (
{ if (!onBlur) return; diff --git a/apps/webapp/app/components/code/codeMirrorTheme.ts b/apps/webapp/app/components/code/codeMirrorTheme.ts index 40b31c31ab..19cfa0d9db 100644 --- a/apps/webapp/app/components/code/codeMirrorTheme.ts +++ b/apps/webapp/app/components/code/codeMirrorTheme.ts @@ -17,10 +17,15 @@ export function darkTheme(): Extension { violet = "#c678dd", darkBackground = "#21252b", highlightBackground = "rgba(71,85,105,0.2)", - background = "rgba(255,255,255,0)", + background = "rgba(11, 16, 24 ,100)", tooltipBackground = "#353a42", selection = "rgb(71 85 105)", - cursor = "#528bff"; + cursor = "#528bff", + scrollbarTrack = "#0E1521", + scrollbarTrackActive = "#131B2B", + scrollbarThumb = "#293649", + scrollbarThumbActive = "#3C4B62", + scrollbarBg = "#0E1521"; const jsonHeroEditorTheme = EditorView.theme( { @@ -94,6 +99,45 @@ export function darkTheme(): Extension { color: ivory, }, }, + ".cm-scroller": { + scrollbarWidth: "thin", + scrollbarColor: `${scrollbarThumb} ${scrollbarTrack}`, + }, + ".cm-scroller::-webkit-scrollbar": { + display: "block", + width: "8px", + height: "8px", + }, + ".cm-scroller::-webkit-scrollbar-track": { + backgroundColor: scrollbarTrack, + borderRadius: "0", + }, + ".cm-scroller::-webkit-scrollbar-track:hover": { + backgroundColor: scrollbarTrackActive, + }, + ".cm-scroller::-webkit-scrollbar-track:active": { + backgroundColor: scrollbarTrackActive, + }, + ".cm-scroller::-webkit-scrollbar-thumb": { + backgroundColor: scrollbarThumb, + borderRadius: "0", + }, + ".cm-scroller::-webkit-scrollbar-thumb:hover": { + backgroundColor: scrollbarThumbActive, + }, + ".cm-scroller::-webkit-scrollbar-thumb:active": { + backgroundColor: scrollbarThumbActive, + }, + ".cm-scroller::-webkit-scrollbar-corner": { + backgroundColor: scrollbarBg, + borderRadius: "0", + }, + ".cm-scroller::-webkit-scrollbar-corner:hover": { + backgroundColor: scrollbarBg, + }, + ".cm-scroller::-webkit-scrollbar-corner:active": { + backgroundColor: scrollbarBg, + }, }, { dark: true } ); diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index dd28d4b00e..754adce160 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -187,32 +187,46 @@ export default function Page() { onSubmit={(e) => submitForm(e)} >
- -
- { - currentJson.current = v; +
+ { + currentJson.current = v; - //deselect the example if it's been edited - if (selectedCodeSampleId) { - if (v !== selectedCodeSample) { - setDefaultJson(v); - setSelectedCodeSampleId(undefined); - } + //deselect the example if it's been edited + if (selectedCodeSampleId) { + if (v !== selectedCodeSample) { + setDefaultJson(v); + setSelectedCodeSampleId(undefined); } + } + }} + height="100%" + min-height="100%" + max-height="100%" + autoFocus + placeholder="Use your schema to enter valid JSON or add one of the example payloads then click 'Run test'" + className="h-full" + /> +
+ + {/* Copy button */} +
- +
{examples.length > 0 && (
From b8cb6a353d79b7324f16b3a09e8720ea90643708 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 16:28:54 +0100 Subject: [PATCH 19/35] Adding copy and clear to the JSONEditor, not working properly yet though --- .../webapp/app/components/code/JSONEditor.tsx | 69 ++++++++++++++++--- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/apps/webapp/app/components/code/JSONEditor.tsx b/apps/webapp/app/components/code/JSONEditor.tsx index 7636fbcb2c..a78701e195 100644 --- a/apps/webapp/app/components/code/JSONEditor.tsx +++ b/apps/webapp/app/components/code/JSONEditor.tsx @@ -2,10 +2,12 @@ import { json as jsonLang } from "@codemirror/lang-json"; import type { ViewUpdate } from "@codemirror/view"; import type { ReactCodeMirrorProps, UseCodeMirror } from "@uiw/react-codemirror"; import { useCodeMirror } from "@uiw/react-codemirror"; -import { useRef, useEffect } from "react"; +import { useRef, useEffect, useCallback } from "react"; import { getEditorSetup } from "./codeMirrorSetup"; import { darkTheme } from "./codeMirrorTheme"; import { cn } from "~/utils/cn"; +import { Button } from "../primitives/Buttons"; +import { ClipboardIcon } from "@heroicons/react/20/solid"; export interface JSONEditorProps extends Omit { defaultValue?: string; @@ -14,6 +16,8 @@ export interface JSONEditorProps extends Omit { onChange?: (value: string) => void; onUpdate?: (update: ViewUpdate) => void; onBlur?: (code: string) => void; + showCopyButton?: boolean; + showClearButton?: boolean; } const languages = { @@ -38,6 +42,8 @@ export function JSONEditor(opts: JSONEditorProps) { onBlur, basicSetup, autoFocus, + showCopyButton = true, + showClearButton = true, } = { ...defaultProps, ...opts, @@ -76,20 +82,65 @@ export function JSONEditor(opts: JSONEditorProps) { //if the defaultValue changes update the editor useEffect(() => { if (state !== undefined) { + console.log("content updated to:"); + console.log(defaultValue); state.update({ changes: { from: 0, to: state.doc.length, insert: defaultValue }, }); } }, [defaultValue, state]); + const clear = useCallback(() => { + if (state === undefined) return; + onChange?.(""); + }, [state]); + + const copy = useCallback(() => { + if (state === undefined) return; + console.log("copying"); + console.log(state.doc.lines); + navigator.clipboard.writeText(state.doc.toString()); + }, [state]); + return ( -
{ - if (!onBlur) return; - onBlur(editor.current?.textContent ?? ""); - }} - /> +
+
{ + if (!onBlur) return; + onBlur(editor.current?.textContent ?? ""); + }} + /> +
+ {showClearButton && ( + + )} + {showCopyButton && ( + + )} +
+
); } From 1764f7319b6432c2f23cdd8ef82a80a835055e01 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 16:29:06 +0100 Subject: [PATCH 20/35] Removed the copy/clear buttons from the Test route --- .../route.tsx | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index 754adce160..ed89ee3fbd 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -1,5 +1,6 @@ import { useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; +import { ClipboardIcon } from "@heroicons/react/20/solid"; import { ClockIcon, CodeBracketIcon } from "@heroicons/react/24/outline"; import { Form, useActionData, useSubmit } from "@remix-run/react"; import { ActionFunction, LoaderArgs, json } from "@remix-run/server-runtime"; @@ -210,22 +211,6 @@ export default function Page() { placeholder="Use your schema to enter valid JSON or add one of the example payloads then click 'Run test'" className="h-full" /> -
- - {/* Copy button */} - -
{examples.length > 0 && ( From e98a85a993d2959e98cc059513f4db33512a509f Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 16:44:28 +0100 Subject: [PATCH 21/35] Delete the light color theme --- .../app/components/code/codeMirrorTheme.ts | 154 ------------------ 1 file changed, 154 deletions(-) diff --git a/apps/webapp/app/components/code/codeMirrorTheme.ts b/apps/webapp/app/components/code/codeMirrorTheme.ts index 19cfa0d9db..babcccf09e 100644 --- a/apps/webapp/app/components/code/codeMirrorTheme.ts +++ b/apps/webapp/app/components/code/codeMirrorTheme.ts @@ -199,157 +199,3 @@ export function darkTheme(): Extension { return [jsonHeroEditorTheme, syntaxHighlighting(jsonHeroHighlightStyle)]; } - -export function lightTheme(): Extension[] { - const stringColor = "text-[#53a053]", - numberColor = "text-[#447bef]", - variableColor = "text-[#a42ea2]", - booleanColor = "text-[#e2574e]", - coral = "text-[#e06c75]", - invalid = "text-[#ffffff]", - ivory = "text-[#abb2bf]", - stone = "text-[#7d8799]", - malibu = "text-[#61afef]", - whiskey = "text-[#d19a66]", - violet = "text-[#c678dd]", - darkBackground = "text-[#21252b]", - highlightBackground = "text-[#D0D0D0]", - background = "text-[#ffffff]", - tooltipBackground = "text-[#353a42]", - selection = "text-[#D0D0D0]", - cursor = "text-[#528bff]"; - - const jsonHeroEditorTheme = EditorView.theme( - { - "&": { - color: ivory, - backgroundColor: background, - }, - - ".cm-content": { - caretColor: cursor, - fontFamily: "monospace", - fontSize: "14px", - }, - - ".cm-cursor, .cm-dropCursor": { borderLeftColor: cursor }, - "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { - backgroundColor: selection, - }, - - ".cm-panels": { backgroundColor: darkBackground, color: ivory }, - ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, - ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, - - ".cm-searchMatch": { - backgroundColor: "#72a1ff59", - outline: "1px solid #457dff", - }, - ".cm-searchMatch.cm-searchMatch-selected": { - backgroundColor: "#6199ff2f", - }, - - ".cm-activeLine": { backgroundColor: highlightBackground }, - ".cm-selectionMatch": { backgroundColor: "#aafe661a" }, - - "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { - backgroundColor: "#bad0f847", - outline: "1px solid #515a6b", - }, - - ".cm-gutters": { - backgroundColor: background, - color: stone, - border: "none", - }, - - ".cm-activeLineGutter": { - backgroundColor: highlightBackground, - }, - - ".cm-foldPlaceholder": { - backgroundColor: "transparent", - border: "none", - color: "#ddd", - }, - - ".cm-tooltip": { - border: "none", - backgroundColor: tooltipBackground, - }, - ".cm-tooltip .cm-tooltip-arrow:before": { - borderTopColor: "transparent", - borderBottomColor: "transparent", - }, - ".cm-tooltip .cm-tooltip-arrow:after": { - borderTopColor: tooltipBackground, - borderBottomColor: tooltipBackground, - }, - ".cm-tooltip-autocomplete": { - "& > ul > li[aria-selected]": { - backgroundColor: highlightBackground, - color: ivory, - }, - }, - }, - { dark: false } - ); - - /// The highlighting style for code in the JSON Hero theme. - const jsonHeroHighlightStyle = tagHighlighter([ - { tag: tags.keyword, class: violet }, - { - tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], - class: variableColor, - }, - { - tag: [tags.function(tags.variableName), tags.labelName], - class: malibu, - }, - { - tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], - class: whiskey, - }, - { tag: [tags.definition(tags.name), tags.separator], class: ivory }, - { - tag: [ - tags.typeName, - tags.className, - tags.number, - tags.changed, - tags.annotation, - tags.modifier, - tags.self, - tags.namespace, - ], - class: numberColor, - }, - { - tag: [ - tags.operator, - tags.operatorKeyword, - tags.url, - tags.escape, - tags.regexp, - tags.link, - tags.special(tags.string), - ], - class: stringColor, - }, - { tag: [tags.meta, tags.comment], class: stone }, - - { tag: tags.link, class: stone }, - { tag: tags.heading, class: coral }, - { - tag: [tags.atom, tags.bool, tags.special(tags.variableName)], - class: booleanColor, - }, - { - tag: [tags.processingInstruction, tags.string, tags.inserted], - class: stringColor, - }, - { tag: tags.invalid, class: invalid }, - ]); - - return [jsonHeroEditorTheme, syntaxHighlighting(jsonHeroHighlightStyle)]; -} From d85026f82044259ede2f314e9a1242caf624300b Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 16:55:19 +0100 Subject: [PATCH 22/35] The editor now supports copying/clearing etc --- .../webapp/app/components/code/JSONEditor.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/webapp/app/components/code/JSONEditor.tsx b/apps/webapp/app/components/code/JSONEditor.tsx index a78701e195..096e17197c 100644 --- a/apps/webapp/app/components/code/JSONEditor.tsx +++ b/apps/webapp/app/components/code/JSONEditor.tsx @@ -71,7 +71,7 @@ export function JSONEditor(opts: JSONEditorProps) { onChange, onUpdate, }; - const { setContainer, state } = useCodeMirror(settings); + const { setContainer, view } = useCodeMirror(settings); useEffect(() => { if (editor.current) { @@ -81,26 +81,26 @@ export function JSONEditor(opts: JSONEditorProps) { //if the defaultValue changes update the editor useEffect(() => { - if (state !== undefined) { - console.log("content updated to:"); - console.log(defaultValue); - state.update({ - changes: { from: 0, to: state.doc.length, insert: defaultValue }, + if (view !== undefined) { + if (view.state.doc.toString() === defaultValue) return; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: defaultValue }, }); } - }, [defaultValue, state]); + }, [defaultValue, view]); const clear = useCallback(() => { - if (state === undefined) return; + if (view === undefined) return; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: undefined }, + }); onChange?.(""); - }, [state]); + }, [view]); const copy = useCallback(() => { - if (state === undefined) return; - console.log("copying"); - console.log(state.doc.lines); - navigator.clipboard.writeText(state.doc.toString()); - }, [state]); + if (view === undefined) return; + navigator.clipboard.writeText(view.state.doc.toString()); + }, [view]); return (
From fc58e9bb93369504a4e50266ff8c553fbc844c4b Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 17:14:10 +0100 Subject: [PATCH 23/35] Made it clear when text is copied --- apps/webapp/app/components/code/JSONEditor.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/webapp/app/components/code/JSONEditor.tsx b/apps/webapp/app/components/code/JSONEditor.tsx index 096e17197c..3506c4f62e 100644 --- a/apps/webapp/app/components/code/JSONEditor.tsx +++ b/apps/webapp/app/components/code/JSONEditor.tsx @@ -2,12 +2,12 @@ import { json as jsonLang } from "@codemirror/lang-json"; import type { ViewUpdate } from "@codemirror/view"; import type { ReactCodeMirrorProps, UseCodeMirror } from "@uiw/react-codemirror"; import { useCodeMirror } from "@uiw/react-codemirror"; -import { useRef, useEffect, useCallback } from "react"; +import { useRef, useEffect, useCallback, useState } from "react"; import { getEditorSetup } from "./codeMirrorSetup"; import { darkTheme } from "./codeMirrorTheme"; import { cn } from "~/utils/cn"; import { Button } from "../primitives/Buttons"; -import { ClipboardIcon } from "@heroicons/react/20/solid"; +import { CheckIcon, ClipboardDocumentCheckIcon, ClipboardIcon } from "@heroicons/react/20/solid"; export interface JSONEditorProps extends Omit { defaultValue?: string; @@ -72,6 +72,7 @@ export function JSONEditor(opts: JSONEditorProps) { onUpdate, }; const { setContainer, view } = useCodeMirror(settings); + const [copied, setCopied] = useState(false); useEffect(() => { if (editor.current) { @@ -100,6 +101,10 @@ export function JSONEditor(opts: JSONEditorProps) { const copy = useCallback(() => { if (view === undefined) return; navigator.clipboard.writeText(view.state.doc.toString()); + setCopied(true); + setTimeout(() => { + setCopied(false); + }, 1500); }, [view]); return ( @@ -130,7 +135,8 @@ export function JSONEditor(opts: JSONEditorProps) {
- Learn more about running tests - +
{payload.error ? ( {payload.error} From 7ed3aabdb2b7a7ffe845a188959ee61ad03b8e55 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 17:46:23 +0100 Subject: [PATCH 25/35] Fixed CMD shortcut keys --- .../app/components/primitives/ShortcutKey.tsx | 2 ++ .../components/stories/Shortcuts.stories.tsx | 1 + apps/webapp/app/hooks/useShortcutKeys.tsx | 23 ++++++++++++------- apps/webapp/package.json | 2 +- pnpm-lock.yaml | 13 ++++------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/webapp/app/components/primitives/ShortcutKey.tsx b/apps/webapp/app/components/primitives/ShortcutKey.tsx index 4e29a73dbc..8be993c12e 100644 --- a/apps/webapp/app/components/primitives/ShortcutKey.tsx +++ b/apps/webapp/app/components/primitives/ShortcutKey.tsx @@ -54,5 +54,7 @@ function modifierString(modifier: Modifier, isMac: boolean) { return isMac ? "⌘" : "⊞+"; case "shift": return isMac ? "⇧" : "Shift+"; + case "mod": + return isMac ? "⌘" : "Ctrl+"; } } diff --git a/apps/webapp/app/components/stories/Shortcuts.stories.tsx b/apps/webapp/app/components/stories/Shortcuts.stories.tsx index 95e2a63393..dc2f381a75 100644 --- a/apps/webapp/app/components/stories/Shortcuts.stories.tsx +++ b/apps/webapp/app/components/stories/Shortcuts.stories.tsx @@ -25,6 +25,7 @@ const shortcuts: ShortcutDefinition[] = [ { key: "k", modifiers: ["meta"] }, { key: "del", modifiers: ["ctrl", "alt"] }, { key: "enter", modifiers: ["meta"] }, + { key: "enter", modifiers: ["mod"] }, ]; function Collection() { diff --git a/apps/webapp/app/hooks/useShortcutKeys.tsx b/apps/webapp/app/hooks/useShortcutKeys.tsx index 03103dd3c3..092e163967 100644 --- a/apps/webapp/app/hooks/useShortcutKeys.tsx +++ b/apps/webapp/app/hooks/useShortcutKeys.tsx @@ -6,6 +6,7 @@ export type Modifier = "alt" | "ctrl" | "meta" | "shift" | "mod"; export type Shortcut = { key: string; modifiers?: Modifier[]; + enabledOnInputElements?: boolean; }; export type ShortcutDefinition = @@ -19,25 +20,31 @@ type useShortcutKeysProps = { shortcut: ShortcutDefinition; action: (event: KeyboardEvent) => void; disabled?: boolean; + enabledOnInputElements?: boolean; }; export function useShortcutKeys({ shortcut, action, disabled = false }: useShortcutKeysProps) { - const keys = createKeysFromShortcut(shortcut); + const { platform } = useOperatingSystem(); + const isMac = platform === "mac"; + const relevantShortcut = "mac" in shortcut ? (isMac ? shortcut.mac : shortcut.windows) : shortcut; + + const keys = createKeysFromShortcut(relevantShortcut); useHotkeys( keys, (event, hotkeysEvent) => { action(event); }, - { enabled: !disabled } + { + enabled: !disabled, + enableOnFormTags: relevantShortcut.enabledOnInputElements, + enableOnContentEditable: relevantShortcut.enabledOnInputElements, + } ); } -function createKeysFromShortcut(shortcut: ShortcutDefinition) { - const { platform } = useOperatingSystem(); - const isMac = platform === "mac"; - let relevantShortcut = "mac" in shortcut ? (isMac ? shortcut.mac : shortcut.windows) : shortcut; - const modifiers = relevantShortcut.modifiers; - const character = relevantShortcut.key; +function createKeysFromShortcut(shortcut: Shortcut) { + const modifiers = shortcut.modifiers; + const character = shortcut.key; return modifiers ? modifiers.map((k) => k).join("+") + "+" + character : character; } diff --git a/apps/webapp/package.json b/apps/webapp/package.json index 2e90e4b22e..3bee9fb846 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -93,7 +93,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.0", - "react-hotkeys-hook": "^3.4.7", + "react-hotkeys-hook": "^4.4.1", "react-use": "^17.4.0", "recharts": "^2.8.0", "remix-auth": "^3.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 100a4df48c..e5adbb33c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,7 +168,7 @@ importers: react: ^18.2.0 react-dom: ^18.2.0 react-hot-toast: ^2.4.0 - react-hotkeys-hook: ^3.4.7 + react-hotkeys-hook: ^4.4.1 react-use: ^17.4.0 recharts: ^2.8.0 remix-auth: ^3.2.2 @@ -261,7 +261,7 @@ importers: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 react-hot-toast: 2.4.0_biqbaboplfbrettd7655fr4n2y - react-hotkeys-hook: 3.4.7_biqbaboplfbrettd7655fr4n2y + react-hotkeys-hook: 4.4.1_biqbaboplfbrettd7655fr4n2y react-use: 17.4.0_biqbaboplfbrettd7655fr4n2y recharts: 2.8.0_v2m5e27vhdewzwhryxwfaorcca remix-auth: 3.4.0_mrckq3wlqfipa3hs7ezq3k3x3y @@ -20182,10 +20182,6 @@ packages: lru-cache: 7.18.3 dev: false - /hotkeys-js/3.9.4: - resolution: {integrity: sha512-2zuLt85Ta+gIyvs4N88pCYskNrxf1TFv3LR9t5mdAZIX8BcgQQ48F2opUptvHa6m8zsy5v/a0i9mWzTrlNWU0Q==} - dev: false - /hpagent/0.1.2: resolution: {integrity: sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==} requiresBuild: true @@ -25774,13 +25770,12 @@ packages: - csstype dev: false - /react-hotkeys-hook/3.4.7_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-+bbPmhPAl6ns9VkXkNNyxlmCAIyDAcWbB76O4I0ntr3uWCRuIQf/aRLartUahe9chVMPj+OEzzfk3CQSjclUEQ==} + /react-hotkeys-hook/4.4.1_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==} peerDependencies: react: '>=16.8.1' react-dom: '>=16.8.1' dependencies: - hotkeys-js: 3.9.4 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 dev: false From 93d083b7f951ec70388426c4028d9e9e087967c6 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 17:52:32 +0100 Subject: [PATCH 26/35] =?UTF-8?q?Run=20test=20button=20now=20works=20with?= =?UTF-8?q?=20=E2=8C=98=20Enter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../route.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx index d092d43223..a2f1112f2e 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.jobs.$jobParam.test/route.tsx @@ -332,6 +332,7 @@ export default function Page() { variant="primary/medium" LeadingIcon="beaker" leadingIconClassName="text-bright" + shortcut={{ key: "enter", modifiers: ["mod"], enabledOnInputElements: true }} > Run test From 6cb50ffb8a83efbaeae70a58f0c005efa700bbe1 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 17:52:50 +0100 Subject: [PATCH 27/35] =?UTF-8?q?CodeMirror=20now=20allows=20=E2=8C=98Ente?= =?UTF-8?q?r=20to=20escape=20the=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/code/codeMirrorSetup.ts | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/apps/webapp/app/components/code/codeMirrorSetup.ts b/apps/webapp/app/components/code/codeMirrorSetup.ts index 9e7ff711df..e765d4954e 100644 --- a/apps/webapp/app/components/code/codeMirrorSetup.ts +++ b/apps/webapp/app/components/code/codeMirrorSetup.ts @@ -1,34 +1,17 @@ +import { closeBrackets } from "@codemirror/autocomplete"; +import { indentWithTab } from "@codemirror/commands"; +import { bracketMatching } from "@codemirror/language"; +import { highlightSelectionMatches } from "@codemirror/search"; +import { Prec, type Extension } from "@codemirror/state"; import { - highlightSpecialChars, drawSelection, - highlightActiveLine, dropCursor, - lineNumbers, + highlightActiveLine, highlightActiveLineGutter, + highlightSpecialChars, keymap, + lineNumbers, } from "@codemirror/view"; -import type { Extension } from "@codemirror/state"; -import { highlightSelectionMatches } from "@codemirror/search"; -import { json as jsonLang } from "@codemirror/lang-json"; -import { closeBrackets } from "@codemirror/autocomplete"; -import { bracketMatching } from "@codemirror/language"; -import { indentWithTab } from "@codemirror/commands"; - -export function getPreviewSetup(): Array { - return [ - jsonLang(), - highlightSpecialChars(), - drawSelection(), - dropCursor(), - bracketMatching(), - highlightSelectionMatches(), - lineNumbers(), - ]; -} - -export function getViewerSetup(): Array { - return [drawSelection(), dropCursor(), bracketMatching(), lineNumbers()]; -} export function getEditorSetup(showLineNumbers = true, showHighlights = true): Array { const options = [ @@ -36,6 +19,18 @@ export function getEditorSetup(showLineNumbers = true, showHighlights = true): A dropCursor(), bracketMatching(), closeBrackets(), + Prec.highest( + keymap.of([ + { + key: "Mod-Enter", + run: () => { + console.log("Mod-Enter"); + return true; + }, + preventDefault: false, + }, + ]) + ), keymap.of([indentWithTab]), ]; From b08c22e659bfe0884e3b4158494ee95424f04ea0 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 18:08:16 +0100 Subject: [PATCH 28/35] Added JSON linter to the test editor --- .../app/components/code/codeMirrorSetup.ts | 6 ++++- apps/webapp/package.json | 1 + pnpm-lock.yaml | 22 +++++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/webapp/app/components/code/codeMirrorSetup.ts b/apps/webapp/app/components/code/codeMirrorSetup.ts index e765d4954e..4931967276 100644 --- a/apps/webapp/app/components/code/codeMirrorSetup.ts +++ b/apps/webapp/app/components/code/codeMirrorSetup.ts @@ -1,6 +1,8 @@ import { closeBrackets } from "@codemirror/autocomplete"; import { indentWithTab } from "@codemirror/commands"; +import { jsonParseLinter } from "@codemirror/lang-json"; import { bracketMatching } from "@codemirror/language"; +import { lintGutter, lintKeymap, linter } from "@codemirror/lint"; import { highlightSelectionMatches } from "@codemirror/search"; import { Prec, type Extension } from "@codemirror/state"; import { @@ -19,6 +21,8 @@ export function getEditorSetup(showLineNumbers = true, showHighlights = true): A dropCursor(), bracketMatching(), closeBrackets(), + lintGutter(), + linter(jsonParseLinter()), Prec.highest( keymap.of([ { @@ -31,7 +35,7 @@ export function getEditorSetup(showLineNumbers = true, showHighlights = true): A }, ]) ), - keymap.of([indentWithTab]), + keymap.of([indentWithTab, ...lintKeymap]), ]; if (showLineNumbers) { diff --git a/apps/webapp/package.json b/apps/webapp/package.json index 3bee9fb846..a7576143e7 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -34,6 +34,7 @@ "@codemirror/lang-javascript": "^6.1.1", "@codemirror/lang-json": "^6.0.1", "@codemirror/language": "^6.3.1", + "@codemirror/lint": "^6.4.2", "@codemirror/search": "^6.2.3", "@codemirror/state": "^6.1.3", "@codemirror/view": "^6.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5adbb33c3..1fc5501a66 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,7 @@ importers: '@codemirror/lang-javascript': ^6.1.1 '@codemirror/lang-json': ^6.0.1 '@codemirror/language': ^6.3.1 + '@codemirror/lint': ^6.4.2 '@codemirror/search': ^6.2.3 '@codemirror/state': ^6.1.3 '@codemirror/view': ^6.5.0 @@ -202,6 +203,7 @@ importers: '@codemirror/lang-javascript': 6.1.2 '@codemirror/lang-json': 6.0.1 '@codemirror/language': 6.3.2 + '@codemirror/lint': 6.4.2 '@codemirror/search': 6.2.3 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 @@ -232,7 +234,7 @@ importers: '@trigger.dev/core': link:../../packages/core '@trigger.dev/database': link:../../packages/database '@trigger.dev/sdk': link:../../packages/trigger-sdk - '@uiw/react-codemirror': 4.19.5_k4ec5g7vuuzzonc3d6xbjnmmle + '@uiw/react-codemirror': 4.19.5_th22fcplkuhrqjnlojwclcaim4 class-variance-authority: 0.5.2_typescript@4.9.4 clsx: 1.2.1 compression: 1.7.4 @@ -5332,7 +5334,7 @@ packages: dependencies: '@codemirror/autocomplete': 6.4.0_czcfkg2f66rxeiodoti7r2gulu '@codemirror/language': 6.3.2 - '@codemirror/lint': 6.1.0 + '@codemirror/lint': 6.4.2 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 '@lezer/common': 1.0.2 @@ -5357,8 +5359,8 @@ packages: style-mod: 4.0.0 dev: false - /@codemirror/lint/6.1.0: - resolution: {integrity: sha512-mdvDQrjRmYPvQ3WrzF6Ewaao+NWERYtpthJvoQ3tK3t/44Ynhk8ZGjTSL9jMEv8CgSMogmt75X8ceOZRDSXHtQ==} + /@codemirror/lint/6.4.2: + resolution: {integrity: sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==} dependencies: '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 @@ -13653,12 +13655,13 @@ packages: '@typescript-eslint/types': 5.59.6 eslint-visitor-keys: 3.4.2 - /@uiw/codemirror-extensions-basic-setup/4.19.5_wd2tsis3in55bkaiwnc2c46tom: + /@uiw/codemirror-extensions-basic-setup/4.19.5_o3n2erwajrogdzfxqd6wu4qkza: resolution: {integrity: sha512-1zt7ZPJ01xKkSW/KDy0FZNga0bngN1fC594wCVG7FBi60ehfcAucpooQ+JSPScKXopxcb+ugPKZvVLzr9/OfzA==} peerDependencies: '@codemirror/autocomplete': '>=6.0.0' '@codemirror/commands': '>=6.0.0' '@codemirror/language': '>=6.0.0' + '@codemirror/lint': '>=6.0.0' '@codemirror/search': '>=6.0.0' '@codemirror/state': '>=6.0.0' '@codemirror/view': '>=6.0.0' @@ -13666,13 +13669,13 @@ packages: '@codemirror/autocomplete': 6.4.0_czcfkg2f66rxeiodoti7r2gulu '@codemirror/commands': 6.1.3 '@codemirror/language': 6.3.2 - '@codemirror/lint': 6.1.0 + '@codemirror/lint': 6.4.2 '@codemirror/search': 6.2.3 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 dev: false - /@uiw/react-codemirror/4.19.5_k4ec5g7vuuzzonc3d6xbjnmmle: + /@uiw/react-codemirror/4.19.5_th22fcplkuhrqjnlojwclcaim4: resolution: {integrity: sha512-ZCHh8d7beXbF8/t7F1+yHht6A9Y6CdKeOkZq4A09lxJEnyTQrj1FMf2zvfaqc7K23KNjkTCtSlbqKKbVDgrWaw==} peerDependencies: '@codemirror/state': '>=6.0.0' @@ -13685,13 +13688,14 @@ packages: '@codemirror/state': 6.2.0 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 6.7.2 - '@uiw/codemirror-extensions-basic-setup': 4.19.5_wd2tsis3in55bkaiwnc2c46tom + '@uiw/codemirror-extensions-basic-setup': 4.19.5_o3n2erwajrogdzfxqd6wu4qkza codemirror: 6.0.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' + - '@codemirror/lint' - '@codemirror/search' dev: false @@ -15754,7 +15758,7 @@ packages: '@codemirror/autocomplete': 6.4.0_czcfkg2f66rxeiodoti7r2gulu '@codemirror/commands': 6.1.3 '@codemirror/language': 6.3.2 - '@codemirror/lint': 6.1.0 + '@codemirror/lint': 6.4.2 '@codemirror/search': 6.2.3 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 From 9e2e968bf40b9750642ed800f48583d90a10a999 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 4 Oct 2023 18:54:18 +0100 Subject: [PATCH 29/35] Fix for buttons not being aligned correctly --- apps/webapp/app/components/primitives/Buttons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/components/primitives/Buttons.tsx b/apps/webapp/app/components/primitives/Buttons.tsx index 532d368367..8912d0988d 100644 --- a/apps/webapp/app/components/primitives/Buttons.tsx +++ b/apps/webapp/app/components/primitives/Buttons.tsx @@ -144,7 +144,7 @@ export function ButtonContent(props: ButtonContentPropsType) { const textColorClassName = variation.textColor; return ( -
+
Date: Wed, 4 Oct 2023 18:54:27 +0100 Subject: [PATCH 30/35] Copy/clear buttons now aligned --- apps/webapp/app/components/code/JSONEditor.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/webapp/app/components/code/JSONEditor.tsx b/apps/webapp/app/components/code/JSONEditor.tsx index 3506c4f62e..7d5ef0c237 100644 --- a/apps/webapp/app/components/code/JSONEditor.tsx +++ b/apps/webapp/app/components/code/JSONEditor.tsx @@ -1,13 +1,13 @@ import { json as jsonLang } from "@codemirror/lang-json"; import type { ViewUpdate } from "@codemirror/view"; +import { CheckIcon, ClipboardIcon } from "@heroicons/react/20/solid"; import type { ReactCodeMirrorProps, UseCodeMirror } from "@uiw/react-codemirror"; import { useCodeMirror } from "@uiw/react-codemirror"; -import { useRef, useEffect, useCallback, useState } from "react"; -import { getEditorSetup } from "./codeMirrorSetup"; -import { darkTheme } from "./codeMirrorTheme"; +import { useCallback, useEffect, useRef, useState } from "react"; import { cn } from "~/utils/cn"; import { Button } from "../primitives/Buttons"; -import { CheckIcon, ClipboardDocumentCheckIcon, ClipboardIcon } from "@heroicons/react/20/solid"; +import { getEditorSetup } from "./codeMirrorSetup"; +import { darkTheme } from "./codeMirrorTheme"; export interface JSONEditorProps extends Omit { defaultValue?: string; @@ -117,7 +117,7 @@ export function JSONEditor(opts: JSONEditorProps) { onBlur(editor.current?.textContent ?? ""); }} /> -
+
{showClearButton && (
)} diff --git a/references/job-catalog/src/byo-auth.ts b/references/job-catalog/src/byo-auth.ts index e77786bb13..b739f69127 100644 --- a/references/job-catalog/src/byo-auth.ts +++ b/references/job-catalog/src/byo-auth.ts @@ -23,7 +23,7 @@ const stripe = new Stripe({ }); const slack = new Slack({ id: "slack" }); const openai = new OpenAI({ id: "openai" }); -const github = new Github({ id: "github" }); +const github = new Github({ id: "github-byoa" }); client.defineAuthResolver(resend, async (ctx, integration) => { return { From 9d028867bc64fe596a9ca7cf0ad279b5c13f5a92 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Thu, 5 Oct 2023 10:35:31 +0100 Subject: [PATCH 35/35] =?UTF-8?q?Fix=20for=20buttons=20going=20full=20widt?= =?UTF-8?q?h=20when=20they=20shouldn=E2=80=99t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/webapp/app/components/primitives/Buttons.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/components/primitives/Buttons.tsx b/apps/webapp/app/components/primitives/Buttons.tsx index 8912d0988d..e469c2561b 100644 --- a/apps/webapp/app/components/primitives/Buttons.tsx +++ b/apps/webapp/app/components/primitives/Buttons.tsx @@ -144,7 +144,7 @@ export function ButtonContent(props: ButtonContentPropsType) { const textColorClassName = variation.textColor; return ( -
+