Openstatus www.openstatus.dev
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: workspace limits (#950)

* fix: workspace limits

* chore: remove log

* ci: apply automated fixes

* chore: use different workspace schema for dev and prod

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

Maximilian Kaske
autofix-ci[bot]
and committed by
GitHub
9ad3b623 3d959807

+53 -20
+1 -1
apps/web/src/app/app/[workspaceSlug]/(dashboard)/status-pages/[id]/domain/page.tsx
··· 15 15 const page = await api.page.getPageById.query({ id }); 16 16 const workspace = await api.workspace.getWorkspace.query(); 17 17 18 - const isValid = allPlans[workspace.plan].limits["custom-domain"]; 18 + const isValid = workspace.limits["custom-domain"]; 19 19 20 20 if (!page) return notFound(); 21 21
+1 -3
apps/web/src/app/app/[workspaceSlug]/(dashboard)/status-pages/[id]/subscribers/page.tsx
··· 1 1 import { notFound } from "next/navigation"; 2 2 3 - import { allPlans } from "@openstatus/db/src/schema/plan/config"; 4 - 5 3 import { ProFeatureAlert } from "@/components/billing/pro-feature-alert"; 6 4 import { columns } from "@/components/data-table/page-subscriber/columns"; 7 5 import { DataTable } from "@/components/data-table/page-subscriber/data-table"; ··· 18 16 19 17 if (!page) return notFound(); 20 18 21 - const isValid = allPlans[workspace.plan].limits["status-subscribers"]; 19 + const isValid = workspace.limits["status-subscribers"]; 22 20 if (!isValid) return <ProFeatureAlert feature={"Status page subscribers"} />; 23 21 24 22 const data = await api.pageSubscriber.getPageSubscribersByPageId.query({
+1 -1
apps/web/src/app/status-page/[domain]/_components/footer.tsx
··· 9 9 } 10 10 11 11 export function Footer({ plan, timeZone }: Props) { 12 - const isWhiteLabel = allPlans[plan].limits["white-label"]; 12 + const isWhiteLabel = allPlans[plan].limits["white-label"]; // FIXME: use the workspace.limits 13 13 return ( 14 14 <footer className="z-10 mx-auto grid w-full grid-cols-5 items-center justify-between gap-4"> 15 15 <p className="truncate font-light text-muted-foreground text-xs">
+5 -2
apps/web/src/components/dashboard/limit.tsx
··· 3 3 export function Limit() { 4 4 return ( 5 5 <div className="col-span-full text-center"> 6 - <p className="text-foreground text-sm"> 6 + <p className="text-muted-foreground text-sm"> 7 7 You have reached the account limits. Please{" "} 8 - <Link href={"./settings/billing"} className="underline"> 8 + <Link 9 + href={"./settings/billing"} 10 + className="text-foreground underline underline-offset-4 hover:no-underline" 11 + > 9 12 upgrade 10 13 </Link>{" "} 11 14 your account.
+1 -1
packages/api/src/router/invitation.ts
··· 20 20 .mutation(async (opts) => { 21 21 const { email } = opts.input; 22 22 23 - const _members = allPlans[opts.ctx.workspace.plan].limits.members; 23 + const _members = opts.ctx.workspace.limits.members; 24 24 const membersLimit = _members === "Unlimited" ? 420 : _members; 25 25 26 26 const usersToWorkspacesNumbers = (
+6 -8
packages/api/src/router/monitor.ts
··· 34 34 .input(insertMonitorSchema) 35 35 .output(selectMonitorSchema) 36 36 .mutation(async (opts) => { 37 - const monitorLimit = allPlans[opts.ctx.workspace.plan].limits.monitors; 38 - const periodicityLimit = 39 - allPlans[opts.ctx.workspace.plan].limits.periodicity; 40 - const regionsLimit = allPlans[opts.ctx.workspace.plan].limits.regions; 37 + const monitorLimit = opts.ctx.workspace.limits.monitors; 38 + const periodicityLimit = opts.ctx.workspace.limits.periodicity; 39 + const regionsLimit = opts.ctx.workspace.limits.regions; 41 40 42 41 const monitorNumbers = ( 43 42 await opts.ctx.db.query.monitor.findMany({ ··· 252 251 .mutation(async (opts) => { 253 252 if (!opts.input.id) return; 254 253 255 - const periodicityLimit = 256 - allPlans[opts.ctx.workspace.plan].limits.periodicity; 254 + const periodicityLimit = opts.ctx.workspace.limits.periodicity; 257 255 258 - const regionsLimit = allPlans[opts.ctx.workspace.plan].limits.regions; 256 + const regionsLimit = opts.ctx.workspace.limits.regions; 259 257 260 258 // the user is not allowed to use the cron job 261 259 if ( ··· 729 727 }), 730 728 731 729 isMonitorLimitReached: protectedProcedure.query(async (opts) => { 732 - const monitorLimit = allPlans[opts.ctx.workspace.plan].limits.monitors; 730 + const monitorLimit = opts.ctx.workspace.limits.monitors; 733 731 const monitorNumbers = ( 734 732 await opts.ctx.db.query.monitor.findMany({ 735 733 where: and(
+3 -3
packages/api/src/router/page.ts
··· 42 42 }) 43 43 ).length; 44 44 45 - const limit = allPlans[opts.ctx.workspace.plan].limits; 45 + const limit = opts.ctx.workspace.limits; 46 46 47 47 // the user has reached the status page number limits 48 48 if (pageNumbers >= limit["status-pages"]) { ··· 123 123 124 124 const monitorIds = monitors?.map((item) => item.monitorId) || []; 125 125 126 - const limit = allPlans[opts.ctx.workspace.plan].limits; 126 + const limit = opts.ctx.workspace.limits; 127 127 128 128 // the user is not eligible for password protection 129 129 if ( ··· 369 369 }), 370 370 371 371 isPageLimitReached: protectedProcedure.query(async (opts) => { 372 - const pageLimit = allPlans[opts.ctx.workspace.plan].limits["status-pages"]; 372 + const pageLimit = opts.ctx.workspace.limits["status-pages"]; 373 373 const pageNumbers = ( 374 374 await opts.ctx.db.query.page.findMany({ 375 375 where: eq(monitor.workspaceId, opts.ctx.workspace.id),
+35 -1
packages/db/src/schema/workspaces/validation.ts
··· 9 9 export const workspacePlanSchema = z.enum(workspacePlans); 10 10 export const workspaceRoleSchema = z.enum(workspaceRole); 11 11 12 - export const selectWorkspaceSchema = createSelectSchema(workspace).extend({ 12 + /** 13 + * Workspace schema with limits and plan 14 + * If not available in the db, the limits will be taken from the workspace plan 15 + */ 16 + const selectWorkspaceSchemaDevelopment = createSelectSchema(workspace) 17 + .extend({ 18 + limits: z.string().transform((val) => { 19 + const parsed = JSON.parse(val); 20 + const result = limitsV1.partial().safeParse(parsed); 21 + if (result.error) return {}; 22 + return result.data; 23 + }), 24 + plan: z 25 + .enum(workspacePlans) 26 + .nullable() 27 + .default("free") 28 + .transform((val) => val ?? "free"), 29 + }) 30 + .transform((val) => { 31 + return { 32 + ...val, 33 + limits: limitsV1.parse({ ...allPlans[val.plan].limits, ...val.limits }), 34 + }; 35 + }); 36 + 37 + /** 38 + * Workspace schema with limits and plan 39 + * The limits for paid users have to be defined within the db otherwise, fallbacks to free plan limits 40 + */ 41 + const selectWorkspaceSchemaProduction = createSelectSchema(workspace).extend({ 13 42 limits: z.string().transform((val) => { 14 43 const parsed = JSON.parse(val); 15 44 const result = limitsV1.safeParse(parsed); ··· 28 57 .default("free") 29 58 .transform((val) => val ?? "free"), 30 59 }); 60 + 61 + export const selectWorkspaceSchema = 62 + process.env.NODE_ENV === "development" 63 + ? selectWorkspaceSchemaDevelopment 64 + : selectWorkspaceSchemaProduction; 31 65 32 66 export const insertWorkspaceSchema = createSelectSchema(workspace); 33 67