Openstatus www.openstatus.dev

chore: include addon in upgrade dialog (#1749)

* chore: include addon in upgrade dialog

* chore: add billing link

* chore: increase opacity

authored by

Maximilian Kaske and committed by
GitHub
90caca33 3def9e66

+77 -19
+2 -2
apps/dashboard/src/app/(dashboard)/monitors/(list)/nav-actions.tsx
··· 24 24 {limitReached ? ( 25 25 <Button 26 26 size="sm" 27 - data-disabled={limitReached} 28 - className="data-[disabled=true]:opacity-50" 27 + data-limited={limitReached} 28 + className="data-[limited=true]:opacity-80" 29 29 onClick={() => setOpenDialog(true)} 30 30 > 31 31 Create Monitor
+8 -6
apps/dashboard/src/app/(dashboard)/settings/billing/client.tsx
··· 181 181 <div className="flex flex-col gap-2 pt-4"> 182 182 {planAddons["email-domain-protection"] ? ( 183 183 <BillingAddons 184 - label="Magic Link (Auth)" 185 - description="Only allow user with a given email domain to access the status page." 184 + label={planAddons["email-domain-protection"].title} 185 + description={ 186 + planAddons["email-domain-protection"].description 187 + } 186 188 addon="email-domain-protection" 187 189 workspace={workspace} 188 190 /> 189 191 ) : null} 190 192 {planAddons["white-label"] ? ( 191 193 <BillingAddons 192 - label="White Label" 193 - description="Remove the 'powered by openstatus.dev' footer from your status pages." 194 + label={planAddons["white-label"].title} 195 + description={planAddons["white-label"].description} 194 196 addon="white-label" 195 197 workspace={workspace} 196 198 /> 197 199 ) : null} 198 200 {planAddons["status-pages"] ? ( 199 201 <BillingAddons 200 - label="Status Pages" 201 - description="Create and manage status pages for your workspace." 202 + label={planAddons["status-pages"].title} 203 + description={planAddons["status-pages"].description} 202 204 addon="status-pages" 203 205 workspace={workspace} 204 206 />
+7 -3
apps/dashboard/src/app/(dashboard)/status-pages/(list)/nav-actions.tsx
··· 24 24 {limitReached ? ( 25 25 <Button 26 26 size="sm" 27 - data-disabled={limitReached} 28 - className="data-[disabled=true]:opacity-50" 27 + data-limited={limitReached} 28 + className="data-[limited=true]:opacity-80" 29 29 onClick={() => setOpenDialog(true)} 30 30 > 31 31 Create Status Page ··· 35 35 <Link href="/status-pages/create">Create Status Page</Link> 36 36 </Button> 37 37 )} 38 - <UpgradeDialog open={openDialog} onOpenChange={setOpenDialog} /> 38 + <UpgradeDialog 39 + open={openDialog} 40 + onOpenChange={setOpenDialog} 41 + limit="status-pages" 42 + /> 39 43 </div> 40 44 ); 41 45 }
+32 -3
apps/dashboard/src/components/dialogs/upgrade.tsx
··· 1 + import { Link } from "@/components/common/link"; 1 2 import { Note, NoteButton } from "@/components/common/note"; 3 + import { BillingAddons } from "@/components/content/billing-addons"; 2 4 import { DataTable } from "@/components/data-table/billing/data-table"; 3 5 import { 4 6 Dialog, ··· 7 9 DialogHeader, 8 10 DialogTitle, 9 11 } from "@/components/ui/dialog"; 12 + import { Separator } from "@/components/ui/separator"; 10 13 import { useTRPC } from "@/lib/trpc/client"; 11 14 import type { WorkspacePlan } from "@openstatus/db/src/schema"; 12 - import type { Limits } from "@openstatus/db/src/schema/plan/schema"; 15 + import { allPlans } from "@openstatus/db/src/schema/plan/config"; 16 + import type { Addons, Limits } from "@openstatus/db/src/schema/plan/schema"; 13 17 import { getPlansForLimit } from "@openstatus/db/src/schema/plan/utils"; 14 18 import type { DialogProps } from "@radix-ui/react-dialog"; 15 19 import { useQuery } from "@tanstack/react-query"; ··· 32 36 33 37 if (!workspace) return null; 34 38 39 + const planAddons = allPlans[workspace.plan].addons; 40 + 35 41 const getRestrictTo = () => { 36 42 if (props.restrictTo) return props.restrictTo; 37 43 if (props.limit) return getPlansForLimit(workspace.plan, props.limit); ··· 40 46 41 47 const restrictTo = getRestrictTo(); 42 48 49 + const addon = 50 + props.limit && Object.prototype.hasOwnProperty.call(planAddons, props.limit) 51 + ? (props.limit as keyof Addons) 52 + : null; 53 + 43 54 return ( 44 55 <Dialog {...props}> 45 - <DialogContent className="max-h-[80vh] overflow-y-auto"> 56 + <DialogContent className="max-h-[80vh] overflow-y-auto sm:max-w-2xl"> 46 57 <DialogHeader> 47 58 <DialogTitle>Upgrade Workspace</DialogTitle> 48 59 <DialogDescription> 49 60 Upgrade your workspace to support more monitors, status pages, 50 - regions, and much more. 61 + regions, and much more. Get an overview within your{" "} 62 + <Link 63 + onClick={() => props.onOpenChange?.(false)} 64 + href="/settings/billing" 65 + > 66 + billing settings 67 + </Link> 68 + . 51 69 </DialogDescription> 52 70 </DialogHeader> 71 + {addon && planAddons[addon] ? ( 72 + <> 73 + <BillingAddons 74 + label={planAddons[addon].title} 75 + description={planAddons[addon].description} 76 + addon={addon} 77 + workspace={workspace} 78 + /> 79 + <Separator /> 80 + </> 81 + ) : null} 53 82 {restrictTo.length === 0 ? ( 54 83 <Note> 55 84 <CalendarClock />
+2 -2
apps/dashboard/src/components/nav/nav-monitors.tsx
··· 99 99 <Tooltip> 100 100 <TooltipTrigger asChild> 101 101 <SidebarMenuAction 102 - data-disabled={limitReached} 103 - className="relative top-0 right-0 border data-[disabled=true]:opacity-50" 102 + data-limited={limitReached} 103 + className="relative top-0 right-0 border data-[limited=true]:opacity-80" 104 104 onClick={() => { 105 105 if (limitReached) { 106 106 setOpenUpgradeDialog(true);
+3 -2
apps/dashboard/src/components/nav/nav-status-pages.tsx
··· 83 83 <Tooltip> 84 84 <TooltipTrigger asChild> 85 85 <SidebarMenuAction 86 - data-disabled={limitReached} 87 - className="relative top-0 right-0 border data-[disabled=true]:opacity-50" 86 + data-limited={limitReached} 87 + className="relative top-0 right-0 border data-[limited=true]:opacity-80" 88 88 onClick={() => { 89 89 if (limitReached) { 90 90 setOpenUpgradeDialog(true); ··· 190 190 <UpgradeDialog 191 191 open={openUpgradeDialog} 192 192 onOpenChange={setOpenUpgradeDialog} 193 + limit="status-pages" 193 194 /> 194 195 </SidebarGroup> 195 196 );
+23 -1
packages/db/src/schema/plan/config.ts
··· 7 7 id: WorkspacePlan; 8 8 description: string; 9 9 price: Price; 10 - addons: Partial<Addons>; 10 + addons: Partial<{ 11 + [K in keyof Addons]: { 12 + title: string; 13 + description: string; 14 + price: Price; 15 + }; 16 + }>; 11 17 limits: PlanLimits; 12 18 }; 13 19 ··· 66 72 }, 67 73 addons: { 68 74 "email-domain-protection": { 75 + title: "Magic Link (Auth)", 76 + description: 77 + "Only allow user with a given email domain to access the status page.", 69 78 price: { 70 79 USD: 100, 71 80 EUR: 100, ··· 73 82 }, 74 83 }, 75 84 "white-label": { 85 + title: "White Label", 86 + description: 87 + "Remove the 'powered by openstatus.dev' footer from your status pages.", 76 88 price: { 77 89 USD: 300, 78 90 EUR: 300, ··· 80 92 }, 81 93 }, 82 94 "status-pages": { 95 + title: "Status Pages", 96 + description: "Create and manage status pages for your workspace.", 83 97 price: { 84 98 USD: 20, 85 99 EUR: 20, ··· 130 144 }, 131 145 addons: { 132 146 "email-domain-protection": { 147 + title: "Magic Link (Auth)", 148 + description: 149 + "Only allow user with a given email domain to access the status page.", 133 150 price: { 134 151 USD: 100, 135 152 EUR: 100, ··· 137 154 }, 138 155 }, 139 156 "white-label": { 157 + title: "White Label", 158 + description: 159 + "Remove the 'powered by openstatus.dev' footer from your status pages.", 140 160 price: { 141 161 USD: 300, 142 162 EUR: 300, ··· 144 164 }, 145 165 }, 146 166 "status-pages": { 167 + title: "Status Pages", 168 + description: "Create and manage status pages for your workspace.", 147 169 price: { 148 170 USD: 20, 149 171 EUR: 20,