From 3c60018ca20f49986e9f37efc8ca850913c4e022 Mon Sep 17 00:00:00 2001 From: Derock Date: Sat, 20 Jan 2024 21:11:00 -0500 Subject: [PATCH] wip: form update route --- package.json | 1 + pnpm-lock.yaml | 84 +++++++++++++------ .../service/[serviceId]/_hooks/service.ts | 21 ----- .../service/[serviceId]/advanced/page.tsx | 9 -- .../{[id] => [projectId]}/(home)/layout.tsx | 0 .../{[id] => [projectId]}/(home)/page.tsx | 0 .../{[id] => [projectId]}/ProjectLayout.tsx | 2 +- .../_components/CreateService.tsx | 0 .../_components/DeployChanges.tsx | 0 .../_components/ServiceCard.tsx | 0 .../_context/ProjectContext.tsx | 0 .../project/{[id] => [projectId]}/layout.tsx | 6 +- .../[serviceId]/_components/DeleteButton.tsx | 0 .../service/[serviceId]/_hooks/service.ts | 39 +++++++++ .../advanced/DeploymentSettings.tsx | 25 +++--- .../service/[serviceId]/advanced/page.tsx | 17 ++++ .../service/[serviceId]/containers/page.tsx | 0 .../service/[serviceId]/home/page.tsx | 0 .../service/[serviceId]/layout.tsx | 0 .../service/[serviceId]/page.tsx | 0 src/components/ui/switch.tsx | 29 +++++++ src/hooks/forms.tsx | 4 +- .../api/routers/projects/service/index.ts | 66 ++++++++++++++- src/server/db/schema.ts | 2 +- src/utils/utils.ts | 10 ++- 25 files changed, 237 insertions(+), 78 deletions(-) delete mode 100644 src/app/(dashboard)/project/[id]/service/[serviceId]/_hooks/service.ts delete mode 100644 src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/page.tsx rename src/app/(dashboard)/project/{[id] => [projectId]}/(home)/layout.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/(home)/page.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/ProjectLayout.tsx (98%) rename src/app/(dashboard)/project/{[id] => [projectId]}/_components/CreateService.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/_components/DeployChanges.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/_components/ServiceCard.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/_context/ProjectContext.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/layout.tsx (66%) rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/_components/DeleteButton.tsx (100%) create mode 100644 src/app/(dashboard)/project/[projectId]/service/[serviceId]/_hooks/service.ts rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/advanced/DeploymentSettings.tsx (86%) create mode 100644 src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/page.tsx rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/containers/page.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/home/page.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/layout.tsx (100%) rename src/app/(dashboard)/project/{[id] => [projectId]}/service/[serviceId]/page.tsx (100%) create mode 100644 src/components/ui/switch.tsx diff --git a/package.json b/package.json index 828bce5..e87482c 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.0.4", "@t3-oss/env-nextjs": "^0.7.1", "@tanstack/react-query": "^5.17.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6b1e6b..1704e30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ dependencies: '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.46)(react@18.2.0) + '@radix-ui/react-switch': + specifier: ^1.0.3 + version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-tabs': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) @@ -1642,13 +1645,13 @@ packages: /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 dev: false /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 dev: false /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0): @@ -1664,7 +1667,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.46 '@types/react-dom': 18.2.18 @@ -1713,7 +1716,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) @@ -1733,7 +1736,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -1747,7 +1750,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -1795,7 +1798,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -1813,7 +1816,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) @@ -1861,7 +1864,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -1879,7 +1882,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.46)(react@18.2.0) @@ -1906,7 +1909,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 react: 18.2.0 @@ -1946,7 +1949,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) @@ -1984,7 +1987,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@floating-ui/react-dom': 2.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) @@ -2014,7 +2017,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.46 '@types/react-dom': 18.2.18 @@ -2035,7 +2038,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 @@ -2057,7 +2060,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-slot': 1.0.2(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 '@types/react-dom': 18.2.18 @@ -2078,7 +2081,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) @@ -2171,6 +2174,33 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-switch@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.46)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.46)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.46)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.46)(react@18.2.0) + '@types/react': 18.2.46 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==} peerDependencies: @@ -2208,7 +2238,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -2222,7 +2252,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 react: 18.2.0 @@ -2237,7 +2267,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 react: 18.2.0 @@ -2252,7 +2282,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -2266,7 +2296,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.46 react: 18.2.0 dev: false @@ -2280,7 +2310,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/rect': 1.0.1 '@types/react': 18.2.46 react: 18.2.0 @@ -2295,7 +2325,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.46)(react@18.2.0) '@types/react': 18.2.46 react: 18.2.0 @@ -2314,7 +2344,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.46 '@types/react-dom': 18.2.18 @@ -2325,7 +2355,7 @@ packages: /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 dev: false /@replit/codemirror-lang-csharp@6.2.0(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14): @@ -4143,7 +4173,7 @@ packages: /dom-helpers@3.4.0: resolution: {integrity: sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==} dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 dev: false /dotenv@16.3.1: diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/_hooks/service.ts b/src/app/(dashboard)/project/[id]/service/[serviceId]/_hooks/service.ts deleted file mode 100644 index ddfca16..0000000 --- a/src/app/(dashboard)/project/[id]/service/[serviceId]/_hooks/service.ts +++ /dev/null @@ -1,21 +0,0 @@ -"use client"; - -import { api } from "~/trpc/react"; -import { useProject } from "../../../_context/ProjectContext"; - -/** - * Returns detailed information about a service (or the one currently navigated to) - */ -export function useService(serviceId?: string) { - const project = useProject(); - serviceId ??= project?.selectedService?.id; - - if (!serviceId) { - throw new Error("No service ID provided"); - } - - return api.projects.services.get.useQuery({ - projectId: project.id, - serviceId, - }); -} diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/page.tsx b/src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/page.tsx deleted file mode 100644 index 29c022f..0000000 --- a/src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import DeploymentSettings from "./DeploymentSettings"; - -export default function AdvancedSettings() { - return ( -
- -
- ); -} diff --git a/src/app/(dashboard)/project/[id]/(home)/layout.tsx b/src/app/(dashboard)/project/[projectId]/(home)/layout.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/(home)/layout.tsx rename to src/app/(dashboard)/project/[projectId]/(home)/layout.tsx diff --git a/src/app/(dashboard)/project/[id]/(home)/page.tsx b/src/app/(dashboard)/project/[projectId]/(home)/page.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/(home)/page.tsx rename to src/app/(dashboard)/project/[projectId]/(home)/page.tsx diff --git a/src/app/(dashboard)/project/[id]/ProjectLayout.tsx b/src/app/(dashboard)/project/[projectId]/ProjectLayout.tsx similarity index 98% rename from src/app/(dashboard)/project/[id]/ProjectLayout.tsx rename to src/app/(dashboard)/project/[projectId]/ProjectLayout.tsx index f52bdf2..7c4fa8b 100644 --- a/src/app/(dashboard)/project/[id]/ProjectLayout.tsx +++ b/src/app/(dashboard)/project/[projectId]/ProjectLayout.tsx @@ -16,7 +16,7 @@ export function ProjectLayout(props: { children: React.ReactNode; }) { const params = useParams(); - const projectPath = `/project/${params.id as string}`; + const projectPath = `/project/${params.projectId as string}`; const servicePath = `${projectPath}/service/${params.serviceId as string}`; const project = api.projects.get.useQuery( diff --git a/src/app/(dashboard)/project/[id]/_components/CreateService.tsx b/src/app/(dashboard)/project/[projectId]/_components/CreateService.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/_components/CreateService.tsx rename to src/app/(dashboard)/project/[projectId]/_components/CreateService.tsx diff --git a/src/app/(dashboard)/project/[id]/_components/DeployChanges.tsx b/src/app/(dashboard)/project/[projectId]/_components/DeployChanges.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/_components/DeployChanges.tsx rename to src/app/(dashboard)/project/[projectId]/_components/DeployChanges.tsx diff --git a/src/app/(dashboard)/project/[id]/_components/ServiceCard.tsx b/src/app/(dashboard)/project/[projectId]/_components/ServiceCard.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/_components/ServiceCard.tsx rename to src/app/(dashboard)/project/[projectId]/_components/ServiceCard.tsx diff --git a/src/app/(dashboard)/project/[id]/_context/ProjectContext.tsx b/src/app/(dashboard)/project/[projectId]/_context/ProjectContext.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/_context/ProjectContext.tsx rename to src/app/(dashboard)/project/[projectId]/_context/ProjectContext.tsx diff --git a/src/app/(dashboard)/project/[id]/layout.tsx b/src/app/(dashboard)/project/[projectId]/layout.tsx similarity index 66% rename from src/app/(dashboard)/project/[id]/layout.tsx rename to src/app/(dashboard)/project/[projectId]/layout.tsx index 2cdd23e..bf9db86 100644 --- a/src/app/(dashboard)/project/[id]/layout.tsx +++ b/src/app/(dashboard)/project/[projectId]/layout.tsx @@ -2,10 +2,12 @@ import { api } from "~/trpc/server"; import { ProjectLayout } from "./ProjectLayout"; export default async function ProjectPage(props: { - params: { id: string }; + params: { projectId: string }; children: React.ReactNode; }) { - const project = await api.projects.get.query({ projectId: props.params.id }); + const project = await api.projects.get.query({ + projectId: props.params.projectId, + }); return {props.children}; } diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/_components/DeleteButton.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/_components/DeleteButton.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/_components/DeleteButton.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/_components/DeleteButton.tsx diff --git a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/_hooks/service.ts b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/_hooks/service.ts new file mode 100644 index 0000000..dc5fc89 --- /dev/null +++ b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/_hooks/service.ts @@ -0,0 +1,39 @@ +"use client"; + +import { use } from "react"; +import { api } from "~/trpc/react"; +import { type RouterOutputs } from "~/trpc/shared"; +import { type Awaitable } from "~/utils/utils"; +import { useProject } from "../../../_context/ProjectContext"; + +/** + * Returns detailed information about a service (or the one currently navigated to) + */ +export function useService( + serviceId?: string, + defaultData?: Awaitable, +) { + const project = useProject(); + serviceId ??= project?.selectedService?.id; + + if (!serviceId) { + throw new Error("No service ID provided"); + } + + return api.projects.services.get.useQuery( + { + projectId: project.id, + serviceId, + }, + { + initialData: + // use( + // apiServer.projects.services.get.query({ + // projectId: project.id, + // serviceId: serviceId, + // }) + // ), + defaultData instanceof Promise ? use(defaultData) : defaultData, + }, + ); +} diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/DeploymentSettings.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/DeploymentSettings.tsx similarity index 86% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/DeploymentSettings.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/DeploymentSettings.tsx index 955aa61..e355954 100644 --- a/src/app/(dashboard)/project/[id]/service/[serviceId]/advanced/DeploymentSettings.tsx +++ b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/DeploymentSettings.tsx @@ -17,12 +17,13 @@ import { SelectTrigger, SelectValue, } from "~/components/ui/select"; +import { Switch } from "~/components/ui/switch"; import { FormSubmit, SimpleFormField, useForm } from "~/hooks/forms"; import { DOCKER_DEPLOY_MODE_MAP, DockerDeployMode } from "~/server/db/types"; -import { useService } from "../_hooks/service"; +import { type RouterOutputs } from "~/trpc/shared"; const formValidator = z.object({ - replicas: z.number().int().positive(), + replicas: z.coerce.number().int().positive(), maxReplicasPerNode: z.number().int().positive().nullable(), deployMode: z.enum(["replicated", "global"]).nullable(), zeroDowntime: z.boolean().nullable(), @@ -30,16 +31,19 @@ const formValidator = z.object({ command: z.string().optional().nullable(), }); -export default function DeploymentSettings() { - const { data: service } = useService(); +export default function DeploymentSettings({ + service, +}: { + service: RouterOutputs["projects"]["services"]["get"]; +}) { const form = useForm(formValidator, { defaultValues: { - replicas: service?.replicas, - maxReplicasPerNode: service?.maxReplicasPerNode, - deployMode: service?.deployMode, - zeroDowntime: service?.zeroDowntime, - entrypoint: service?.entrypoint, - command: service?.command, + replicas: service.replicas, + maxReplicasPerNode: service.maxReplicasPerNode, + deployMode: service.deployMode, + zeroDowntime: service.zeroDowntime, + entrypoint: service.entrypoint, + command: service.command, }, }); @@ -127,6 +131,7 @@ export default function DeploymentSettings() { name="zeroDowntime" friendlyName="Zero Downtime" description="When enabled, old containers will stay running until the new containers are online, alowing for zero-downtime deployments." + render={({ field }) => } /> diff --git a/src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/page.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/page.tsx new file mode 100644 index 0000000..c5ee6e1 --- /dev/null +++ b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/advanced/page.tsx @@ -0,0 +1,17 @@ +import { api } from "~/trpc/server"; +import DeploymentSettings from "./DeploymentSettings"; + +export default async function AdvancedSettings(props: { + params: { projectId: string; serviceId: string }; +}) { + const service = await api.projects.services.get.query({ + serviceId: props.params.serviceId, + projectId: props.params.projectId, + }); + + return ( +
+ +
+ ); +} diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/containers/page.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/containers/page.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/containers/page.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/containers/page.tsx diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/home/page.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/home/page.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/home/page.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/home/page.tsx diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/layout.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/layout.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/layout.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/layout.tsx diff --git a/src/app/(dashboard)/project/[id]/service/[serviceId]/page.tsx b/src/app/(dashboard)/project/[projectId]/service/[serviceId]/page.tsx similarity index 100% rename from src/app/(dashboard)/project/[id]/service/[serviceId]/page.tsx rename to src/app/(dashboard)/project/[projectId]/service/[serviceId]/page.tsx diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx new file mode 100644 index 0000000..1320353 --- /dev/null +++ b/src/components/ui/switch.tsx @@ -0,0 +1,29 @@ +"use client"; + +import * as SwitchPrimitives from "@radix-ui/react-switch"; +import * as React from "react"; + +import { cn } from "~/utils/utils"; + +const Switch = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +Switch.displayName = SwitchPrimitives.Root.displayName; + +export { Switch }; diff --git a/src/hooks/forms.tsx b/src/hooks/forms.tsx index 3a1d312..d4eb03a 100644 --- a/src/hooks/forms.tsx +++ b/src/hooks/forms.tsx @@ -37,10 +37,12 @@ export function useForm, TContext = any>( schema: TSchema, props: UseFormProps, TContext> = {}, ) { - return useFormHook>({ + const form = useFormHook>({ ...props, resolver: zodResolver(schema), }); + + return form; } /** diff --git a/src/server/api/routers/projects/service/index.ts b/src/server/api/routers/projects/service/index.ts index 1746a00..01506a7 100644 --- a/src/server/api/routers/projects/service/index.ts +++ b/src/server/api/routers/projects/service/index.ts @@ -7,7 +7,13 @@ import { projectMiddleware } from "~/server/api/middleware/project"; import { serviceMiddleware } from "~/server/api/middleware/service"; import { authenticatedProcedure, createTRPCRouter } from "~/server/api/trpc"; import { service } from "~/server/db/schema"; -import { DOCKER_DEPLOY_MODE_MAP, ServiceSource } from "~/server/db/types"; +import { + DOCKER_DEPLOY_MODE_MAP, + DockerDeployMode, + DockerRestartCondition, + ServiceBuildMethod, + ServiceSource, +} from "~/server/db/types"; import { zDockerName } from "~/server/utils/zod"; import { getServiceContainers } from "./containers"; @@ -32,7 +38,6 @@ export const serviceRouter = createTRPCRouter({ domains: true, ports: true, volumes: true, - project: true, sysctls: true, ulimits: true, }, @@ -47,6 +52,63 @@ export const serviceRouter = createTRPCRouter({ }; }), + update: authenticatedProcedure + .meta({ + openapi: { + method: "PATCH", + path: "/api/projects/:projectId/services/:serviceId", + summary: "Update service", + }, + }) + .input( + z + .object({ + projectId: z.string(), + serviceId: z.string(), + }) + .merge( + z + .object({ + source: z.nativeEnum(ServiceSource), + environment: z.string(), + dockerImage: z.string(), + dockerRegistryUsername: z.string(), + dockerRegistryPassword: z.string(), + // TODO: restrict to valid github url + githubUrl: z.string().url(), + githubBranch: z.string(), + gitUrl: z.string(), + gitBranch: z.string(), + buildMethod: z.nativeEnum(ServiceBuildMethod), + buildPath: z.string(), + command: z.string(), + entrypoint: z.string(), + replicas: z.number(), + maxReplicasPerNode: z.number(), + deployMode: z.nativeEnum(DockerDeployMode), + zeroDowntime: z.boolean(), + max_cpu: z.number(), + max_memory: z.string(), + max_pids: z.number(), + restart: z.nativeEnum(DockerRestartCondition), + }) + .partial(), + ), + ) + .use(projectMiddleware) + .use(serviceMiddleware) + .mutation(async ({ ctx, input }) => { + await ctx.db + .update(service) + .set({ + name: input.name, + zeroDowntime: input.zeroDowntime ? 1 : 0, + deployMode: input.deployMode, + }) + .where(eq(service.id, ctx.service.id)) + .execute(); + }), + create: authenticatedProcedure .meta({ openapi: { diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 8a71b81..24643a3 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -156,7 +156,7 @@ export const service = sqliteTable( // for github/git buildMethod: integer("build_method").$type(), - buildPath: text("build_path"), + buildPath: text("build_path").default("/").notNull(), // deployment settings command: text("command"), diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ec79801..705f443 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,6 +1,8 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" - +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export type Awaitable = T | Promise; + export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); }