forked from github-starred/komodo
ensure sync directory exist
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
use std::fs;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use monitor_client::entities::{
|
use monitor_client::entities::{
|
||||||
sync::ResourceSync, to_monitor_name, toml::ResourcesToml,
|
sync::ResourceSync, to_monitor_name, toml::ResourcesToml,
|
||||||
@@ -32,6 +34,9 @@ pub async fn get_remote_resources(
|
|||||||
.transpose()?
|
.transpose()?
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
|
fs::create_dir_all(&config.sync_directory)
|
||||||
|
.context("failed to create sync directory")?;
|
||||||
|
|
||||||
let mut logs =
|
let mut logs =
|
||||||
git::clone(clone_args, &config.sync_directory, github_token)
|
git::clone(clone_args, &config.sync_directory, github_token)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ export const AccountSelector = ({
|
|||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
className="w-full lg:w-[200px] max-w-[50%]"
|
className="w-full lg:w-[200px] max-w-[50%]"
|
||||||
disabled={disabled || !id}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<SelectValue placeholder={placeholder} />
|
<SelectValue placeholder={placeholder} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
|||||||
@@ -49,7 +49,11 @@ export const ResourceDescription = ({
|
|||||||
const inv = useInvalidate();
|
const inv = useInvalidate();
|
||||||
|
|
||||||
const key =
|
const key =
|
||||||
type === "ServerTemplate" ? "server_template" : type.toLowerCase();
|
type === "ServerTemplate"
|
||||||
|
? "server_template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "sync"
|
||||||
|
: type.toLowerCase();
|
||||||
|
|
||||||
const resource = useRead(`Get${type}`, {
|
const resource = useRead(`Get${type}`, {
|
||||||
[key]: id,
|
[key]: id,
|
||||||
@@ -244,10 +248,12 @@ export const CopyResource = ({
|
|||||||
|
|
||||||
export const NewResource = ({
|
export const NewResource = ({
|
||||||
type,
|
type,
|
||||||
|
readable_type,
|
||||||
server_id,
|
server_id,
|
||||||
build_id,
|
build_id,
|
||||||
}: {
|
}: {
|
||||||
type: UsableResource;
|
type: UsableResource;
|
||||||
|
readable_type?: string;
|
||||||
server_id?: string;
|
server_id?: string;
|
||||||
build_id?: string;
|
build_id?: string;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -255,7 +261,11 @@ export const NewResource = ({
|
|||||||
const { mutateAsync } = useWrite(`Create${type}`);
|
const { mutateAsync } = useWrite(`Create${type}`);
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const type_display =
|
const type_display =
|
||||||
type === "ServerTemplate" ? "server-template" : type.toLowerCase();
|
type === "ServerTemplate"
|
||||||
|
? "server-template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "resource-sync"
|
||||||
|
: type.toLowerCase();
|
||||||
const config =
|
const config =
|
||||||
type === "Deployment"
|
type === "Deployment"
|
||||||
? {
|
? {
|
||||||
@@ -267,7 +277,7 @@ export const NewResource = ({
|
|||||||
: {};
|
: {};
|
||||||
return (
|
return (
|
||||||
<NewLayout
|
<NewLayout
|
||||||
entityType={type}
|
entityType={readable_type ?? type}
|
||||||
onSuccess={async () => {
|
onSuccess={async () => {
|
||||||
const id = (await mutateAsync({ name, config }))._id?.$oid!;
|
const id = (await mutateAsync({ name, config }))._id?.$oid!;
|
||||||
nav(`/${usableResourcePath(type)}/${id}`);
|
nav(`/${usableResourcePath(type)}/${id}`);
|
||||||
@@ -276,7 +286,7 @@ export const NewResource = ({
|
|||||||
onOpenChange={() => setName("")}
|
onOpenChange={() => setName("")}
|
||||||
>
|
>
|
||||||
<div className="grid md:grid-cols-2 items-center">
|
<div className="grid md:grid-cols-2 items-center">
|
||||||
{type} Name
|
{readable_type ?? type} Name
|
||||||
<Input
|
<Input
|
||||||
placeholder={`${type_display}-name`}
|
placeholder={`${type_display}-name`}
|
||||||
value={name}
|
value={name}
|
||||||
@@ -296,7 +306,11 @@ export const DeleteResource = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const nav = useNavigate();
|
const nav = useNavigate();
|
||||||
const key =
|
const key =
|
||||||
type === "ServerTemplate" ? "server_template" : type.toLowerCase();
|
type === "ServerTemplate"
|
||||||
|
? "server_template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "sync"
|
||||||
|
: type.toLowerCase();
|
||||||
const resource = useRead(`Get${type}`, {
|
const resource = useRead(`Get${type}`, {
|
||||||
[key]: id,
|
[key]: id,
|
||||||
} as any).data;
|
} as any).data;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { RepoComponents } from "./repo";
|
|||||||
import { ServerComponents } from "./server";
|
import { ServerComponents } from "./server";
|
||||||
import { ProcedureComponents } from "./procedure/index";
|
import { ProcedureComponents } from "./procedure/index";
|
||||||
import { ServerTemplateComponents } from "./server-template";
|
import { ServerTemplateComponents } from "./server-template";
|
||||||
import { ResourceSyncComponents } from "./sync";
|
import { ResourceSyncComponents } from "./resource-sync";
|
||||||
|
|
||||||
export const ResourceComponents: {
|
export const ResourceComponents: {
|
||||||
[key in UsableResource]: RequiredResourceComponents;
|
[key in UsableResource]: RequiredResourceComponents;
|
||||||
|
|||||||
57
frontend/src/components/resources/resource-sync/actions.tsx
Normal file
57
frontend/src/components/resources/resource-sync/actions.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { ConfirmButton } from "@components/util";
|
||||||
|
import { useExecute, useInvalidate, useRead, useWrite } from "@lib/hooks";
|
||||||
|
import { sync_no_changes } from "@lib/utils";
|
||||||
|
import { Loader2, RefreshCcw, SquarePlay } from "lucide-react";
|
||||||
|
|
||||||
|
export const RefreshSync = ({ id }: { id: string }) => {
|
||||||
|
const inv = useInvalidate();
|
||||||
|
const { mutate, isPending } = useWrite("RefreshResourceSyncPending", {
|
||||||
|
onSuccess: () => inv(["GetResourceSync", { sync: id }]),
|
||||||
|
});
|
||||||
|
const pending = isPending;
|
||||||
|
return (
|
||||||
|
<ConfirmButton
|
||||||
|
title="Refresh"
|
||||||
|
icon={
|
||||||
|
pending ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<RefreshCcw className="w-4 h-4" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={() => mutate({ sync: id })}
|
||||||
|
disabled={pending}
|
||||||
|
loading={pending}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ExecuteSync = ({ id }: { id: string }) => {
|
||||||
|
const { mutate, isPending } = useExecute("RunSync");
|
||||||
|
const syncing = useRead(
|
||||||
|
"GetResourceSyncActionState",
|
||||||
|
{ sync: id },
|
||||||
|
{ refetchInterval: 5000 }
|
||||||
|
).data?.syncing;
|
||||||
|
const sync = useRead("GetResourceSync", { sync: id }).data;
|
||||||
|
|
||||||
|
if (!sync || sync_no_changes(sync)) return null;
|
||||||
|
|
||||||
|
const pending = isPending || syncing;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmButton
|
||||||
|
title="Execute Sync"
|
||||||
|
icon={
|
||||||
|
pending ? (
|
||||||
|
<Loader2 className="w-4 h-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<SquarePlay className="w-4 h-4" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={() => mutate({ sync: id })}
|
||||||
|
disabled={pending}
|
||||||
|
loading={pending}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import { Types } from "@monitor/client";
|
|||||||
import { ResourceSyncConfig } from "./config";
|
import { ResourceSyncConfig } from "./config";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs";
|
||||||
|
import { ExecuteSync, RefreshSync } from "./actions";
|
||||||
|
|
||||||
const useResourceSync = (id?: string) =>
|
const useResourceSync = (id?: string) =>
|
||||||
useRead("ListResourceSyncs", {}).data?.find((d) => d.id === id);
|
useRead("ListResourceSyncs", {}).data?.find((d) => d.id === id);
|
||||||
@@ -44,12 +45,12 @@ export const ResourceSyncComponents: RequiredResourceComponents = {
|
|||||||
Dashboard: () => {
|
Dashboard: () => {
|
||||||
const syncs_count = useRead("ListResourceSyncs", {}).data?.length;
|
const syncs_count = useRead("ListResourceSyncs", {}).data?.length;
|
||||||
return (
|
return (
|
||||||
<Link to="/syncs/" className="w-full">
|
<Link to="/resource-syncs/" className="w-full">
|
||||||
<Card className="hover:bg-accent/50 transition-colors cursor-pointer">
|
<Card className="hover:bg-accent/50 transition-colors cursor-pointer">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div>
|
<div>
|
||||||
<CardTitle>Syncs</CardTitle>
|
<CardTitle>Resource Syncs</CardTitle>
|
||||||
<CardDescription>{syncs_count} Total</CardDescription>
|
<CardDescription>{syncs_count} Total</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<FolderSync className="w-4 h-4" />
|
<FolderSync className="w-4 h-4" />
|
||||||
@@ -60,7 +61,7 @@ export const ResourceSyncComponents: RequiredResourceComponents = {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
New: () => <NewResource type="ResourceSync" />,
|
New: () => <NewResource type="ResourceSync" readable_type="Resource Sync" />,
|
||||||
|
|
||||||
Table: ({ resources }) => (
|
Table: ({ resources }) => (
|
||||||
<ResourceSyncTable syncs={resources as Types.ResourceSyncListItem[]} />
|
<ResourceSyncTable syncs={resources as Types.ResourceSyncListItem[]} />
|
||||||
@@ -73,7 +74,7 @@ export const ResourceSyncComponents: RequiredResourceComponents = {
|
|||||||
|
|
||||||
Info: {},
|
Info: {},
|
||||||
|
|
||||||
Actions: {},
|
Actions: { RefreshSync, ExecuteSync },
|
||||||
|
|
||||||
Page: {},
|
Page: {},
|
||||||
|
|
||||||
@@ -52,7 +52,12 @@ export const Sidebar = () => {
|
|||||||
|
|
||||||
{RESOURCE_TARGETS.map((type) => {
|
{RESOURCE_TARGETS.map((type) => {
|
||||||
const RTIcon = ResourceComponents[type].Icon;
|
const RTIcon = ResourceComponents[type].Icon;
|
||||||
const name = type === "ServerTemplate" ? "Template" : type;
|
const name =
|
||||||
|
type === "ServerTemplate"
|
||||||
|
? "Template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "Sync"
|
||||||
|
: type;
|
||||||
return (
|
return (
|
||||||
<SidebarLink
|
<SidebarLink
|
||||||
key={type}
|
key={type}
|
||||||
|
|||||||
@@ -125,7 +125,11 @@ const PrimaryDropdown = () => {
|
|||||||
const [icon, title] = Components
|
const [icon, title] = Components
|
||||||
? [
|
? [
|
||||||
<Components.Icon />,
|
<Components.Icon />,
|
||||||
(type === "ServerTemplate" ? "Template" : type) + "s",
|
(type === "ServerTemplate"
|
||||||
|
? "Template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "Sync"
|
||||||
|
: type) + "s",
|
||||||
]
|
]
|
||||||
: location.pathname === "/"
|
: location.pathname === "/"
|
||||||
? [<Home className="w-4 h-4" />, "Home"]
|
? [<Home className="w-4 h-4" />, "Home"]
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ export const useResourceParamType = () => {
|
|||||||
const type = useParams().type;
|
const type = useParams().type;
|
||||||
if (!type) return undefined;
|
if (!type) return undefined;
|
||||||
if (type === "server-templates") return "ServerTemplate";
|
if (type === "server-templates") return "ServerTemplate";
|
||||||
|
if (type === "resource-syncs") return "ResourceSync";
|
||||||
return (type[0].toUpperCase() + type.slice(1, -1)) as UsableResource;
|
return (type[0].toUpperCase() + type.slice(1, -1)) as UsableResource;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,15 @@ const on_message = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (update.target.type === "ResourceSync") {
|
||||||
|
invalidate(
|
||||||
|
["ListResourceSyncs"],
|
||||||
|
["GetResourceSync"],
|
||||||
|
["GetResourceSyncActionState"],
|
||||||
|
["GetResourceSyncsSummary"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
update.target.type === "System" &&
|
update.target.type === "System" &&
|
||||||
update.operation.includes("Variable")
|
update.operation.includes("Variable")
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const RESOURCE_TARGETS: UsableResource[] = [
|
|||||||
"Builder",
|
"Builder",
|
||||||
"Alerter",
|
"Alerter",
|
||||||
"ServerTemplate",
|
"ServerTemplate",
|
||||||
|
"ResourceSync",
|
||||||
];
|
];
|
||||||
|
|
||||||
export function env_to_text(envVars: Types.EnvironmentVar[] | undefined) {
|
export function env_to_text(envVars: Types.EnvironmentVar[] | undefined) {
|
||||||
@@ -97,6 +98,7 @@ export const convertTsMsToLocalUnixTsInSecs = (ts: number) =>
|
|||||||
|
|
||||||
export const usableResourcePath = (resource: UsableResource) => {
|
export const usableResourcePath = (resource: UsableResource) => {
|
||||||
if (resource === "ServerTemplate") return "server-templates";
|
if (resource === "ServerTemplate") return "server-templates";
|
||||||
|
if (resource === "ResourceSync") return "resource-syncs";
|
||||||
return `${resource.toLowerCase()}s`;
|
return `${resource.toLowerCase()}s`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -173,3 +175,21 @@ export const filterBySplit = <T>(
|
|||||||
: items) ?? []
|
: items) ?? []
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const sync_no_changes = (sync: Types.ResourceSync) => {
|
||||||
|
const pending = sync.info?.pending;
|
||||||
|
if (!pending) return false;
|
||||||
|
return (
|
||||||
|
!pending.server_updates?.length &&
|
||||||
|
!pending.deployment_updates?.length &&
|
||||||
|
!pending.build_updates?.length &&
|
||||||
|
!pending.repo_updates?.length &&
|
||||||
|
!pending.procedure_updates?.length &&
|
||||||
|
!pending.alerter_updates?.length &&
|
||||||
|
!pending.builder_updates?.length &&
|
||||||
|
!pending.server_template_updates?.length &&
|
||||||
|
!pending.resource_sync_updates?.length &&
|
||||||
|
!pending.variable_updates?.length &&
|
||||||
|
!pending.user_group_updates?.length
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -14,7 +14,12 @@ import { useState } from "react";
|
|||||||
|
|
||||||
export const Resources = () => {
|
export const Resources = () => {
|
||||||
const type = useResourceParamType()!;
|
const type = useResourceParamType()!;
|
||||||
const name = type === "ServerTemplate" ? "Server Template" : type;
|
const name =
|
||||||
|
type === "ServerTemplate"
|
||||||
|
? "Server Template"
|
||||||
|
: type === "ResourceSync"
|
||||||
|
? "Resource Sync"
|
||||||
|
: type;
|
||||||
useSetTitle(name + "s");
|
useSetTitle(name + "s");
|
||||||
const Components = ResourceComponents[type];
|
const Components = ResourceComponents[type];
|
||||||
const [search, set] = useState("");
|
const [search, set] = useState("");
|
||||||
|
|||||||
Reference in New Issue
Block a user