-
-
+
-
*/}
>
);
};
diff --git a/frontend/src/pages/deployment/components/deployment-logs.tsx b/frontend/src/pages/deployment/components/deployment-logs.tsx
new file mode 100644
index 000000000..f071e45c3
--- /dev/null
+++ b/frontend/src/pages/deployment/components/deployment-logs.tsx
@@ -0,0 +1,65 @@
+import { Button } from "@ui/button";
+import { Card, CardHeader, CardContent } from "@ui/card";
+import { Tabs, TabsList, TabsTrigger } from "@ui/tabs";
+// import { useDeploymentLog } from "@hooks/deployments";
+import { TabsContent } from "@radix-ui/react-tabs";
+import { AlertOctagon, ChevronDown } from "lucide-react";
+import { useEffect } from "react";
+import { useRead } from "@hooks";
+
+const scroll_to_bottom = (id: string) => () =>
+ document
+ .getElementById(id)
+ ?.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
+
+export const DeploymentLogs = ({ deploymentId }: { deploymentId: string }) => {
+ const { data, refetch } = useRead({
+ type: "GetLog",
+ params: { deployment_id: deploymentId, tail: 200 },
+ });
+
+ useEffect(() => {
+ const handle = setInterval(() => refetch(), 30000);
+ return () => clearInterval(handle);
+ }, [refetch]);
+
+ useEffect(() => {
+ scroll_to_bottom("stdout")();
+ scroll_to_bottom("stderr")();
+ }, [data]);
+
+ return (
+
+
+
+
+
+ Out
+
+
+ Err
+ {data?.stderr && (
+
+ )}
+
+
+
+ {["stdout", "stderr"].map((t) => (
+
+
+
+ {data?.[t as keyof typeof data] || `no ${t} logs`}
+
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/frontend/src/pages/deployment/index.tsx b/frontend/src/pages/deployment/index.tsx
new file mode 100644
index 000000000..1ed9c68f1
--- /dev/null
+++ b/frontend/src/pages/deployment/index.tsx
@@ -0,0 +1,126 @@
+// import { DeploymentLogs } from "@pages/resource/deployment/components/logs";
+import { Resource } from "@layouts/resource";
+// import { Updates } from "@components/updates";
+import { useParams } from "react-router-dom";
+import { CardDescription } from "@ui/card";
+// import { DeploymentConfig } from "@pages/resource/deployment/components/config";
+// import {
+// RedeployContainer,
+// StartOrStopContainer,
+// RemoveContainer,
+// } from "@pages/resource/deployment/components/actions";
+// import { DeleteDeployment } from "@pages/resource/deployment/components/delete";
+import { useRead, useSetRecentlyViewed } from "@hooks";
+import { Circle } from "lucide-react";
+import { cn } from "@util/helpers";
+import { DeploymentLogs } from "./components/deployment-logs";
+import { Updates } from "@components/updates/updates";
+
+export const DeploymentName = ({
+ deploymentId,
+}: {
+ deploymentId: string | undefined;
+}) => {
+ const deployments = useRead({ type: "ListDeployments", params: {} }).data;
+ const deployment = deployments?.find((d) => d.id === deploymentId);
+ return <>{deployment?.name ?? "..."}>;
+};
+
+export const DeploymentStatus = ({
+ deploymentId,
+}: {
+ deploymentId: string | undefined;
+}) => {
+ const deployments = useRead({ type: "ListDeployments", params: {} }).data;
+ const deployment = deployments?.find((d) => d.id === deploymentId);
+ return <>{deployments ? deployment?.status ?? "not deployed" : "..."}>;
+};
+
+export const DeploymentStatusIcon = ({
+ deploymentId,
+}: {
+ deploymentId: string | undefined;
+}) => {
+ const deployments = useRead({ type: "ListDeployments", params: {} }).data;
+ const deployment = deployments?.find((d) => d.id === deploymentId);
+ return (
+
+ );
+};
+
+// export const DeploymentInfo = ({ deploymentId }: { deploymentId: string }) => {
+// const deployments = useRead({ type: "ListDeployments", params: {} }).data;
+// const deployment = deployments?.find((d) => d.id === deploymentId);
+
+// return (
+//
+//
+//
+//
+// {data ? deployment?.container?.image ?? "no image" : "..."}
+//
+//
+//
+//
+//
+//
+//
+//
+//
+// );
+// };
+
+export const Deployment = () => {
+ const { deploymentId } = useParams();
+ const push = useSetRecentlyViewed();
+
+ if (!deploymentId) return null;
+ push("Deployment", deploymentId);
+
+ return (
+
}
+ info={
+
+
deployment info
+ {/*
*/}
+
|
+
+
+
+
+
|
+ {/*
*/}
+
+ }
+ actions={
+ <>
+ {/*
+
+
*/}
+ >
+ }
+ tabs={[
+ {
+ title: "Logs",
+ component:
,
+ },
+ {
+ title: "Config",
+ component: <>Config>,
+ },
+ {
+ title: "Updates",
+ component: <>Updates>,
+ },
+ ]}
+ />
+ );
+};
diff --git a/frontend/src/pages/server/index.tsx b/frontend/src/pages/server/index.tsx
index 2218c9da8..0b8050cba 100644
--- a/frontend/src/pages/server/index.tsx
+++ b/frontend/src/pages/server/index.tsx
@@ -1,4 +1,4 @@
-import { useRead } from "@hooks";
+import { useRead, useSetRecentlyViewed } from "@hooks";
import { Resource } from "@layouts/resource";
import { ServerStatus } from "@monitor/client/dist/types";
import { CardDescription } from "@ui/card";
@@ -83,7 +83,12 @@ export const ServerStatusIcon = ({
export const Server = () => {
const { serverId } = useParams();
- // const { data } = useRead({ type: "GetServer", params: { id: serverId! } });
+ const push = useSetRecentlyViewed();
+
+ // if (!serverId) return null;
+ // push("Server", serverId!);
+ if (!serverId) return null;
+ push("Server", serverId);
return (
},
{ path: "signup", element:
},
- // {
- // path: "deployments",
- // children: [
- // { path: "", element:
},
- // { path: ":deploymentId", element:
},
- // ],
- // },
+ {
+ path: "deployments",
+ children: [
+ { path: "", element: "deploymenys" },
+ { path: ":deploymentId", element:
},
+ ],
+ },
// {
// path: "builds",
// children: [
diff --git a/frontend/src/util/helpers.ts b/frontend/src/util/helpers.ts
index a0f5861a7..014c3d706 100644
--- a/frontend/src/util/helpers.ts
+++ b/frontend/src/util/helpers.ts
@@ -62,7 +62,7 @@ export function readableMonitorTimestamp(rfc3339_ts: string) {
} ${pm ? "PM" : "AM"}`;
}
-export function readableDuration(start_ts: string, end_ts: string) {
+export function readableDuration(start_ts: number, end_ts: number) {
const start = new Date(start_ts);
const end = new Date(end_ts);
const durr = end.getTime() - start.getTime();
@@ -146,7 +146,9 @@ export function copyToClipboard(text: string) {
navigator.clipboard.writeText(text);
}
-export function parseEnvVarseToDotEnv(envVars: Types.EnvironmentVar[] | undefined) {
+export function parseEnvVarseToDotEnv(
+ envVars: Types.EnvironmentVar[] | undefined
+) {
return envVars?.reduce(
(prev, { variable, value }) =>
prev + (prev ? "\n" : "") + `${variable}=${value}`,
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index a297d5b21..d32f9f39b 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -5,9 +5,9 @@ import tsconfigPaths from "vite-tsconfig-paths";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), tsconfigPaths()],
- resolve: {
- alias: {
- "@monitor/client": "../client/ts"
- }
- }
+ // resolve: {
+ // alias: {
+ // "@monitor/client": "../client/ts"
+ // }
+ // }
});