diff --git a/apps/app/src/app/page.tsx b/apps/app/src/app/page.tsx index 035ab9c18..725d8de70 100644 --- a/apps/app/src/app/page.tsx +++ b/apps/app/src/app/page.tsx @@ -3,8 +3,10 @@ import { MainNav } from "~/components/ui/main-nav"; import { GenerateToken } from "~/components/generate-token"; import { ExtractStartForm } from "~/components/extract-start-form"; import { TransformStartForm } from "~/components/transform-start-form"; +import { getEnvTenants } from "~/components/tenant.env"; export default function Page() { + const tenants = getEnvTenants(); // getServerSideProps is deprecated. createServerContext documentation lackluster return ( <>
@@ -19,8 +21,8 @@ export default function Page() {
- - + + ); -} +} \ No newline at end of file diff --git a/apps/app/src/components/extract-start-form.tsx b/apps/app/src/components/extract-start-form.tsx index c6371e7ba..c9f28876b 100644 --- a/apps/app/src/components/extract-start-form.tsx +++ b/apps/app/src/components/extract-start-form.tsx @@ -3,9 +3,13 @@ import { useAuth } from '@clerk/nextjs'; import { useState } from 'react'; import type { ChangeEvent, Dispatch, SetStateAction } from 'react'; import { Input } from './ui/input'; +import { TenantPicker } from './tenant-picker'; +import type { Tenant } from './tenant.env'; - -export function ExtractStartForm() { +type ExtractStartFormProps = { + TENANTS: Tenant[] | undefined +} +export function ExtractStartForm({ TENANTS }: ExtractStartFormProps) { const { getToken } = useAuth(); const currentDate = new Date(); currentDate.setMonth(currentDate.getMonth() - 6); @@ -18,6 +22,7 @@ export function ExtractStartForm() { const [to, setTo] = useState(new Date().toISOString().slice(0, 10)); const [status, setStatus] = useState('---'); const [body, setBody] = useState(''); + const [tenantId, setTenantId] = useState((TENANTS || [])[0]?.id || -1); const handleInputChange = (stateSetter: Dispatch>) => (ev: ChangeEvent) => stateSetter(ev.target.value); @@ -25,13 +30,14 @@ export function ExtractStartForm() { const handleSubmit = async () => { if (!process.env.NEXT_PUBLIC_EXTRACT_API_URL) return console.error('Missing ENV variable: NEXT_PUBLIC_EXTRACT_API_URL'); + if (tenantId === -1) return console.error(`Invalid ENV variable: TENANTS`); setStatus('...'); setBody(''); const token = await getToken({ template: 'dashboard' }); if (!token) return; - const requestBody = JSON.stringify({ repositoryId, repositoryName, namespaceName, sourceControl, from: new Date(from), to: new Date(to) }); + const requestBody = JSON.stringify({ repositoryId, repositoryName, namespaceName, sourceControl, from: new Date(from), to: new Date(to), tenantId }); const res = await fetch(process.env.NEXT_PUBLIC_EXTRACT_API_URL, { method: 'post', @@ -81,6 +87,12 @@ export function ExtractStartForm() { + + tenant: + + + + diff --git a/apps/app/src/components/tenant-picker.tsx b/apps/app/src/components/tenant-picker.tsx new file mode 100644 index 000000000..2e7bca9a0 --- /dev/null +++ b/apps/app/src/components/tenant-picker.tsx @@ -0,0 +1,25 @@ +"use client" +import type { ChangeEvent } from "react"; +import type { Tenant } from "./tenant.env"; + +type TenantPickerProps = { + tenants: Tenant[] | undefined + setTenantId: (tenantId: number) => void; +} +export function TenantPicker({ tenants, setTenantId }: TenantPickerProps) { + + if (tenants === undefined) return (Invalid environment varibale: TENANTS); + + if (tenants.length === 0) return (Empty tenancy config); + + const handleSelectChange = (ev: ChangeEvent) => setTenantId(Number(ev.target.value)); + + return ( + + ); + +} diff --git a/apps/app/src/components/tenant.env.ts b/apps/app/src/components/tenant.env.ts new file mode 100644 index 000000000..64db07f05 --- /dev/null +++ b/apps/app/src/components/tenant.env.ts @@ -0,0 +1,34 @@ +import { z } from "zod"; + +const ENVSchema = z.object({ + TENANTS: z.string(), +}) +const TenantSchema = z.object({ + id: z.number(), + tenant: z.string(), + dbUrl: z.string(), +}); +const TenantArraySchema = z.array(TenantSchema); + +const processEnv = () => { + const validEnv = ENVSchema.safeParse(process.env); + if (!validEnv.success) { + console.error(`Missing required environment variable 'TENANT'`); + return undefined; + } + + const validTenantArray = TenantArraySchema.safeParse(JSON.parse(validEnv.data.TENANTS)); + if (!validTenantArray.success) { + console.error("Invalid environment variable 'TENANTS' value:", ...validTenantArray.error.issues); + return undefined; + } + + return validTenantArray.data; +} + +const TENANTS = processEnv(); + + +export const getEnvTenants = () => TENANTS; + +export type Tenant = z.infer; diff --git a/apps/app/src/components/transform-start-form.tsx b/apps/app/src/components/transform-start-form.tsx index 55b2b99bf..d3eec7011 100644 --- a/apps/app/src/components/transform-start-form.tsx +++ b/apps/app/src/components/transform-start-form.tsx @@ -1,15 +1,23 @@ "use client" import { useAuth } from '@clerk/nextjs'; import { useState } from 'react'; +import type { Tenant } from './tenant.env'; +import { TenantPicker } from './tenant-picker'; - -export function TransformStartForm() { +type TransformStartFormProps = { + TENANTS: Tenant[] | undefined +} +export function TransformStartForm({ TENANTS }: TransformStartFormProps) { const { getToken } = useAuth(); + const [tenantId, setTenantId] = useState((TENANTS || [])[0]?.id || -1); const [status, setStatus] = useState('---'); const [body, setBody] = useState(''); const handleClick = async () => { if (!process.env.NEXT_PUBLIC_TRANSFORM_API_URL) return console.error('Missing ENV variable: NEXT_PUBLIC_TRANSFORM_API_URL'); + if (tenantId === -1) return console.error(`Invalid ENV variable: TENANTS`); + const requestBody = JSON.stringify({ tenantId }); + setStatus('...'); setBody(''); @@ -18,6 +26,7 @@ export function TransformStartForm() { const res = await fetch(process.env.NEXT_PUBLIC_TRANSFORM_API_URL, { method: 'post', + body: requestBody, headers: { 'Authorization': 'Bearer ' + token } @@ -36,6 +45,7 @@ export function TransformStartForm() { +
tenant:
{status}
{body}