From 18ab17eed43ca804d47199fc13e8bda2a1e63929 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Tue, 2 Jul 2024 14:37:37 +0100 Subject: [PATCH] Replaced Upgrade callout with a more generic InfoPanel component --- .../app/components/primitives/InfoPanel.tsx | 71 +++++++++++++++++++ .../components/primitives/UpgradeCallout.tsx | 42 ----------- .../route.tsx | 43 +++++------ .../route.tsx | 13 +++- 4 files changed, 103 insertions(+), 66 deletions(-) create mode 100644 apps/webapp/app/components/primitives/InfoPanel.tsx delete mode 100644 apps/webapp/app/components/primitives/UpgradeCallout.tsx diff --git a/apps/webapp/app/components/primitives/InfoPanel.tsx b/apps/webapp/app/components/primitives/InfoPanel.tsx new file mode 100644 index 000000000..f57419c65 --- /dev/null +++ b/apps/webapp/app/components/primitives/InfoPanel.tsx @@ -0,0 +1,71 @@ +import { LinkButton } from "./Buttons"; +import { Header3 } from "./Headers"; +import { Paragraph } from "./Paragraph"; +import { cn } from "~/utils/cn"; + +const variants = { + info: { + panelStyle: "border-grid-bright bg-background-bright", + }, + upgrade: { + panelStyle: "border-indigo-400/20 bg-indigo-800/10", + }, +}; + +type InfoPanelVariant = keyof typeof variants; + +type Props = { + title?: string; + children: React.ReactNode; + to?: string; + buttonLabel?: string; + icon: React.ComponentType; + iconClassName?: string; + variant?: InfoPanelVariant; + panelClassName?: string; +}; + +export function InfoPanel({ + title, + children, + to, + buttonLabel, + icon, + iconClassName, + variant = "info", + panelClassName = "max-w-sm", +}: Props) { + const Icon = icon; + const variantStyle = variants[variant]; + + return ( +
+
+ + + {to && ( + + {buttonLabel} + + )} +
+
+ {title && {title}} + {typeof children === "string" ? ( + + {children} + + ) : ( + children + )} +
+
+ ); +} diff --git a/apps/webapp/app/components/primitives/UpgradeCallout.tsx b/apps/webapp/app/components/primitives/UpgradeCallout.tsx deleted file mode 100644 index 852efb587..000000000 --- a/apps/webapp/app/components/primitives/UpgradeCallout.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { LockOpenIcon } from "@heroicons/react/24/solid"; -import { useOrganization } from "~/hooks/useOrganizations"; -import { v3BillingPath } from "~/utils/pathBuilder"; -import { LinkButton } from "./Buttons"; -import { Header3 } from "./Headers"; -import { Paragraph } from "./Paragraph"; - -type Props = { - title: string; - children: React.ReactNode; - to?: string; -}; - -export function UpgradeCallout({ title, children, to }: Props) { - const organization = useOrganization(); - - to = to || v3BillingPath(organization); - - return ( -
-
- - - Upgrade - -
-
- {title} - {typeof children === "string" ? ( - - {children} - - ) : ( - children - )} -
-
- ); -} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.apikeys/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.apikeys/route.tsx index f35aa7cee..8d9151477 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.apikeys/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.apikeys/route.tsx @@ -1,5 +1,4 @@ -import { BookOpenIcon } from "@heroicons/react/20/solid"; -import { InformationCircleIcon } from "@heroicons/react/24/outline"; +import { BookOpenIcon, InformationCircleIcon, LockOpenIcon } from "@heroicons/react/20/solid"; import { LoaderFunctionArgs } from "@remix-run/server-runtime"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { AdminDebugTooltip } from "~/components/admin/debugTooltip"; @@ -9,7 +8,7 @@ import { PageBody, PageContainer } from "~/components/layout/AppLayout"; import { LinkButton } from "~/components/primitives/Buttons"; import { ClipboardField } from "~/components/primitives/ClipboardField"; import { DateTime } from "~/components/primitives/DateTime"; -import { Header3 } from "~/components/primitives/Headers"; +import { InfoPanel } from "~/components/primitives/InfoPanel"; import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/PageHeader"; import { Paragraph } from "~/components/primitives/Paragraph"; import { Property, PropertyTable } from "~/components/primitives/PropertyTable"; @@ -23,10 +22,10 @@ import { TableRow, } from "~/components/primitives/Table"; import { TextLink } from "~/components/primitives/TextLink"; -import { UpgradeCallout } from "~/components/primitives/UpgradeCallout"; +import { useOrganization } from "~/hooks/useOrganizations"; import { ApiKeysPresenter } from "~/presenters/v3/ApiKeysPresenter.server"; import { requireUserId } from "~/services/session.server"; -import { ProjectParamSchema, docsPath } from "~/utils/pathBuilder"; +import { ProjectParamSchema, docsPath, v3BillingPath } from "~/utils/pathBuilder"; export const loader = async ({ request, params }: LoaderFunctionArgs) => { const userId = await requireUserId(request); @@ -54,6 +53,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { export default function Page() { const { environments, hasStaging } = useTypedLoaderData(); + const organization = useOrganization(); return ( @@ -124,25 +124,26 @@ export default function Page() { -
-
-
- -
-
- Secret keys - - Secret keys should be used on your server. They give full API access and allow you - to trigger tasks from your - backend. - -
-
+
+ + + Secret keys should be used on your server. They give full API access and allow you + to trigger tasks from your + backend. + + {!hasStaging && ( - + Upgrade your plan to add a Staging environment. - + )}
diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.environment-variables/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.environment-variables/route.tsx index e2b8744b7..e1710a975 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.environment-variables/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.environment-variables/route.tsx @@ -1,6 +1,12 @@ import { useForm } from "@conform-to/react"; import { parse } from "@conform-to/zod"; -import { BookOpenIcon, PencilSquareIcon, PlusIcon, TrashIcon } from "@heroicons/react/20/solid"; +import { + BookOpenIcon, + InformationCircleIcon, + PencilSquareIcon, + PlusIcon, + TrashIcon, +} from "@heroicons/react/20/solid"; import { Form, Outlet, useActionData, useNavigation } from "@remix-run/react"; import { ActionFunctionArgs, @@ -22,6 +28,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components import { Fieldset } from "~/components/primitives/Fieldset"; import { FormButtons } from "~/components/primitives/FormButtons"; import { FormError } from "~/components/primitives/FormError"; +import { InfoPanel } from "~/components/primitives/InfoPanel"; import { Input } from "~/components/primitives/Input"; import { InputGroup } from "~/components/primitives/InputGroup"; import { Label } from "~/components/primitives/Label"; @@ -256,10 +263,10 @@ export default function Page() { - + Dev environment variables specified here will be overridden by ones in your .env file when running locally. - +