From 2765fe12cdeb3c088eadf897a4a62c6028b25637 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Wed, 10 May 2023 08:44:41 +0100 Subject: [PATCH] Tidied up more old components --- apps/webapp/app/components/CopyTextButton.tsx | 2 +- apps/webapp/app/components/code/CodeBlock.tsx | 1 - .../components/integrations/ConnectButton.tsx | 2 +- .../app/components/primitives/Buttons.tsx | 4 +- .../components/{ => primitives}/CopyText.tsx | 6 +- .../app/components/primitives/Dialog.tsx | 189 +++++++++++------ .../{Icon.tsx => primitives/NamedIcon.tsx} | 0 .../app/components/primitives/Spinner.tsx | 4 +- .../{tutorial => primitives}/StepNumber.tsx | 0 .../webapp/app/components/primitives/Tabs.tsx | 173 +++++---------- .../app/components/primitives/Tooltip.tsx | 44 ++-- apps/webapp/app/components/runs/runStatus.tsx | 17 +- .../app/components/samples/custom-event.ts | 29 --- .../app/components/samples/github-issues.ts | 28 --- .../app/components/samples/github-stars.ts | 26 --- .../samples/new-user-slack-message.ts | 35 ---- .../samples/resend-email-drip-campaign.ts | 119 ----------- .../app/components/samples/samplesList.tsx | 135 ------------ .../app/components/samples/scheduled-cron.ts | 26 --- .../app/components/samples/scheduled.ts | 25 --- .../samples/shopify-create-new-product.ts | 63 ------ apps/webapp/app/components/samples/webhook.ts | 34 --- .../whatsapp-listen-for-message-and-reply.ts | 39 ---- .../app/components/templates/TemplateCard.tsx | 52 ----- .../components/templates/TemplateOverview.tsx | 149 ------------- .../components/templates/TemplatesData.tsx | 75 ------- .../components/templates/TemplatesGrid.tsx | 124 ----------- .../app/components/triggers/Trigger.tsx | 198 ------------------ .../app/components/triggers/TriggerIcons.tsx | 70 ------- .../app/components/triggers/triggerLabel.tsx | 23 -- .../$organizationSlug/__org/integrations.tsx | 2 +- apps/webapp/package.json | 3 + pnpm-lock.yaml | 104 ++++++++- 33 files changed, 324 insertions(+), 1477 deletions(-) rename apps/webapp/app/components/{ => primitives}/CopyText.tsx (80%) rename apps/webapp/app/components/{Icon.tsx => primitives/NamedIcon.tsx} (100%) rename apps/webapp/app/components/{tutorial => primitives}/StepNumber.tsx (100%) delete mode 100644 apps/webapp/app/components/samples/custom-event.ts delete mode 100644 apps/webapp/app/components/samples/github-issues.ts delete mode 100644 apps/webapp/app/components/samples/github-stars.ts delete mode 100644 apps/webapp/app/components/samples/new-user-slack-message.ts delete mode 100644 apps/webapp/app/components/samples/resend-email-drip-campaign.ts delete mode 100644 apps/webapp/app/components/samples/samplesList.tsx delete mode 100644 apps/webapp/app/components/samples/scheduled-cron.ts delete mode 100644 apps/webapp/app/components/samples/scheduled.ts delete mode 100644 apps/webapp/app/components/samples/shopify-create-new-product.ts delete mode 100644 apps/webapp/app/components/samples/webhook.ts delete mode 100644 apps/webapp/app/components/samples/whatsapp-listen-for-message-and-reply.ts delete mode 100644 apps/webapp/app/components/templates/TemplateCard.tsx delete mode 100644 apps/webapp/app/components/templates/TemplateOverview.tsx delete mode 100644 apps/webapp/app/components/templates/TemplatesData.tsx delete mode 100644 apps/webapp/app/components/templates/TemplatesGrid.tsx delete mode 100644 apps/webapp/app/components/triggers/Trigger.tsx delete mode 100644 apps/webapp/app/components/triggers/TriggerIcons.tsx delete mode 100644 apps/webapp/app/components/triggers/triggerLabel.tsx diff --git a/apps/webapp/app/components/CopyTextButton.tsx b/apps/webapp/app/components/CopyTextButton.tsx index 9706d5f43..58bc7762d 100644 --- a/apps/webapp/app/components/CopyTextButton.tsx +++ b/apps/webapp/app/components/CopyTextButton.tsx @@ -7,7 +7,7 @@ import { } from "@heroicons/react/24/outline"; import classNames from "classnames"; import { useCallback, useState } from "react"; -import { CopyText } from "./CopyText"; +import { CopyText } from "./primitives/CopyText"; import { TertiaryButton } from "./primitives/Buttons"; import { Body } from "./primitives/text/Body"; diff --git a/apps/webapp/app/components/code/CodeBlock.tsx b/apps/webapp/app/components/code/CodeBlock.tsx index 99da678fb..4e7fa5a8d 100644 --- a/apps/webapp/app/components/code/CodeBlock.tsx +++ b/apps/webapp/app/components/code/CodeBlock.tsx @@ -8,7 +8,6 @@ import "prismjs/components/prism-bash"; import "prismjs/plugins/line-numbers/prism-line-numbers"; import "prismjs/plugins/line-numbers/prism-line-numbers.css"; import { CopyTextButton } from "../CopyTextButton"; -import classNames from "classnames"; Prism.manual = true; diff --git a/apps/webapp/app/components/integrations/ConnectButton.tsx b/apps/webapp/app/components/integrations/ConnectButton.tsx index 962862b74..4da7d04c8 100644 --- a/apps/webapp/app/components/integrations/ConnectButton.tsx +++ b/apps/webapp/app/components/integrations/ConnectButton.tsx @@ -3,7 +3,7 @@ import classNames from "classnames"; import { useTypedFetcher } from "remix-typedjson"; import type { action } from "~/routes/resources/connection/oauth2"; import type { ExternalApi } from "~/services/externalApis/types"; -import { NamedIcon } from "../Icon"; +import { NamedIcon } from "../primitives/NamedIcon"; import { PrimaryButton } from "../primitives/Buttons"; import { Sheet, diff --git a/apps/webapp/app/components/primitives/Buttons.tsx b/apps/webapp/app/components/primitives/Buttons.tsx index 18e6fc2b0..905e4ca9c 100644 --- a/apps/webapp/app/components/primitives/Buttons.tsx +++ b/apps/webapp/app/components/primitives/Buttons.tsx @@ -26,11 +26,11 @@ const btnVariants = { const iconVariants = { size: { - // ExtraSmall: "h-3", + // extraSmall: "h-3", small: "h-4", medium: "h-4", large: "h-5", - // ExtraLarge: "h-6", + // extraLarge: "h-6", }, theme: { primary: "text-slate-900", diff --git a/apps/webapp/app/components/CopyText.tsx b/apps/webapp/app/components/primitives/CopyText.tsx similarity index 80% rename from apps/webapp/app/components/CopyText.tsx rename to apps/webapp/app/components/primitives/CopyText.tsx index 9987f6cde..6b6281e5a 100644 --- a/apps/webapp/app/components/CopyText.tsx +++ b/apps/webapp/app/components/primitives/CopyText.tsx @@ -14,7 +14,7 @@ export function CopyText({ onCopied, }: CopyTextProps) { const onClick = useCallback( - (event: React.MouseEvent) => { + (event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); navigator.clipboard.writeText(value); @@ -26,8 +26,8 @@ export function CopyText({ ); return ( -
+
+ ); } diff --git a/apps/webapp/app/components/primitives/Dialog.tsx b/apps/webapp/app/components/primitives/Dialog.tsx index b7c1b2214..d174ac0e5 100644 --- a/apps/webapp/app/components/primitives/Dialog.tsx +++ b/apps/webapp/app/components/primitives/Dialog.tsx @@ -1,66 +1,127 @@ -import { Dialog as HeadlessDialog, Transition } from "@headlessui/react"; -import { forwardRef, Fragment } from "react"; +"use client"; -type DialogProps = Parameters[0] & { - children: React.ReactNode; +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; +import { cn } from "~/utils/cn"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = ({ + className, + children, + ...props +}: DialogPrimitive.DialogPortalProps) => ( + +
+ {children} +
+
+); +DialogPortal.displayName = DialogPrimitive.Portal.displayName; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, }; - -//todo change to use ShadCn -function Dialog({ onClose, children, ...props }: DialogProps) { - return ( - - - -
- - -
-
- - {children} - -
-
- - - ); -} - -type PanelProps = Parameters[0]; -const Panel = forwardRef((props: PanelProps, ref) => ( - -)); -Panel.displayName = "Dialog.Panel"; - -type TitleProps = Parameters[0]; -const Title = forwardRef((props: TitleProps, ref) => ( - -)); -Title.displayName = "Dialog.Title"; - -export const StyledDialog = { Dialog, Panel, Title }; diff --git a/apps/webapp/app/components/Icon.tsx b/apps/webapp/app/components/primitives/NamedIcon.tsx similarity index 100% rename from apps/webapp/app/components/Icon.tsx rename to apps/webapp/app/components/primitives/NamedIcon.tsx diff --git a/apps/webapp/app/components/primitives/Spinner.tsx b/apps/webapp/app/components/primitives/Spinner.tsx index 2b713269a..b1e44d267 100644 --- a/apps/webapp/app/components/primitives/Spinner.tsx +++ b/apps/webapp/app/components/primitives/Spinner.tsx @@ -1,3 +1,5 @@ +import { cn } from "~/utils/cn"; + export function Spinner({ className }: { className?: string }) { return ( [0]; -type HeadlessTabListProps = Parameters[0]; +import * as React from "react"; +import * as TabsPrimitive from "@radix-ui/react-tabs"; +import { cn } from "~/utils/cn"; -export function ClassicList({ children, ...props }: HeadlessTabListProps) { - return ( - - {children} - - ); -} +const Tabs = TabsPrimitive.Root; -export function Classic({ children, ...props }: HeadlessTabProps) { - return ( - - classnames( - selected - ? "border-t border-slate-200 bg-white text-slate-600" - : "border-b border-t border-slate-200 bg-slate-50 text-slate-700 hover:border-slate-200 hover:text-slate-800", - "flex whitespace-nowrap border-r py-3 px-3 text-xs focus:outline-none" - ) - } - {...props} - > - {children} - - ); -} +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsList.displayName = TabsPrimitive.List.displayName; -export function UnderlinedList({ children, ...props }: HeadlessTabListProps) { - return ( - - {children} - - ); -} +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; -export function Underlined({ children, ...props }: HeadlessTabProps) { - return ( - - classnames( - selected - ? "border-slate-300 text-slate-300 outline-none" - : "border-transparent text-slate-400 hover:border-slate-200 hover:text-slate-200", - "disabled:text-slate-300 disabled:hover:border-transparent", - "flex whitespace-nowrap border-b-2 py-2 px-4 text-base font-medium transition" - ) - } - {...props} - > - {children} - - ); -} +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsContent.displayName = TabsPrimitive.Content.displayName; -export function SegmentedList({ - children, - className, - ...props -}: HeadlessTabListProps) { - return ( - - {children} - - ); -} - -export function Segmented({ children, ...props }: HeadlessTabProps) { - return ( - - classnames( - selected - ? "rounded bg-indigo-600 text-white shadow outline-none" - : "rounded text-slate-300 transition hover:bg-slate-700 hover:text-slate-300 hover:shadow-none", - "flex whitespace-nowrap py-2 px-4 text-xs font-medium" - ) - } - {...props} - > - {children} - - ); -} - -export function LargeBoxList({ - children, - className, - ...props -}: HeadlessTabListProps) { - return ( - - {children} - - ); -} - -export function LargeBox({ children, ...props }: HeadlessTabProps) { - return ( - - classnames( - selected - ? "bg-slate-800 text-white shadow outline-none" - : "text-slate-300 transition hover:bg-slate-800/50 hover:text-slate-300 hover:shadow-none", - "flex flex-col items-center justify-center gap-4 rounded border border-slate-700 py-6 px-4 text-base font-medium" - ) - } - {...props} - > - {children} - - ); -} +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/apps/webapp/app/components/primitives/Tooltip.tsx b/apps/webapp/app/components/primitives/Tooltip.tsx index fabec79f8..9f29b115a 100644 --- a/apps/webapp/app/components/primitives/Tooltip.tsx +++ b/apps/webapp/app/components/primitives/Tooltip.tsx @@ -1,21 +1,29 @@ -import classNames from "classnames"; -import React, { memo } from "react"; +"use client"; -export type TooltipProps = { - children: React.ReactNode; - text: string; - className?: string; -}; +import * as React from "react"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import { cn } from "~/utils/cn"; -export const Tooltip: React.FC = memo((props) => { - return ( - - - {props.text} - - {props.children} - - ); -}); +const TooltipProvider = TooltipPrimitive.Provider; -Tooltip.displayName = "Tooltip"; +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/apps/webapp/app/components/runs/runStatus.tsx b/apps/webapp/app/components/runs/runStatus.tsx index 7f2c66de4..f5e55fa82 100644 --- a/apps/webapp/app/components/runs/runStatus.tsx +++ b/apps/webapp/app/components/runs/runStatus.tsx @@ -4,10 +4,9 @@ import { CheckCircleIcon, ExclamationTriangleIcon, } from "@heroicons/react/24/solid"; -import classNames from "classnames"; import type { ReactNode } from "react"; -import type { WorkflowRunStatus } from "~/models/workflowRun.server"; import { Spinner } from "../primitives/Spinner"; +import { cn } from "~/utils/cn"; export function runStatusTitle(status: WorkflowRunStatus): string { switch (status) { @@ -53,7 +52,7 @@ export function runStatusIcon( case "SUCCESS": return ( ); case "DISCONNECTED": return ( { - //insert your code here - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/github-issues.ts b/apps/webapp/app/components/samples/github-issues.ts deleted file mode 100644 index f0e2ba109..000000000 --- a/apps/webapp/app/components/samples/github-issues.ts +++ /dev/null @@ -1,28 +0,0 @@ -export function githubIssues(apiKey: string) { - return `import { Trigger } from "@trigger.dev/sdk"; -import * as github from "@trigger.dev/github"; -import * as slack from "@trigger.dev/slack"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "github-issues-to-slack", - name: "Posts to Slack when a GitHub Issue created or modified", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - on: github.events.issueEvent({ - //todo set your repo here - repo: "my-github-org/my-github-repo", - }), - run: async (event, ctx) => { - //we post a Slack message - const response = await slack.postMessage("send-to-slack", { - //todo set your Slack channel name here - channelName: "my-slack-channel-name", - text: \`A new issue has been created or modified. \${event.action}\`, - }); - - return response.message; - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/github-stars.ts b/apps/webapp/app/components/samples/github-stars.ts deleted file mode 100644 index 81141d194..000000000 --- a/apps/webapp/app/components/samples/github-stars.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function githubStars(apiKey: string) { - return `import { Trigger } from "@trigger.dev/sdk"; -import * as github from "@trigger.dev/github"; -import * as slack from "@trigger.dev/slack"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "new-github-star-to-slack", - name: "New GitHub Star: triggerdotdev/trigger.dev", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - on: github.events.newStarEvent({ - //todo set your repo here - repo: "triggerdotdev/trigger.dev", - }), - run: async (event) => { - //we post a Slack message - await slack.postMessage("github-stars", { - //todo set your Slack channel name here - channelName: "github-stars", - text: \`New GitHub star from \n<\${event.sender.html_url}|\${event.sender.login}>\`, - }); - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/new-user-slack-message.ts b/apps/webapp/app/components/samples/new-user-slack-message.ts deleted file mode 100644 index e15daedcf..000000000 --- a/apps/webapp/app/components/samples/new-user-slack-message.ts +++ /dev/null @@ -1,35 +0,0 @@ -export function newUserSlackMessage(apiKey: string) { - return `import { Trigger, customEvent } from "@trigger.dev/sdk"; -import { postMessage } from "@trigger.dev/slack"; -import { z } from "zod"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "new-user", - name: "New user slack message", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - on: customEvent({ - name: "user.created", - schema: z.object({ - name: z.string(), - email: z.string(), - paidPlan: z.boolean(), - }), - }), - run: async (event, ctx) => { - await ctx.logger.info("This log will appear on the Trigger.dev run page"); - - //send a message to the #new-users Slack channel with user details - const response = await postMessage("send-to-slack", { - channelName: "new-users", - text: \`New user: \${event.name} (\${event.email}) signed up. \${ - event.paidPlan ? "They are paying" : "They are on the free plan" - }.\`, - }); - - return response.message; - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/resend-email-drip-campaign.ts b/apps/webapp/app/components/samples/resend-email-drip-campaign.ts deleted file mode 100644 index c59de5660..000000000 --- a/apps/webapp/app/components/samples/resend-email-drip-campaign.ts +++ /dev/null @@ -1,119 +0,0 @@ -export function resendEmailDripCampaign(apiKey: string) { - return `import { customEvent, Trigger } from "@trigger.dev/sdk"; -import * as resend from "@trigger.dev/resend"; -import * as slack from "@trigger.dev/slack"; -import { Html } from "@react-email/html"; -import { Preview } from "@react-email/preview"; -import { Section } from "@react-email/section"; -import { Text } from "@react-email/text"; -import { z } from "zod"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "welcome-email-campaign", - name: "Welcome email drip campaign", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - on: customEvent({ - name: "user.created", - schema: z.object({ - userId: z.string(), - }), - }), - async run(event, context) { - //get the user data from the database - const user = await getUser(event.userId); - - await slack.postMessage("send-to-slack", { - channelName: "new-users", - text: \`New user signed up: \${user.name} (\${user.email})\`, - }); - - //Send the first email - const welcomeResponse = await resend.sendEmail("welcome-email", { - from: "Trigger.dev ", - replyTo: "James ", - to: user.email, - subject: "Welcome to Trigger.dev", - react: , - }); - await context.logger.debug( - \`Sent welcome email to \${welcomeResponse.to} with id \${welcomeResponse.id} - \` - ); - - //wait 1 day, check if the user has created a workflow and send the appropriate email - await context.waitFor("wait-a-while", { days: 1 }); - const updatedUser = await getUser(event.userId); - - if (updatedUser.hasOnboarded) { - await resend.sendEmail("onboarding-complete", { - from: "Trigger.dev ", - replyTo: "James ", - to: updatedUser.email, - subject: "Pro tips for workflows", - react: , - }); - } else { - await resend.sendEmail("onboarding-incomplete", { - from: "Trigger.dev ", - replyTo: "James ", - to: updatedUser.email, - subject: "Help with your first workflow", - react: , - }); - } - }, -}).listen(); - -function WelcomeEmail({ name }: { name?: string }) { - return ( - - This is the text that appears in the inbox list -
- Hey {name ?? "there"}, - Your message goes here. -
- - ); -} - -function TipsEmail({ name }: { name: string }) { - return ( - - This is the text that appears in the inbox list -
- Hi {name ?? "there"}, - - Tips content goes here - -
- - ); -} - -function InactiveEmail({ name }: { name: string }) { - return ( - - This is the text that appears in the inbox list -
- Hi {name ?? "there"}, - - Re-engagement content goes here - -
- - ); -} - -//This file is a mock database, in your real app you would access your real database from inside these functions -async function getUser(userId: string, hasOnboarded = false) { - return { - id: userId, - name: "Matt Aitken", - email: "matt@trigger.dev", - hasOnboarded, - }; -}`; -} diff --git a/apps/webapp/app/components/samples/samplesList.tsx b/apps/webapp/app/components/samples/samplesList.tsx deleted file mode 100644 index cdcf5b5b5..000000000 --- a/apps/webapp/app/components/samples/samplesList.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { - StarIcon, - ShoppingCartIcon, - ChatBubbleOvalLeftEllipsisIcon, - UserIcon, - DocumentTextIcon, -} from "@heroicons/react/24/outline"; -import { customEvent } from "./custom-event"; -import { githubIssues } from "./github-issues"; -import { githubStars } from "./github-stars"; -import { newUserSlackMessage } from "./new-user-slack-message"; -import { shopifyCreateNewProducts } from "./shopify-create-new-product"; -import { webhook } from "./webhook"; -import { scheduled } from "./scheduled"; -import { whatsappListenForMessageAndReply } from "./whatsapp-listen-for-message-and-reply"; -import { scheduledCron } from "./scheduled-cron"; - -export type ExampleProject = { - name: string; - title?: string; - icon?: React.ReactNode; - docsLink?: string; - description: string; - requiredPackages: string; - code: (apiKey: string) => string; - packagesCopy?: string; - bulletPoints?: string[]; - type: "example" | "from-scratch" | "blank"; -}; - -export const allExamples: ExampleProject[] = [ - { - icon: , - name: "GitHub star → Slack", - title: "When you receive a GitHub star, post that user's details to Slack", - description: - "This workflow is triggered when a GitHub user adds a star to a repository. The user's details will then be posted in a specific Slack channel.", - requiredPackages: "@trigger.dev/sdk @trigger.dev/github @trigger.dev/slack", - code: githubStars, - type: "example", - }, - { - icon: , - name: "New user → Slack", - title: "When a new user signs up, post a message to Slack", - description: - "This workflow is triggered when a new user signs up. The user's details will then be posted in a specific Slack channel.", - requiredPackages: "@trigger.dev/sdk @trigger.dev/slack zod", - code: newUserSlackMessage, - type: "example", - }, - - { - icon: , - name: "New item → Shopify", - title: "When a custom event is triggered, create a new product in Shopify", - description: - "This workflow is triggered by a custom event. Once it is triggered, a new product is created in Shopify with the specified details.", - requiredPackages: "@trigger.dev/sdk @trigger.dev/shopify zod", - code: shopifyCreateNewProducts, - packagesCopy: "Shopify", - type: "example", - }, - { - icon: , - name: "GitHub issue → Slack", - title: "When a GitHub issue is created or modified, post it to Slack", - description: - "This workflow is triggered when a new issue is created or modified in GitHub. The issue will then be posted in a specific Slack channel.", - requiredPackages: "@trigger.dev/sdk @trigger.dev/github @trigger.dev/slack", - code: githubIssues, - type: "example", - }, - - { - icon: , - name: "WhatsApp → WhatsApp", - title: "Listen for WhatsApp messages and automatically reply", - description: - "This workflow is triggered when a WhatsApp message has been received. When received, a pre-determined reply is sent.", - requiredPackages: "@trigger.dev/sdk @trigger.dev/whatsapp", - code: whatsappListenForMessageAndReply, - packagesCopy: "WhatsApp", - type: "example", - }, - { - name: "Webhook", - requiredPackages: "@trigger.dev/sdk zod", - code: webhook, - docsLink: "https://docs.trigger.dev/triggers/webhooks", - description: - "Webhooks allow you to subscribe to events from APIs but can be difficult to work with, especially when developing locally. Trigger.dev makes using webhooks easy:", - bulletPoints: [ - "You don’t need to register/unregister for webhooks, we do it for you.", - "They work locally during development without needing to use tunnels (e.g. Ngrok).", - "We receive the webhook, then keep trying to send it to you until you receive it. If your server goes down, no problem.", - ], - type: "from-scratch", - }, - { - name: "Custom event", - requiredPackages: "@trigger.dev/sdk zod", - code: customEvent, - docsLink: "https://docs.trigger.dev/triggers/custom-events", - description: - "Custom event triggers allow you to run workflows from your own code (or your other workflows). Send an event and any workflows that subscribe to that custom event will get triggered. You can easily send an event from anywhere, including from inside another workflow. Events don’t have to come from the same server as your workflow and can be sent as HTTP requests from any language.", - type: "from-scratch", - }, - { - name: "Scheduled (recurring)", - requiredPackages: "@trigger.dev/sdk", - code: scheduled, - docsLink: "https://docs.trigger.dev/triggers/scheduled", - description: - "Run a workflow on a recurring schedule. The example below will run every 5 minutes, starting 5 minutes after this code is first run on your server (that includes running locally).", - type: "from-scratch", - }, - { - name: "Scheduled (CRON)", - requiredPackages: "@trigger.dev/sdk", - code: scheduledCron, - docsLink: "https://docs.trigger.dev/triggers/scheduled", - description: - "Run a workflow on a recurring schedule. The example job below will run at 2:30pm every Monday.", - type: "from-scratch", - }, -]; - -export const exampleProjects = allExamples.filter( - (example) => example.type === "example" -); - -export const fromScratchProjects = allExamples.filter( - (example) => example.type === "from-scratch" -); diff --git a/apps/webapp/app/components/samples/scheduled-cron.ts b/apps/webapp/app/components/samples/scheduled-cron.ts deleted file mode 100644 index 7ce6148af..000000000 --- a/apps/webapp/app/components/samples/scheduled-cron.ts +++ /dev/null @@ -1,26 +0,0 @@ -export function scheduledCron(apiKey: string) { - return `import { Trigger, scheduleEvent } from "@trigger.dev/sdk"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "cron-scheduled-workflow", - name: "Cron Scheduled Workflow", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - //todo set your CRON expression here - //this example runs every Monday at 2:30pm UTC - //this site is useful when writing CRON: https://crontab.guru - //you don't have to wait to test, use our "Test" button on your workflow page - on: scheduleEvent({ cron: "30 14 * * 1" }), - run: async (event, ctx) => { - //this function is run every Monday at 2:30pm UTC - await ctx.logger.info("Received the cron scheduled event", { - event, - wallTime: new Date(), - }); - - return { foo: "bar" }; - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/scheduled.ts b/apps/webapp/app/components/samples/scheduled.ts deleted file mode 100644 index 058476094..000000000 --- a/apps/webapp/app/components/samples/scheduled.ts +++ /dev/null @@ -1,25 +0,0 @@ -export function scheduled(apiKey: string) { - return `import { Trigger, scheduleEvent } from "@trigger.dev/sdk"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "scheduled-workflow", - name: "Scheduled Workflow", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - //todo set how often you want your event to fire here - //this example runs every 5 minutes, the first run will be 5 minutes after the workflow is first connected - //you don't have to wait to test, use our "Test" button on your workflow page - on: scheduleEvent({ rateOf: { minutes: 5 } }), - run: async (event, ctx) => { - //this function is run every 5 minutes - await ctx.logger.info("Received the scheduled event", { - event, - wallTime: new Date(), - }); - - return { foo: "bar" }; - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/shopify-create-new-product.ts b/apps/webapp/app/components/samples/shopify-create-new-product.ts deleted file mode 100644 index 6c81fb4a3..000000000 --- a/apps/webapp/app/components/samples/shopify-create-new-product.ts +++ /dev/null @@ -1,63 +0,0 @@ -export function shopifyCreateNewProducts(apiKey: string) { - return `import { Trigger, customEvent } from "@trigger.dev/sdk"; -import { z } from "zod"; -import * as shopify from "@trigger.dev/shopify"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "shopify-products", - name: "Shopify products", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - //todo define the schema for the events you want to receive - //this example accepts an empty JSON object: {} - //you can use z.any() to accept any JSON, but you won't get nice types in the run function - on: customEvent({ - name: "shopify.products", - schema: z.object({}), - }), - run: async (event, ctx) => { - //this creates a new product in your Shopify store, with a variant - const newProduct = await shopify.createProduct("create-product", { - descriptionHtml: "This is my brilliant product description.", - title: \`Fantastic product \${Math.floor(Math.random() * 1000)}\`, - productType: "t-shirt", - vendor: "Nike", - options: ["Color", "Size"], - standardizedProductType: { - //you may need to update this to match your store's product taxonomy - productTaxonomyNodeId: "gid://shopify/ProductTaxonomyNode/352", - }, - variants: [ - { - price: "99.99", - sku: "variant-1", - inventoryItem: { - tracked: true, - }, - options: ["Maroon", "Tiny"], - }, - ], - }); - - //we add two images to the product - const newImages = await shopify.appendProductImages("append-images", { - id: newProduct.id, - images: [ - { - src: "https://via.placeholder.com/600/92c952.png", - altText: "Image 1", - }, - { - src: "https://via.placeholder.com/600/d32776.png", - altText: "Image 2", - }, - ], - }); - - return newProduct; - }, -}).listen(); -`; -} diff --git a/apps/webapp/app/components/samples/webhook.ts b/apps/webapp/app/components/samples/webhook.ts deleted file mode 100644 index d902dd49f..000000000 --- a/apps/webapp/app/components/samples/webhook.ts +++ /dev/null @@ -1,34 +0,0 @@ -export function webhook(apiKey: string) { - return `import { webhookEvent, Trigger } from "@trigger.dev/sdk"; -import { z } from "zod"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "caldotcom-to-slack", - name: "Cal.com To Slack", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - //todo setup your custom webhook. - //we have integrations that make this much easier for supported APIs - on: webhookEvent({ - service: "cal.com", - //the name of the event you want to subscribe for - eventName: "BOOKING_CREATED", - filter: { - triggerEvent: ["BOOKING_CREATED"], - }, - //you can define a schema to validate the payload, and have nice types in the run function - //here we use z.any() to accept any payload - schema: z.any(), - //some webhooks are signed, set the header name and we'll verify the signature for you - verifyPayload: { - enabled: true, - header: "X-Cal-Signature-256", - }, - }), - run: async (event, ctx) => { - //insert your code here - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/samples/whatsapp-listen-for-message-and-reply.ts b/apps/webapp/app/components/samples/whatsapp-listen-for-message-and-reply.ts deleted file mode 100644 index 9fea54ab3..000000000 --- a/apps/webapp/app/components/samples/whatsapp-listen-for-message-and-reply.ts +++ /dev/null @@ -1,39 +0,0 @@ -export function whatsappListenForMessageAndReply(apiKey: string) { - return `import { Trigger } from "@trigger.dev/sdk"; -import { events, sendReaction, sendText } from "@trigger.dev/whatsapp"; - -new Trigger({ - //todo: ensure this id is only used for this workflow - id: "whatsapp-webhook", - name: "Listen for WhatsApp messages and reply", - // For security, we recommend moving this api key to your .env / secrets file. - // Our env variable is called TRIGGER_API_KEY - apiKey: "${apiKey}", - //todo you need put in your WhatsApp Business account ID - on: events.messageEvent({ - accountId: "", - }), - run: async (event, ctx) => { - //these logs will appear on the run page - await ctx.logger.info(\`Message data\`, event.message); - await ctx.logger.info(\`Phone number\`, event.contacts[0]); - - //add a 🥰 reaction to the original message - const reactionResponse = await sendReaction("reaction", { - fromId: event.metadata.phone_number_id, - to: event.message.from, - isReplyTo: event.message.id, - emoji: "🥰", - }); - - //send a text message in response - const textResponse = await sendText("text-msg", { - fromId: event.metadata.phone_number_id, - to: event.message.from, - text: "Hello! This is a text sent automatically from https://www.trigger.dev", - }); - - //we support all other types of WhatsApp messages (audio, video, document, location, etc) - }, -}).listen();`; -} diff --git a/apps/webapp/app/components/templates/TemplateCard.tsx b/apps/webapp/app/components/templates/TemplateCard.tsx deleted file mode 100644 index 9177ba1e7..000000000 --- a/apps/webapp/app/components/templates/TemplateCard.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import classNames from "classnames"; -import type { TemplateListItem } from "~/presenters/templateListPresenter.server"; -import { ApiLogoIcon } from "../code/ApiLogoIcon"; -import { Body } from "../primitives/text/Body"; -import { Header1 } from "../primitives/Headers"; - -export function TemplateCard({ - template, - className, -}: { - template: TemplateListItem; - className?: string; -}) { - return ( -
-
- {template.shortTitle} -
-
-
- - {template.title} - - - {template.description} - -
-
- {template.services.map((service) => ( -
- -
- ))} -
-
-
- ); -} diff --git a/apps/webapp/app/components/templates/TemplateOverview.tsx b/apps/webapp/app/components/templates/TemplateOverview.tsx deleted file mode 100644 index 2429303e5..000000000 --- a/apps/webapp/app/components/templates/TemplateOverview.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline"; -import classNames from "classnames"; -import { Fragment } from "react"; -import type { TemplateListItem } from "~/presenters/templateListPresenter.server"; -import { ApiLogoIcon } from "../code/ApiLogoIcon"; -import { CopyTextPanel } from "../CopyTextButton"; -import { SecondaryA } from "../primitives/Buttons"; -import { Body } from "../primitives/text/Body"; -import { Header1 } from "../primitives/Headers"; - -export function TemplateOverview({ - template, - className, - commandFlags, -}: { - template: TemplateListItem; - className?: string; - commandFlags?: string; -}) { - const { docsHTML, imageUrl } = template; - - return ( -
-
- -
-
-
- Template hero -
- -
-
-
-
-
- ); -} - -function TemplateDetails({ - className, - template, - commandFlags, -}: { - className?: string; - template: TemplateListItem; - commandFlags?: string; -}) { - const { title, description, repositoryUrl, id } = template; - return ( -
- - {title} - - {description} - {template.services.length != 0 ? ( - <> -
- - Integrations - -
-
-
- {template.services.map((service) => ( - - - - ))} -
- - ) : ( - <> - )} -
- - Help and guides - -
-
-
- - View Repo - - - - View Docs - - -
-
- - Get started - -
-
- - Run this command in your terminal to create a new project using this - template. - - -
- ); -} diff --git a/apps/webapp/app/components/templates/TemplatesData.tsx b/apps/webapp/app/components/templates/TemplatesData.tsx deleted file mode 100644 index 069cdabbb..000000000 --- a/apps/webapp/app/components/templates/TemplatesData.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import GitHubStarsTemplateBg from "../../../public/images/templates/github-stars-template-bg.png"; -import ResendSlackTemplateBg from "../../../public/images/templates/resend-slack-template-bg.png"; -import ShopifyTemplateBg from "../../../public/images/templates/shopify-template-bg.png"; - -export type TemplateData = { - title: string; - shortTitle: string; - description: string; - imageURL: string; - githubRepoURL: string; - services: string[]; - documentation?: string; -}; - -export const templateData = [ - { - title: "Slack notifications when a GitHub repo is starred", - shortTitle: "GitHub stars to Slack", - description: - "When a GitHub repo is starred, post information about the user to Slack", - imageURL: GitHubStarsTemplateBg, - githubRepoURL: "repo-url", - services: ["slack", "github"], - documentation: ` - ### 🚀 Installation - -Download the Mintlify CLI using the following command - -\`\`\` -npm i -g mintlify -\`\`\` - -### 👩‍💻 Development - -Run the following command at the root of your Mintlify application to preview changes locally. - -\`\`\` -mintlify dev -\`\`\` - -Note - \`mintlify dev\` requires \`yarn\` and it's recommended you install it as a global installation. If you don't have yarn installed already run \`npm install --global yarn\` in your terminal. - -### Custom Ports - -Mintlify uses port 3000 by default. You can use the \`--port\` flag to customize the port Mintlify runs on. For example, use this command to run in port 3333: - -\`\`\` -mintlify dev --port 3333 -\`\`\` - -You will see an error like this if you try to run Mintlify in a port that's already taken: - -\`\`\` -Error: listen EADDRINUSE: address already in use :::3000 -\`\`\` - - ` - }, - { - title: "New user welcome email drip campaign", - shortTitle: "GitHub stars to Slack", - description: "Create a welcome email drip campaign using Slack and Resend", - imageURL: ResendSlackTemplateBg, - githubRepoURL: "repo-url", - services: ["slack", "github"], - }, - { - title: "Add a new product to Shopify", - shortTitle: "GitHub stars to Slack", - description: "Add a new product to Shopify", - imageURL: ShopifyTemplateBg, - githubRepoURL: "repo-url", - services: ["slack", "github"], - }, -]; diff --git a/apps/webapp/app/components/templates/TemplatesGrid.tsx b/apps/webapp/app/components/templates/TemplatesGrid.tsx deleted file mode 100644 index f12cc0637..000000000 --- a/apps/webapp/app/components/templates/TemplatesGrid.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { XMarkIcon } from "@heroicons/react/24/outline"; -import { Link } from "@remix-run/react"; -import classNames from "classnames"; -import { Fragment, useState } from "react"; -import type { TemplateListItem } from "~/presenters/templateListPresenter.server"; -import { CopyTextPanel } from "../CopyTextButton"; -import { StyledDialog } from "../primitives/Dialog"; -import { Header1 } from "../primitives/Headers"; -import { TemplateOverview } from "./TemplateOverview"; - -export function TemplatesGrid({ - templates, - openInNewPage, - commandFlags, -}: { - templates: Array; - openInNewPage: boolean; - commandFlags?: string; -}) { - const [openedTemplate, setOpenedTemplate] = useState( - null - ); - const isOpen = openedTemplate !== null; - - return ( - <> - setOpenedTemplate(null)} - appear - show={isOpen} - as={Fragment} - > - - {openedTemplate && ( - - )} - - - -
- {templates.map((template) => { - return ( - setOpenedTemplate(template)} - className="p-5" - > -
- {template.title} -
-
- - {template.title} - - -
-
- ); - })} -
- - ); -} - -function TemplateButtonOrLink({ - template, - openInNewPage, - onClick, - children, - className, -}: { - template: TemplateListItem; - openInNewPage: boolean; - onClick: (e: React.MouseEvent) => void; - children: React.ReactNode; - className?: string; -}) { - const cardStyles = - "group flex w-full p-5 flex-col self-stretch overflow-hidden rounded-md border border-slate-700/70 bg-slate-800 text-left text-slate-200 shadow-md transition hover:cursor-pointer hover:border-slate-600 hover:bg-slate-700/50 disabled:opacity-50"; - - if (openInNewPage) { - return ( - - {children} - - ); - } else { - return ( - - ); - } -} diff --git a/apps/webapp/app/components/triggers/Trigger.tsx b/apps/webapp/app/components/triggers/Trigger.tsx deleted file mode 100644 index 2c7ebbdf3..000000000 --- a/apps/webapp/app/components/triggers/Trigger.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import type { - CustomEventTrigger, - ScheduledEventTrigger, - ScheduleSourceCron, - ScheduleSourceRate, - SlackInteractionEventTrigger, - TriggerMetadata, - WebhookEventTrigger, -} from "@trigger.dev/internal"; -import { Body } from "../primitives/text/Body"; -import { Header2 } from "../primitives/Headers"; -import cronstrue from "cronstrue"; - -export function TriggerBody({ trigger }: { trigger: TriggerMetadata }) { - switch (trigger.type) { - case "WEBHOOK": - return ; - case "SCHEDULE": - return ; - case "CUSTOM_EVENT": - return ; - case "HTTP_ENDPOINT": - break; - case "SLACK_INTERACTION": - return ; - default: - break; - } - return <>; -} - -const workflowNodeUppercaseClasses = "uppercase text-slate-400 tracking-wide"; - -function SlackInteraction({ - trigger, -}: { - trigger: SlackInteractionEventTrigger; -}) { - return ( -
-
- - Name - - - {trigger.name} - -
- {trigger.source.type === "block_action" && ( -
- - Block - - - {trigger.source.blockId} - -
- )} - {trigger.source.type === "block_action" && ( -
- - Action - - - {trigger.source.actionIds.join(", ")} - -
- )} - {trigger.source.type === "view_submission" && ( -
- - Callback IDs - - - {trigger.source.callbackIds.join(", ")} - -
- )} -
- ); -} - -// trigger.source.actionIds; - -function Webhook({ webhook }: { webhook: WebhookEventTrigger }) { - return ( - <> - - {webhook.name} - -
- {webhook.source && - !webhook.manualRegistration && - Object.entries(webhook.source).map(([key, value]) => ( -
- - {key} - - {value} -
- ))} -
- - ); -} - -function CustomEvent({ event }: { event: CustomEventTrigger }) { - return ( - <> - - Name - - - {event.name} - - - ); -} - -function Scheduled({ event }: { event: ScheduledEventTrigger }) { - return ( - <> -
- {"rateOf" in event.source ? ( - - ) : ( - - )} -
- - ); -} - -function RateOfScheduled({ source }: { source: ScheduleSourceRate }) { - const unit = - "minutes" in source.rateOf - ? source.rateOf.minutes > 1 - ? "minutes" - : "minute" - : "hours" in source.rateOf - ? source.rateOf.hours > 1 - ? "hours" - : "hour" - : source.rateOf.days > 1 - ? "days" - : "day"; - - const value = - "minutes" in source.rateOf - ? source.rateOf.minutes - : "hours" in source.rateOf - ? source.rateOf.hours - : source.rateOf.days; - - return ( -
- - Runs - - - Every {value} {unit} - -
- ); -} - -function AtScheduled({ source }: { source: ScheduleSourceCron }) { - return ( -
-
- - Runs - - - {cronstrue.toString(source.cron, { - throwExceptionOnParseError: false, - verbose: false, - use24HourTimeFormat: true, - })} - -
-
- - Cron expression - - - {source.cron} - -
-
- ); -} diff --git a/apps/webapp/app/components/triggers/TriggerIcons.tsx b/apps/webapp/app/components/triggers/TriggerIcons.tsx deleted file mode 100644 index 3f70fa0bb..000000000 --- a/apps/webapp/app/components/triggers/TriggerIcons.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { ApiLogoIcon } from "../code/ApiLogoIcon"; -import CustomEvent from "../../assets/images/triggers/custom-event.png"; -import HttpEndpoint from "../../assets/images/triggers/http-endpoint.png"; -import Schedule from "../../assets/images/triggers/schedule.png"; -import Webhook from "../../assets/images/triggers/webhook.png"; -import SlackInteraction from "../../assets/images/triggers/slack-interaction.png"; -import { triggerLabel } from "./triggerLabel"; - -type TriggerType = - | "CUSTOM_EVENT" - | "HTTP_ENDPOINT" - | "SCHEDULE" - | "WEBHOOK" - | "SLACK_INTERACTION"; - -const iconClasses = "h-full w-full"; - -export function TriggerTypeIcon({ - type, - provider, -}: { - type: TriggerType; - provider?: { icon: string; name: string }; -}) { - if (provider) { - return ( - - ); - } - switch (type) { - case "CUSTOM_EVENT": - return ( - {triggerLabel(type)} - ); - case "HTTP_ENDPOINT": - return ( - {triggerLabel(type)} - ); - case "SCHEDULE": - return ( - {triggerLabel(type)} - ); - case "WEBHOOK": - return ( - {triggerLabel(type)} - ); - case "SLACK_INTERACTION": - return ( - {triggerLabel(type)} - ); - default: - return null; - } -} diff --git a/apps/webapp/app/components/triggers/triggerLabel.tsx b/apps/webapp/app/components/triggers/triggerLabel.tsx deleted file mode 100644 index d092f472c..000000000 --- a/apps/webapp/app/components/triggers/triggerLabel.tsx +++ /dev/null @@ -1,23 +0,0 @@ -type TriggerType = - | "CUSTOM_EVENT" - | "HTTP_ENDPOINT" - | "SCHEDULE" - | "WEBHOOK" - | "SLACK_INTERACTION"; - -export function triggerLabel(type: TriggerType) { - switch (type) { - case "CUSTOM_EVENT": - return "Custom event"; - case "WEBHOOK": - return "Webhook"; - case "HTTP_ENDPOINT": - return "HTTP endpoint"; - case "SCHEDULE": - return "Scheduled"; - case "SLACK_INTERACTION": - return "Slack interaction"; - default: - return type; - } -} diff --git a/apps/webapp/app/routes/__app/orgs/$organizationSlug/__org/integrations.tsx b/apps/webapp/app/routes/__app/orgs/$organizationSlug/__org/integrations.tsx index a77e648bf..66baa874e 100644 --- a/apps/webapp/app/routes/__app/orgs/$organizationSlug/__org/integrations.tsx +++ b/apps/webapp/app/routes/__app/orgs/$organizationSlug/__org/integrations.tsx @@ -3,7 +3,7 @@ import type { LoaderArgs } from "@remix-run/server-runtime"; import { SliderButton } from "@typeform/embed-react"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import invariant from "tiny-invariant"; -import { NamedIcon, NamedIconInBox } from "~/components/Icon"; +import { NamedIcon, NamedIconInBox } from "~/components/primitives/NamedIcon"; import { ConnectButton } from "~/components/integrations/ConnectButton"; import { AppBody, AppLayoutTwoCol } from "~/components/layout/AppLayout"; import { Container } from "~/components/layout/Container"; diff --git a/apps/webapp/package.json b/apps/webapp/package.json index d20b778e3..305e7449d 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -48,6 +48,7 @@ "@aws-sdk/s3-request-presigner": "^3.186.0", "@cakework/client": "^0.0.54", "@cfworker/json-schema": "^1.12.5", + "@code-hike/mdx": "^0.8.3", "@codemirror/autocomplete": "^6.3.1", "@codemirror/commands": "^6.1.2", "@codemirror/lang-javascript": "^6.1.1", @@ -70,6 +71,8 @@ "@radix-ui/react-label": "^2.0.1", "@radix-ui/react-popover": "^1.0.5", "@radix-ui/react-select": "^1.2.1", + "@radix-ui/react-tabs": "^1.0.3", + "@radix-ui/react-tooltip": "^1.0.5", "@react-email/head": "^0.0.2", "@remix-run/express": "v1.11.0", "@remix-run/node": "v1.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d767d75a0..ff6ef936f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,6 +46,7 @@ importers: '@babel/preset-typescript': ^7.21.4 '@cakework/client': ^0.0.54 '@cfworker/json-schema': ^1.12.5 + '@code-hike/mdx': ^0.8.3 '@codemirror/autocomplete': ^6.3.1 '@codemirror/commands': ^6.1.2 '@codemirror/lang-javascript': ^6.1.1 @@ -71,6 +72,8 @@ importers: '@radix-ui/react-label': ^2.0.1 '@radix-ui/react-popover': ^1.0.5 '@radix-ui/react-select': ^1.2.1 + '@radix-ui/react-tabs': ^1.0.3 + '@radix-ui/react-tooltip': ^1.0.5 '@react-email/head': ^0.0.2 '@remix-run/dev': v1.11.0 '@remix-run/eslint-config': v1.11.0 @@ -231,6 +234,7 @@ importers: '@aws-sdk/s3-request-presigner': 3.245.0 '@cakework/client': 0.0.54 '@cfworker/json-schema': 1.12.5 + '@code-hike/mdx': 0.8.3_react@18.2.0 '@codemirror/autocomplete': 6.4.0_eo6pz6bvsllvatnnwfprpuflde '@codemirror/commands': 6.1.3 '@codemirror/lang-javascript': 6.1.2 @@ -253,6 +257,8 @@ importers: '@radix-ui/react-label': 2.0.1_biqbaboplfbrettd7655fr4n2y '@radix-ui/react-popover': 1.0.5_ib3m5ricvtkl2cll7qpr2f6lvq '@radix-ui/react-select': 1.2.1_ib3m5ricvtkl2cll7qpr2f6lvq + '@radix-ui/react-tabs': 1.0.3_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-tooltip': 1.0.5_ib3m5ricvtkl2cll7qpr2f6lvq '@react-email/head': 0.0.2 '@remix-run/express': 1.11.0_cwk4saenierp7pa7l5cpbeswge '@remix-run/node': 1.11.0_biqbaboplfbrettd7655fr4n2y @@ -4495,6 +4501,23 @@ packages: prettier: 2.8.2 dev: false + /@code-hike/lighter/0.6.4: + resolution: {integrity: sha512-RGH/15WnFecNSPUxMVmbql0py25ijrhQlMtqkOSIgVZtmHxh00DkqImx65uL3dADFIzOa0RkN3ObUJWAppOgJQ==} + dev: false + + /@code-hike/mdx/0.8.3_react@18.2.0: + resolution: {integrity: sha512-pbbv7PivrU+GqPiM0ufehNyhsoge8V25fx+y89M2yKgEWMAFnNkk4E1XaW/X81QzIq3h58IoKEWnNYSJpERTvA==} + peerDependencies: + react: ^16.8.3 || ^17 || ^18 + dependencies: + '@code-hike/lighter': 0.6.4 + node-fetch: 2.6.7 + react: 18.2.0 + shiki: 0.10.1 + transitivePeerDependencies: + - encoding + dev: false + /@codemirror/autocomplete/6.4.0_eo6pz6bvsllvatnnwfprpuflde: resolution: {integrity: sha512-HLF2PnZAm1s4kGs30EiqKMgD7XsYaQ0XJnMR0rofEWQ5t5D60SfqpDIkIh1ze5tiEbyUWm8+VJ6W1/erVvBMIA==} peerDependencies: @@ -6725,6 +6748,26 @@ packages: react-dom: 18.2.0_react@18.2.0 dev: false + /@radix-ui/react-roving-focus/1.0.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.20.7 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-collection': 1.0.2_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-compose-refs': 1.0.0_react@18.2.0 + '@radix-ui/react-context': 1.0.0_react@18.2.0 + '@radix-ui/react-direction': 1.0.0_react@18.2.0 + '@radix-ui/react-id': 1.0.0_react@18.2.0 + '@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-use-callback-ref': 1.0.0_react@18.2.0 + '@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + dev: false + /@radix-ui/react-select/1.2.1_ib3m5ricvtkl2cll7qpr2f6lvq: resolution: {integrity: sha512-GULRMITaOHNj79BZvQs3iZO0+f2IgI8g5HDhMi7Bnc13t7IlG86NFtOCfTLme4PNZdEtU+no+oGgcl6IFiphpQ==} peerDependencies: @@ -6779,6 +6822,50 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-tabs/1.0.3_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-4CkF/Rx1GcrusI/JZ1Rvyx4okGUs6wEenWA0RG/N+CwkRhTy7t54y7BLsWUXrAz/GRbBfHQg/Odfs/RoW0CiRA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.20.7 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-context': 1.0.0_react@18.2.0 + '@radix-ui/react-direction': 1.0.0_react@18.2.0 + '@radix-ui/react-id': 1.0.0_react@18.2.0 + '@radix-ui/react-presence': 1.0.0_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-roving-focus': 1.0.3_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + dev: false + + /@radix-ui/react-tooltip/1.0.5_ib3m5ricvtkl2cll7qpr2f6lvq: + resolution: {integrity: sha512-cDKVcfzyO6PpckZekODJZDe5ZxZ2fCZlzKzTmPhe4mX9qTHRfLcKgqb0OKf22xLwDequ2tVleim+ZYx3rabD5w==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.20.7 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-compose-refs': 1.0.0_react@18.2.0 + '@radix-ui/react-context': 1.0.0_react@18.2.0 + '@radix-ui/react-dismissable-layer': 1.0.3_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-id': 1.0.0_react@18.2.0 + '@radix-ui/react-popper': 1.1.1_ib3m5ricvtkl2cll7qpr2f6lvq + '@radix-ui/react-portal': 1.0.2_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-presence': 1.0.0_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-primitive': 1.0.2_biqbaboplfbrettd7655fr4n2y + '@radix-ui/react-slot': 1.0.1_react@18.2.0 + '@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0 + '@radix-ui/react-visually-hidden': 1.0.2_biqbaboplfbrettd7655fr4n2y + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + transitivePeerDependencies: + - '@types/react' + dev: false + /@radix-ui/react-use-callback-ref/1.0.0_react@18.2.0: resolution: {integrity: sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==} peerDependencies: @@ -16222,7 +16309,6 @@ packages: /jsonc-parser/3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -20372,6 +20458,14 @@ packages: interpret: 1.4.0 rechoir: 0.6.2 + /shiki/0.10.1: + resolution: {integrity: sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==} + dependencies: + jsonc-parser: 3.2.0 + vscode-oniguruma: 1.7.0 + vscode-textmate: 5.2.0 + dev: false + /side-channel/1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -22680,6 +22774,14 @@ packages: acorn-walk: 8.2.0 dev: true + /vscode-oniguruma/1.7.0: + resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} + dev: false + + /vscode-textmate/5.2.0: + resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==} + dev: false + /w3c-keyname/2.2.6: resolution: {integrity: sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==} dev: false