mirror of
https://github.com/biersoeckli/QuickStack.git
synced 2026-01-11 05:59:42 -06:00
fixed some bugs
This commit is contained in:
@@ -30,7 +30,6 @@ export default function AppTabs({
|
||||
<TabsTrigger value="environment">Environment</TabsTrigger>
|
||||
<TabsTrigger value="domains">Domains</TabsTrigger>
|
||||
<TabsTrigger value="storage">Storage</TabsTrigger>
|
||||
<TabsTrigger value="logs">Logs</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="overview">Domains, Logs, etc.</TabsContent>
|
||||
<TabsContent value="general" className="space-y-4">
|
||||
@@ -44,7 +43,6 @@ export default function AppTabs({
|
||||
<DomainsList app={app} />
|
||||
</TabsContent>
|
||||
<TabsContent value="storage">storage</TabsContent>
|
||||
<TabsContent value="logs">logs</TabsContent>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import { toast } from "sonner";
|
||||
import { AppEnvVariablesModel, appEnvVariablesZodModel } from "@/model/env-edit.model";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { AppExtendedModel } from "@/model/app-extended.model";
|
||||
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CheckIcon, CrossIcon } from "lucide-react";
|
||||
|
||||
|
||||
export default function DomainsList({ app }: {
|
||||
@@ -31,8 +34,32 @@ export default function DomainsList({ app }: {
|
||||
<CardTitle>Domains</CardTitle>
|
||||
<CardDescription>Add custom domains to your application. If your app has a domain configured, it will be public and accessible via the internet.</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableCaption>{app.appDomains.length} Domains</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Port</TableHead>
|
||||
<TableHead>SSL</TableHead>
|
||||
<TableHead>Action</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{app.appDomains.map(domain => (
|
||||
<TableRow key={domain.hostname}>
|
||||
<TableCell className="font-medium">{domain.hostname}</TableCell>
|
||||
<TableCell className="font-medium">{domain.port}</TableCell>
|
||||
<TableCell className="font-medium">{domain.useSsl ? <CheckIcon /> : <CrossIcon />}</TableCell>
|
||||
<TableCell className="font-medium"><Button variant="ghost">Edit</Button></TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button>Add Domain</Button>
|
||||
</CardFooter>
|
||||
</Card >
|
||||
|
||||
</>;
|
||||
|
||||
@@ -70,6 +70,5 @@ export default function EnvEdit({ app }: {
|
||||
</form>
|
||||
</Form >
|
||||
</Card >
|
||||
|
||||
</>;
|
||||
}
|
||||
@@ -40,7 +40,14 @@ export const saveGeneralAppSourceInfo = async (prevState: any, inputData: AppSou
|
||||
|
||||
export const saveGeneralAppRateLimits = async (prevState: any, inputData: AppRateLimitsModel, appId: string) =>
|
||||
saveFormAction(inputData, appRateLimitsZodModel, async (validatedData) => {
|
||||
console.log(validatedData)
|
||||
if (validatedData.replicas < 1) {
|
||||
throw new ServiceException('Replica Count must be at least 1');
|
||||
}
|
||||
await getAuthUserSession();
|
||||
|
||||
const existingApp = await appService.getById(appId);
|
||||
await appService.save({
|
||||
...existingApp,
|
||||
...validatedData,
|
||||
id: appId,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,11 +36,10 @@ export default function GeneralAppRateLimits({ app }: {
|
||||
FormUtils.mapValidationErrorsToForm<typeof appRateLimitsZodModel>(state, form);
|
||||
}, [state]);
|
||||
|
||||
const sourceTypeField = form.watch();
|
||||
return <>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Rate Limits</CardTitle>
|
||||
<CardTitle>Container Configuration</CardTitle>
|
||||
<CardDescription>Provide optional rate Limits per running container instance.</CardDescription>
|
||||
</CardHeader>
|
||||
<Form {...form}>
|
||||
@@ -48,6 +47,22 @@ export default function GeneralAppRateLimits({ app }: {
|
||||
return formAction(data);
|
||||
})()}>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="replicas"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Replica Count</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" {...field} value={field.value} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
|
||||
<FormField
|
||||
@@ -107,8 +122,9 @@ export default function GeneralAppRateLimits({ app }: {
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<CardFooter className="gap-4">
|
||||
<SubmitButton>Save</SubmitButton>
|
||||
<p className="text-red-500">{state?.message}</p>
|
||||
</CardFooter>
|
||||
</form>
|
||||
</Form >
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
import projectService from "@/server/services/project.service";
|
||||
import PageTitle from "@/components/custom/page-title";
|
||||
import AppTabs from "./app-tabs";
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { SubmitButton } from "@/components/custom/submit-button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export default async function AppPage({
|
||||
searchParams,
|
||||
@@ -46,6 +49,13 @@ export default async function AppPage({
|
||||
title={app.name}
|
||||
subtitle={`App ID: "${app.id}"`}>
|
||||
</PageTitle>
|
||||
<Card>
|
||||
<CardContent className="p-4 flex gap-4">
|
||||
<Button>Deploy</Button>
|
||||
<Button variant="secondary">Start</Button>
|
||||
<Button variant="secondary">Rebuild</Button>
|
||||
</CardContent>
|
||||
</Card >
|
||||
<AppTabs app={app} tabName={params.tabName} />
|
||||
</div>
|
||||
)
|
||||
|
||||
7
src/app/project/app/route.ts
Normal file
7
src/app/project/app/route.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
// redirects to default route "general" for the app
|
||||
export async function GET(request: Request) {
|
||||
const url = new URL(request.url);
|
||||
redirect(`/project/app/general?appId=${url.searchParams.get("appId")}`);
|
||||
}
|
||||
@@ -8,17 +8,23 @@ import { formatDateTime } from "@/lib/format.utils";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { MoreHorizontal } from "lucide-react";
|
||||
import { Toast } from "@/lib/toast.utils";
|
||||
import { Project } from "@prisma/client";
|
||||
import { App, Project } from "@prisma/client";
|
||||
import { deleteApp } from "./actions";
|
||||
|
||||
|
||||
|
||||
export default function AppTable({ data }: { data: Project[] }) {
|
||||
export default function AppTable({ data }: { data: App[] }) {
|
||||
|
||||
return <>
|
||||
<SimpleDataTable columns={[
|
||||
['id', 'ID', false],
|
||||
['name', 'Name', true],
|
||||
['sourceType', 'Source Type', false, (item) => item.sourceType === 'GIT' ? 'Git' : 'Container'],
|
||||
['replicas', 'Replica Count', false],
|
||||
['memoryLimit', 'Memory Limit', false],
|
||||
['memoryReservation', 'Memory Reservation', false],
|
||||
['cpuLimit', 'CPU Limit', false],
|
||||
['cpuReservation', 'CPU Reservation', false],
|
||||
["createdAt", "Created At", true, (item) => formatDateTime(item.createdAt)],
|
||||
["updatedAt", "Updated At", false, (item) => formatDateTime(item.updatedAt)],
|
||||
]}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { stringToNumber, stringToOptionalNumber } from "@/lib/zod.utils";
|
||||
import { z } from "zod";
|
||||
|
||||
export const appRateLimitsZodModel = z.object({
|
||||
memoryReservation: z.number().nullish(),
|
||||
memoryLimit: z.number().nullish(),
|
||||
cpuReservation: z.number().nullish(),
|
||||
cpuLimit: z.number().nullish(),
|
||||
memoryReservation: stringToOptionalNumber,
|
||||
memoryLimit: stringToOptionalNumber,
|
||||
cpuReservation: stringToOptionalNumber,
|
||||
cpuLimit: stringToOptionalNumber,
|
||||
replicas: stringToNumber,
|
||||
})
|
||||
|
||||
export type AppRateLimitsModel = z.infer<typeof appRateLimitsZodModel>;
|
||||
@@ -17,7 +17,7 @@ export class SuccessActionResult<T> extends ServerActionResult<undefined, T> {
|
||||
}
|
||||
|
||||
export class ErrorActionResult<TErrorData> extends ServerActionResult<TErrorData, undefined> {
|
||||
constructor(errors: FormZodErrorValidationCallback<TErrorData>, message?: string) {
|
||||
constructor(errors?: FormZodErrorValidationCallback<TErrorData>, message?: string) {
|
||||
super('error', undefined, message, errors);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user