mirror of
https://github.com/moghtech/komodo.git
synced 2026-03-11 17:44:19 -05:00
new deployment / repo from server page
This commit is contained in:
@@ -105,6 +105,7 @@ export const BuildConfig = ({
|
||||
selected={id}
|
||||
onSelect={(builder_id) => set({ builder_id })}
|
||||
disabled={disabled}
|
||||
align="end"
|
||||
/>
|
||||
</ConfigItem>
|
||||
),
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Card, CardHeader } from "@ui/card";
|
||||
import { cn } from "@lib/utils";
|
||||
import { useState } from "react";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs";
|
||||
import { ResourceComponents } from "..";
|
||||
|
||||
const useBuild = (id?: string) =>
|
||||
useRead("ListBuilds", {}).data?.find((d) => d.id === id);
|
||||
@@ -33,6 +34,20 @@ const ConfigOrDeployments = ({ id }: { id: string }) => {
|
||||
(deployment) => deployment.info.build_id === id
|
||||
);
|
||||
const deploymentsDisabled = (deployments?.length || 0) === 0;
|
||||
const titleOther = (
|
||||
<TabsList className="justify-start w-fit">
|
||||
<TabsTrigger value="Config" className="w-[110px]">
|
||||
Config
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="Deployments"
|
||||
className="w-[110px]"
|
||||
disabled={deploymentsDisabled}
|
||||
>
|
||||
Deployments
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
);
|
||||
return (
|
||||
<Tabs
|
||||
value={deploymentsDisabled ? "Config" : view}
|
||||
@@ -40,40 +55,12 @@ const ConfigOrDeployments = ({ id }: { id: string }) => {
|
||||
className="grid gap-4"
|
||||
>
|
||||
<TabsContent value="Config">
|
||||
<BuildConfig
|
||||
id={id}
|
||||
titleOther={
|
||||
<TabsList className="justify-start w-fit">
|
||||
<TabsTrigger value="Config" className="w-[110px]">
|
||||
Config
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="Deployments"
|
||||
className="w-[110px]"
|
||||
disabled={deploymentsDisabled}
|
||||
>
|
||||
Deployments
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
}
|
||||
/>
|
||||
<BuildConfig id={id} titleOther={titleOther} />
|
||||
</TabsContent>
|
||||
<TabsContent value="Deployments">
|
||||
<Section
|
||||
titleOther={
|
||||
<TabsList className="justify-start w-fit">
|
||||
<TabsTrigger value="Config" className="w-[110px]">
|
||||
Config
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="Deployments"
|
||||
className="w-[110px]"
|
||||
disabled={deploymentsDisabled}
|
||||
>
|
||||
Deployments
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
}
|
||||
titleOther={titleOther}
|
||||
actions={<ResourceComponents.Deployment.New build_id={id} />}
|
||||
>
|
||||
<DeploymentTable deployments={deployments} />
|
||||
</Section>
|
||||
|
||||
@@ -108,7 +108,7 @@ export const ResourceSelector = ({
|
||||
{!disabled && <ChevronsUpDown className="w-3 h-3" />}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] max-h-[200px] p-0" align={align}>
|
||||
<PopoverContent className="w-[300px] max-h-[300px] p-0" align={align}>
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder={`Search ${type}s`}
|
||||
@@ -228,17 +228,34 @@ export const CopyResource = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const NewResource = ({ type }: { type: UsableResource }) => {
|
||||
export const NewResource = ({
|
||||
type,
|
||||
server_id,
|
||||
build_id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
server_id?: string;
|
||||
build_id?: string;
|
||||
}) => {
|
||||
const nav = useNavigate();
|
||||
const { mutateAsync } = useWrite(`Create${type}`);
|
||||
const [name, setName] = useState("");
|
||||
const type_display =
|
||||
type === "ServerTemplate" ? "server-template" : type.toLowerCase();
|
||||
const config =
|
||||
type === "Deployment"
|
||||
? {
|
||||
server_id,
|
||||
image: build_id ?? { type: "Build", params: { build_id } },
|
||||
}
|
||||
: type === "Repo"
|
||||
? { server_id }
|
||||
: {};
|
||||
return (
|
||||
<NewLayout
|
||||
entityType={type}
|
||||
onSuccess={async () => {
|
||||
const id = (await mutateAsync({ name, config: {} }))._id?.$oid!;
|
||||
const id = (await mutateAsync({ name, config }))._id?.$oid!;
|
||||
nav(`/${usableResourcePath(type)}/${id}`);
|
||||
}}
|
||||
enabled={!!name}
|
||||
|
||||
@@ -103,7 +103,9 @@ export const DeploymentComponents: RequiredResourceComponents = {
|
||||
|
||||
Dashboard: DeploymentsChart,
|
||||
|
||||
New: () => <NewResource type="Deployment" />,
|
||||
New: ({ server_id, build_id }) => (
|
||||
<NewResource type="Deployment" server_id={server_id} build_id={build_id} />
|
||||
),
|
||||
|
||||
Table: ({ search }) => {
|
||||
const deployments = useRead("ListDeployments", {}).data;
|
||||
|
||||
@@ -174,12 +174,12 @@ const Log = ({
|
||||
useEffect(scroll, [_log]);
|
||||
return (
|
||||
<>
|
||||
<div ref={ref} className="h-[80vh] overflow-y-auto">
|
||||
<div ref={ref} className="h-[75vh] overflow-y-auto">
|
||||
<pre
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: _log ? logToHtml(_log) : `no ${stream} logs`,
|
||||
}}
|
||||
className="-scroll-mt-24"
|
||||
className="-scroll-mt-24 pb-[20vh]"
|
||||
/>
|
||||
</div>
|
||||
<Button variant="secondary" className="absolute top-4 right-4" onClick={scroll}>
|
||||
|
||||
@@ -32,7 +32,7 @@ export const RepoComponents: RequiredResourceComponents = {
|
||||
|
||||
Dashboard: RepoDashboard,
|
||||
|
||||
New: () => <NewResource type="Repo" />,
|
||||
New: ({ server_id }) => <NewResource type="Repo" server_id={server_id} />,
|
||||
|
||||
Table: ({ search }) => {
|
||||
const repos = useRead("ListRepos", {}).data;
|
||||
|
||||
@@ -31,6 +31,7 @@ import { Button } from "@ui/button";
|
||||
import { useState } from "react";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs";
|
||||
import { RepoTable } from "../repo/table";
|
||||
import { ResourceComponents } from "..";
|
||||
|
||||
export const useServer = (id?: string) =>
|
||||
useRead("ListServers", {}, { refetchInterval: 5000 }).data?.find(
|
||||
@@ -88,13 +89,19 @@ const ConfigOrChildResources = ({ id }: { id: string }) => {
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="Deployments">
|
||||
<Section titleOther={tabsList}>
|
||||
<Section
|
||||
titleOther={tabsList}
|
||||
actions={<ResourceComponents.Deployment.New server_id={id} />}
|
||||
>
|
||||
<DeploymentTable deployments={deployments} />
|
||||
</Section>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="Repos">
|
||||
<Section titleOther={tabsList}>
|
||||
<Section
|
||||
titleOther={tabsList}
|
||||
actions={<ResourceComponents.Repo.New server_id={id} />}
|
||||
>
|
||||
<RepoTable repos={repos} />
|
||||
</Section>
|
||||
</TabsContent>
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { UsableResource } from "@types";
|
||||
import { useToast } from "@ui/use-toast";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// ============== RESOLVER ==============
|
||||
@@ -291,3 +291,25 @@ export const useFilterResources = <Info>(
|
||||
) ?? []
|
||||
);
|
||||
};
|
||||
|
||||
export type LocalStorageSetter<T> = (state: T) => T;
|
||||
|
||||
export const useLocalStorage = <T>(
|
||||
key: string,
|
||||
init: T
|
||||
): [T, (state: T | LocalStorageSetter<T>) => void] => {
|
||||
const stored = localStorage.getItem(key);
|
||||
const parsed = stored ? (JSON.parse(stored) as T) : undefined;
|
||||
const [state, inner_set] = useState<T>(parsed ?? init);
|
||||
const set = (state: T | LocalStorageSetter<T>) => {
|
||||
inner_set((prev_state) => {
|
||||
const new_val =
|
||||
typeof state === "function"
|
||||
? (state as LocalStorageSetter<T>)(prev_state)
|
||||
: state;
|
||||
localStorage.setItem(key, JSON.stringify(new_val));
|
||||
return new_val;
|
||||
});
|
||||
};
|
||||
return [state, set];
|
||||
};
|
||||
|
||||
@@ -50,7 +50,8 @@ export const Tree = () => {
|
||||
|
||||
const Server = ({ id }: { id: string }) => {
|
||||
const [search] = useAtom(searchAtom);
|
||||
const [open, setOpen] = useState(true);
|
||||
// const [open, setOpen] = useLocalStorage(`server-tree-open-${id}`, false);
|
||||
const [open, setOpen] = useState(false);
|
||||
const server = useRead("ListServers", {}).data?.find(
|
||||
(server) => server.id === id
|
||||
);
|
||||
|
||||
2
frontend/src/types.d.ts
vendored
2
frontend/src/types.d.ts
vendored
@@ -12,7 +12,7 @@ export interface RequiredResourceComponents {
|
||||
Dashboard: React.FC;
|
||||
|
||||
/** New resource button / dialog */
|
||||
New: React.FC;
|
||||
New: React.FC<{ server_id?: string; build_id?: string }>;
|
||||
|
||||
/** A table component to view resource list */
|
||||
Table: React.FC<{ search?: string }>;
|
||||
|
||||
Reference in New Issue
Block a user