forked from github-starred/komodo
add ListPermissions route
This commit is contained in:
@@ -43,6 +43,7 @@ enum ReadRequest {
|
||||
GetUsers(GetUsers),
|
||||
GetUsername(GetUsername),
|
||||
ListApiKeys(ListApiKeys),
|
||||
ListPermissions(ListPermissions),
|
||||
ListUserPermissions(ListUserPermissions),
|
||||
|
||||
// ==== USER GROUP ====
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use axum::async_trait;
|
||||
use monitor_client::{
|
||||
api::read::{ListUserPermissions, ListUserPermissionsResponse},
|
||||
api::read::{
|
||||
ListPermissions, ListPermissionsResponse, ListUserPermissions,
|
||||
ListUserPermissionsResponse,
|
||||
},
|
||||
entities::user::User,
|
||||
};
|
||||
use mungos::{find::find_collect, mongodb::bson::doc};
|
||||
@@ -9,6 +12,26 @@ use resolver_api::Resolve;
|
||||
|
||||
use crate::{db::db_client, state::State};
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<ListPermissions, User> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
ListPermissions {}: ListPermissions,
|
||||
user: User,
|
||||
) -> anyhow::Result<ListPermissionsResponse> {
|
||||
find_collect(
|
||||
&db_client().await.permissions,
|
||||
doc! {
|
||||
"user_target.type": "User",
|
||||
"user_target.id": &user.id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.context("failed to query db for permissions")
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<ListUserPermissions, User> for State {
|
||||
async fn resolve(
|
||||
|
||||
@@ -7,6 +7,21 @@ use crate::entities::permission::Permission;
|
||||
|
||||
use super::MonitorReadRequest;
|
||||
|
||||
/// List permissions for the calling user. Response: [ListPermissionsResponse]
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
)]
|
||||
#[empty_traits(MonitorReadRequest)]
|
||||
#[response(ListPermissionsResponse)]
|
||||
pub struct ListPermissions {}
|
||||
|
||||
#[typeshare]
|
||||
pub type ListPermissionsResponse = Vec<Permission>;
|
||||
|
||||
//
|
||||
|
||||
/// List permissions for a specific user. Admin only. Response: [ListUserPermissionsResponse]
|
||||
#[typeshare]
|
||||
#[derive(
|
||||
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
|
||||
|
||||
@@ -16,6 +16,7 @@ export type ReadResponses = {
|
||||
GetUsers: Types.GetUsersResponse;
|
||||
GetUsername: Types.GetUsernameResponse;
|
||||
ListApiKeys: Types.ListApiKeysResponse;
|
||||
ListPermissions: Types.ListPermissionsResponse;
|
||||
ListUserPermissions: Types.ListUserPermissionsResponse;
|
||||
|
||||
// ==== USER GROUP ====
|
||||
|
||||
@@ -549,6 +549,8 @@ export interface Permission {
|
||||
level?: PermissionLevel;
|
||||
}
|
||||
|
||||
export type ListPermissionsResponse = Permission[];
|
||||
|
||||
export type ListUserPermissionsResponse = Permission[];
|
||||
|
||||
export enum ProcedureType {
|
||||
@@ -1457,6 +1459,11 @@ export interface GetCoreInfoResponse {
|
||||
github_webhook_base_url: string;
|
||||
}
|
||||
|
||||
/** List permissions for the calling user. Response: [ListPermissionsResponse] */
|
||||
export interface ListPermissions {
|
||||
}
|
||||
|
||||
/** List permissions for a specific user. Admin only. Response: [ListUserPermissionsResponse] */
|
||||
export interface ListUserPermissions {
|
||||
user_id: string;
|
||||
}
|
||||
@@ -2108,6 +2115,7 @@ export type ReadRequest =
|
||||
| { type: "GetUsers", params: GetUsers }
|
||||
| { type: "GetUsername", params: GetUsername }
|
||||
| { type: "ListApiKeys", params: ListApiKeys }
|
||||
| { type: "ListPermissions", params: ListPermissions }
|
||||
| { type: "ListUserPermissions", params: ListUserPermissions }
|
||||
| { type: "GetUserGroup", params: GetUserGroup }
|
||||
| { type: "ListUserGroups", params: ListUserGroups }
|
||||
|
||||
@@ -26,12 +26,14 @@ export const ConfigLayout = <
|
||||
>({
|
||||
config,
|
||||
children,
|
||||
disabled,
|
||||
onConfirm,
|
||||
onReset,
|
||||
selector,
|
||||
}: {
|
||||
config: Partial<T>;
|
||||
children: ReactNode;
|
||||
disabled: boolean;
|
||||
onConfirm: () => void;
|
||||
onReset: () => void;
|
||||
selector?: ReactNode;
|
||||
@@ -45,7 +47,7 @@ export const ConfigLayout = <
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onReset}
|
||||
disabled={config ? !Object.keys(config).length : true}
|
||||
disabled={disabled || (config ? !Object.keys(config).length : true)}
|
||||
>
|
||||
<History className="w-4 h-4" />
|
||||
</Button>
|
||||
@@ -53,6 +55,7 @@ export const ConfigLayout = <
|
||||
<ConfirmUpdate
|
||||
content={JSON.stringify(config, null, 2)}
|
||||
onConfirm={onConfirm}
|
||||
disabled={disabled}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
@@ -65,6 +68,7 @@ export const ConfigLayout = <
|
||||
export const Config = <T,>({
|
||||
config,
|
||||
update,
|
||||
disabled,
|
||||
set,
|
||||
onSave,
|
||||
components,
|
||||
@@ -72,6 +76,7 @@ export const Config = <T,>({
|
||||
}: {
|
||||
config: T;
|
||||
update: Partial<T>;
|
||||
disabled: boolean;
|
||||
set: React.Dispatch<SetStateAction<Partial<T>>>;
|
||||
onSave: () => void;
|
||||
selector?: ReactNode;
|
||||
@@ -93,11 +98,14 @@ export const Config = <T,>({
|
||||
return (
|
||||
<ConfigLayout
|
||||
config={update}
|
||||
disabled={disabled}
|
||||
onConfirm={onSave}
|
||||
onReset={() => set({})}
|
||||
selector={
|
||||
<div className="flex gap-4 items-center">
|
||||
{selector}
|
||||
|
||||
{/* Add the config page selector when view is small / md (lg:hidden) */}
|
||||
<Select value={show} onValueChange={setShow}>
|
||||
<SelectTrigger className="w-32 capitalize lg:hidden">
|
||||
<SelectValue />
|
||||
@@ -140,6 +148,7 @@ export const Config = <T,>({
|
||||
update={update}
|
||||
set={(u) => set((p) => ({ ...p, ...u }))}
|
||||
components={v}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -155,11 +164,13 @@ export const ConfigAgain = <
|
||||
>({
|
||||
config,
|
||||
update,
|
||||
disabled,
|
||||
components,
|
||||
set,
|
||||
}: {
|
||||
config: T;
|
||||
update: Partial<T>;
|
||||
disabled: boolean;
|
||||
components: Partial<{
|
||||
[K in keyof T extends string ? keyof T : never]:
|
||||
| boolean
|
||||
@@ -181,6 +192,7 @@ export const ConfigAgain = <
|
||||
label={key.toString()}
|
||||
value={value}
|
||||
onChange={(value) => set({ [key]: value } as Partial<T>)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
case "number":
|
||||
@@ -192,6 +204,7 @@ export const ConfigAgain = <
|
||||
onChange={(value) =>
|
||||
set({ [key]: Number(value) } as Partial<T>)
|
||||
}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
case "boolean":
|
||||
@@ -201,6 +214,7 @@ export const ConfigAgain = <
|
||||
label={key.toString()}
|
||||
value={value}
|
||||
onChange={(value) => set({ [key]: value } as Partial<T>)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
|
||||
@@ -30,7 +30,7 @@ export const ConfigItem = ({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
label: string;
|
||||
label?: string;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}) => (
|
||||
@@ -40,7 +40,7 @@ export const ConfigItem = ({
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div>{snake_case_to_upper_space_case(label)}</div>
|
||||
{label && <div>{snake_case_to_upper_space_case(label)}</div>}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -48,17 +48,17 @@ export const ConfigItem = ({
|
||||
export const ConfigInput = ({
|
||||
label,
|
||||
value,
|
||||
placeholder,
|
||||
disabled,
|
||||
placeholder,
|
||||
onChange,
|
||||
onBlur,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number | undefined;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
onChange?: (value: string) => void;
|
||||
onBlur?: (value: string) => void;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
}) => (
|
||||
<ConfigItem label={label}>
|
||||
<Input
|
||||
@@ -76,14 +76,16 @@ export const ConfigInput = ({
|
||||
export const ConfigSwitch = ({
|
||||
label,
|
||||
value,
|
||||
disabled,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
value: boolean | undefined;
|
||||
disabled: boolean;
|
||||
onChange: (value: boolean) => void;
|
||||
}) => (
|
||||
<ConfigItem label={label}>
|
||||
<Switch checked={value} onCheckedChange={onChange} />
|
||||
<Switch checked={value} onCheckedChange={onChange} disabled={disabled} />
|
||||
</ConfigItem>
|
||||
);
|
||||
|
||||
@@ -93,6 +95,7 @@ export const DoubleInput = <
|
||||
L extends T[K] extends string | number | undefined ? K : never,
|
||||
R extends T[K] extends string | number | undefined ? K : never
|
||||
>({
|
||||
disabled,
|
||||
values,
|
||||
leftval,
|
||||
leftpl,
|
||||
@@ -105,6 +108,7 @@ export const DoubleInput = <
|
||||
onRemove,
|
||||
inputClassName,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
values: T[] | undefined;
|
||||
leftval: L;
|
||||
leftpl: string;
|
||||
@@ -126,6 +130,7 @@ export const DoubleInput = <
|
||||
value={value[leftval] as any}
|
||||
placeholder={leftpl}
|
||||
onChange={(e) => onLeftChange(e.target.value as T[L], i)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
:
|
||||
<Input
|
||||
@@ -133,34 +138,38 @@ export const DoubleInput = <
|
||||
value={value[rightval] as any}
|
||||
placeholder={rightpl}
|
||||
onChange={(e) => onRightChange(e.target.value as T[R], i)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => onRemove(i)}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button variant="secondary" onClick={() => onRemove(i)}>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="flex items-center gap-2 w-[200px] place-self-end"
|
||||
onClick={onAdd}
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" />
|
||||
Add {addName}
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="flex items-center gap-2 w-[200px] place-self-end"
|
||||
onClick={onAdd}
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" />
|
||||
Add {addName}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AccountSelector = ({
|
||||
disabled,
|
||||
id,
|
||||
type,
|
||||
account_type,
|
||||
selected,
|
||||
onSelect,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
id: string | undefined;
|
||||
type: "Server" | "Builder";
|
||||
account_type: keyof Types.GetBuilderAvailableAccountsResponse;
|
||||
@@ -177,10 +186,11 @@ export const AccountSelector = ({
|
||||
<Select
|
||||
value={type === "Builder" ? selected || undefined : selected}
|
||||
onValueChange={onSelect}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger
|
||||
className="w-full lg:w-[300px] max-w-[50%]"
|
||||
disabled={!id}
|
||||
disabled={disabled || !id}
|
||||
>
|
||||
<SelectValue
|
||||
placeholder={type === "Server" ? "Same as build" : "Select Account"}
|
||||
@@ -204,10 +214,12 @@ export const AccountSelector = ({
|
||||
export const InputList = <T extends { [key: string]: unknown }>({
|
||||
field,
|
||||
values,
|
||||
disabled,
|
||||
set,
|
||||
}: {
|
||||
field: keyof T;
|
||||
values: string[];
|
||||
disabled: boolean;
|
||||
set: (update: Partial<T>) => void;
|
||||
}) => (
|
||||
<ConfigItem label={field as string} className="items-start">
|
||||
@@ -221,28 +233,31 @@ export const InputList = <T extends { [key: string]: unknown }>({
|
||||
values[i] = e.target.value;
|
||||
set({ [field]: [...values] } as Partial<T>);
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
// intent="warning"
|
||||
onClick={() =>
|
||||
set({
|
||||
[field]: [...values.filter((_, idx) => idx !== i)],
|
||||
} as Partial<T>)
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
set({
|
||||
[field]: [...values.filter((_, idx) => idx !== i)],
|
||||
} as Partial<T>)
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
// intent="success"
|
||||
onClick={() => set({ [field]: [...values, ""] } as Partial<T>)}
|
||||
>
|
||||
Add {snake_case_to_upper_space_case(field as string).slice(0, -1)}
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => set({ [field]: [...values, ""] } as Partial<T>)}
|
||||
>
|
||||
Add {snake_case_to_upper_space_case(field as string).slice(0, -1)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</ConfigItem>
|
||||
);
|
||||
@@ -250,14 +265,19 @@ export const InputList = <T extends { [key: string]: unknown }>({
|
||||
interface ConfirmUpdateProps {
|
||||
content: string;
|
||||
onConfirm: () => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export const ConfirmUpdate = ({ content, onConfirm }: ConfirmUpdateProps) => {
|
||||
export const ConfirmUpdate = ({
|
||||
content,
|
||||
onConfirm,
|
||||
disabled,
|
||||
}: ConfirmUpdateProps) => {
|
||||
const [open, set] = useState(false);
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={set}>
|
||||
<DialogTrigger asChild>
|
||||
<Button onClick={() => set(true)}>
|
||||
<Button onClick={() => set(true)} disabled={disabled}>
|
||||
<Save className="w-4 h-4" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
@@ -287,10 +307,12 @@ export const ConfirmUpdate = ({ content, onConfirm }: ConfirmUpdateProps) => {
|
||||
export const SystemCommand = ({
|
||||
label,
|
||||
value,
|
||||
disabled,
|
||||
set,
|
||||
}: {
|
||||
label: string;
|
||||
value?: Types.SystemCommand;
|
||||
disabled: boolean;
|
||||
set: (value: Types.SystemCommand) => void;
|
||||
}) => {
|
||||
return (
|
||||
@@ -303,6 +325,7 @@ export const SystemCommand = ({
|
||||
value={value?.path}
|
||||
className="w-[300px]"
|
||||
onChange={(e) => set({ ...(value || {}), path: e.target.value })}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 items-center justify-end">
|
||||
@@ -312,6 +335,7 @@ export const SystemCommand = ({
|
||||
value={value?.command}
|
||||
className="w-[300px]"
|
||||
onChange={(e) => set({ ...(value || {}), command: e.target.value })}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -158,7 +158,7 @@ const BuildArgs = ({
|
||||
}, [args, set]);
|
||||
|
||||
return (
|
||||
<ConfigItem label="Build Args" className="flex-col gap-4 items-start">
|
||||
<ConfigItem className="flex-col gap-4 items-start">
|
||||
<Textarea
|
||||
className="min-h-[300px]"
|
||||
placeholder="VARIABLE=value"
|
||||
|
||||
@@ -9,10 +9,12 @@ import { RefObject, createRef, useEffect, useState } from "react";
|
||||
export const EnvVars = ({
|
||||
vars,
|
||||
set,
|
||||
disabled,
|
||||
server,
|
||||
}: {
|
||||
vars: Types.EnvironmentVar[];
|
||||
set: (input: Partial<Types.DeploymentConfig>) => void;
|
||||
disabled: boolean;
|
||||
/// eg server id
|
||||
server?: string;
|
||||
}) => {
|
||||
@@ -23,11 +25,8 @@ export const EnvVars = ({
|
||||
}, [env, set]);
|
||||
|
||||
return (
|
||||
<ConfigItem
|
||||
label="Environment Variables"
|
||||
className="flex-col gap-4 items-start"
|
||||
>
|
||||
{server && (
|
||||
<ConfigItem className="flex-col gap-4 items-start">
|
||||
{!disabled && server && (
|
||||
<Secrets server={server} env={env} setEnv={setEnv} envRef={ref} />
|
||||
)}
|
||||
<Textarea
|
||||
@@ -58,10 +57,11 @@ const Secrets = ({
|
||||
return (
|
||||
secrets &&
|
||||
secrets.length > 0 && (
|
||||
<div className="w-full flex gap-4 justify-end items-center">
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="text-muted-foreground">secrets:</div>
|
||||
{secrets?.map((secret) => (
|
||||
<Button
|
||||
variant="secondary"
|
||||
key={secret}
|
||||
onClick={() =>
|
||||
setEnv(
|
||||
|
||||
@@ -7,9 +7,11 @@ import { MinusCircle, PlusCircle } from "lucide-react";
|
||||
export const ExtraArgs = ({
|
||||
args,
|
||||
set,
|
||||
disabled,
|
||||
}: {
|
||||
args: string[];
|
||||
set: (update: Partial<Types.DeploymentConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<ConfigItem label="Extra Args" className="items-start">
|
||||
@@ -23,25 +25,30 @@ export const ExtraArgs = ({
|
||||
args[i] = e.target.value;
|
||||
set({ extra_args: [...args] });
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
set({ extra_args: [...args.filter((_, idx) => idx !== i)] })
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
set({ extra_args: [...args.filter((_, idx) => idx !== i)] })
|
||||
}
|
||||
>
|
||||
<MinusCircle className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="flex items-center gap-2 w-[200px] place-self-end"
|
||||
onClick={() => set({ extra_args: [...args, ""] })}
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" /> Add Extra Arg
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="flex items-center gap-2 w-[200px] place-self-end"
|
||||
onClick={() => set({ extra_args: [...args, ""] })}
|
||||
>
|
||||
<PlusCircle className="w-4 h-4" /> Add Extra Arg
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</ConfigItem>
|
||||
);
|
||||
|
||||
@@ -14,10 +14,12 @@ import {
|
||||
} from "@ui/select";
|
||||
|
||||
const BuildVersionSelector = ({
|
||||
disabled,
|
||||
buildId,
|
||||
selected,
|
||||
onSelect,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
buildId: string | undefined;
|
||||
selected: string | undefined;
|
||||
onSelect: (version: string) => void;
|
||||
@@ -28,8 +30,12 @@ const BuildVersionSelector = ({
|
||||
{ enabled: !!buildId }
|
||||
).data;
|
||||
return (
|
||||
<Select value={selected || undefined} onValueChange={onSelect}>
|
||||
<SelectTrigger className="w-full lg:w-[150px]">
|
||||
<Select
|
||||
value={selected || undefined}
|
||||
onValueChange={onSelect}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger className="w-full lg:w-[150px]" disabled={disabled}>
|
||||
<SelectValue placeholder="Select Version" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -70,9 +76,11 @@ const ImageTypeSelector = ({
|
||||
export const ImageConfig = ({
|
||||
image,
|
||||
set,
|
||||
disabled,
|
||||
}: {
|
||||
image: Types.DeploymentImage | undefined;
|
||||
set: (input: Partial<Types.DeploymentConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => (
|
||||
<ConfigItem label="Image">
|
||||
<div className="flex gap-4 w-full justify-end">
|
||||
@@ -121,6 +129,7 @@ export const ImageConfig = ({
|
||||
},
|
||||
})
|
||||
}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -14,16 +14,19 @@ const format_mode = (m: string) => m.split("-").join(" ");
|
||||
export const RestartModeSelector = ({
|
||||
selected,
|
||||
set,
|
||||
disabled,
|
||||
}: {
|
||||
selected: Types.RestartMode | undefined;
|
||||
set: (input: Partial<Types.DeploymentConfig>) => void;
|
||||
disabled: boolean;
|
||||
}) => (
|
||||
<ConfigItem label="Restart Mode">
|
||||
<Select
|
||||
value={selected || undefined}
|
||||
onValueChange={(restart: Types.RestartMode) => set({ restart })}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger className="max-w-[150px] capitalize">
|
||||
<SelectTrigger className="max-w-[150px] capitalize" disabled={disabled}>
|
||||
<SelectValue placeholder="Select Type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
||||
@@ -38,6 +38,7 @@ export const ServerSelector = ({
|
||||
);
|
||||
|
||||
export const DeploymentConfig = ({ id }: { id: string }) => {
|
||||
// const perms = useRead("ListPerm")
|
||||
const config = useRead("GetDeployment", { deployment: id }).data?.config;
|
||||
const [update, set] = useState<Partial<Types.DeploymentConfig>>({});
|
||||
const { mutate } = useWrite("UpdateDeployment");
|
||||
|
||||
Reference in New Issue
Block a user