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 monitor_client::entities::{
|
||||
sync::ResourceSync, to_monitor_name, toml::ResourcesToml,
|
||||
@@ -32,6 +34,9 @@ pub async fn get_remote_resources(
|
||||
.transpose()?
|
||||
.cloned();
|
||||
|
||||
fs::create_dir_all(&config.sync_directory)
|
||||
.context("failed to create sync directory")?;
|
||||
|
||||
let mut logs =
|
||||
git::clone(clone_args, &config.sync_directory, github_token)
|
||||
.await
|
||||
|
||||
@@ -217,7 +217,7 @@ export const AccountSelector = ({
|
||||
>
|
||||
<SelectTrigger
|
||||
className="w-full lg:w-[200px] max-w-[50%]"
|
||||
disabled={disabled || !id}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectValue placeholder={placeholder} />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -49,7 +49,11 @@ export const ResourceDescription = ({
|
||||
const inv = useInvalidate();
|
||||
|
||||
const key =
|
||||
type === "ServerTemplate" ? "server_template" : type.toLowerCase();
|
||||
type === "ServerTemplate"
|
||||
? "server_template"
|
||||
: type === "ResourceSync"
|
||||
? "sync"
|
||||
: type.toLowerCase();
|
||||
|
||||
const resource = useRead(`Get${type}`, {
|
||||
[key]: id,
|
||||
@@ -244,10 +248,12 @@ export const CopyResource = ({
|
||||
|
||||
export const NewResource = ({
|
||||
type,
|
||||
readable_type,
|
||||
server_id,
|
||||
build_id,
|
||||
}: {
|
||||
type: UsableResource;
|
||||
readable_type?: string;
|
||||
server_id?: string;
|
||||
build_id?: string;
|
||||
}) => {
|
||||
@@ -255,7 +261,11 @@ export const NewResource = ({
|
||||
const { mutateAsync } = useWrite(`Create${type}`);
|
||||
const [name, setName] = useState("");
|
||||
const type_display =
|
||||
type === "ServerTemplate" ? "server-template" : type.toLowerCase();
|
||||
type === "ServerTemplate"
|
||||
? "server-template"
|
||||
: type === "ResourceSync"
|
||||
? "resource-sync"
|
||||
: type.toLowerCase();
|
||||
const config =
|
||||
type === "Deployment"
|
||||
? {
|
||||
@@ -267,7 +277,7 @@ export const NewResource = ({
|
||||
: {};
|
||||
return (
|
||||
<NewLayout
|
||||
entityType={type}
|
||||
entityType={readable_type ?? type}
|
||||
onSuccess={async () => {
|
||||
const id = (await mutateAsync({ name, config }))._id?.$oid!;
|
||||
nav(`/${usableResourcePath(type)}/${id}`);
|
||||
@@ -276,7 +286,7 @@ export const NewResource = ({
|
||||
onOpenChange={() => setName("")}
|
||||
>
|
||||
<div className="grid md:grid-cols-2 items-center">
|
||||
{type} Name
|
||||
{readable_type ?? type} Name
|
||||
<Input
|
||||
placeholder={`${type_display}-name`}
|
||||
value={name}
|
||||
@@ -296,7 +306,11 @@ export const DeleteResource = ({
|
||||
}) => {
|
||||
const nav = useNavigate();
|
||||
const key =
|
||||
type === "ServerTemplate" ? "server_template" : type.toLowerCase();
|
||||
type === "ServerTemplate"
|
||||
? "server_template"
|
||||
: type === "ResourceSync"
|
||||
? "sync"
|
||||
: type.toLowerCase();
|
||||
const resource = useRead(`Get${type}`, {
|
||||
[key]: id,
|
||||
} as any).data;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { RepoComponents } from "./repo";
|
||||
import { ServerComponents } from "./server";
|
||||
import { ProcedureComponents } from "./procedure/index";
|
||||
import { ServerTemplateComponents } from "./server-template";
|
||||
import { ResourceSyncComponents } from "./sync";
|
||||
import { ResourceSyncComponents } from "./resource-sync";
|
||||
|
||||
export const ResourceComponents: {
|
||||
[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 { useState } from "react";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@ui/tabs";
|
||||
import { ExecuteSync, RefreshSync } from "./actions";
|
||||
|
||||
const useResourceSync = (id?: string) =>
|
||||
useRead("ListResourceSyncs", {}).data?.find((d) => d.id === id);
|
||||
@@ -44,12 +45,12 @@ export const ResourceSyncComponents: RequiredResourceComponents = {
|
||||
Dashboard: () => {
|
||||
const syncs_count = useRead("ListResourceSyncs", {}).data?.length;
|
||||
return (
|
||||
<Link to="/syncs/" className="w-full">
|
||||
<Link to="/resource-syncs/" className="w-full">
|
||||
<Card className="hover:bg-accent/50 transition-colors cursor-pointer">
|
||||
<CardHeader>
|
||||
<div className="flex justify-between">
|
||||
<div>
|
||||
<CardTitle>Syncs</CardTitle>
|
||||
<CardTitle>Resource Syncs</CardTitle>
|
||||
<CardDescription>{syncs_count} Total</CardDescription>
|
||||
</div>
|
||||
<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 }) => (
|
||||
<ResourceSyncTable syncs={resources as Types.ResourceSyncListItem[]} />
|
||||
@@ -73,7 +74,7 @@ export const ResourceSyncComponents: RequiredResourceComponents = {
|
||||
|
||||
Info: {},
|
||||
|
||||
Actions: {},
|
||||
Actions: { RefreshSync, ExecuteSync },
|
||||
|
||||
Page: {},
|
||||
|
||||
@@ -52,7 +52,12 @@ export const Sidebar = () => {
|
||||
|
||||
{RESOURCE_TARGETS.map((type) => {
|
||||
const RTIcon = ResourceComponents[type].Icon;
|
||||
const name = type === "ServerTemplate" ? "Template" : type;
|
||||
const name =
|
||||
type === "ServerTemplate"
|
||||
? "Template"
|
||||
: type === "ResourceSync"
|
||||
? "Sync"
|
||||
: type;
|
||||
return (
|
||||
<SidebarLink
|
||||
key={type}
|
||||
|
||||
@@ -125,7 +125,11 @@ const PrimaryDropdown = () => {
|
||||
const [icon, title] = Components
|
||||
? [
|
||||
<Components.Icon />,
|
||||
(type === "ServerTemplate" ? "Template" : type) + "s",
|
||||
(type === "ServerTemplate"
|
||||
? "Template"
|
||||
: type === "ResourceSync"
|
||||
? "Sync"
|
||||
: type) + "s",
|
||||
]
|
||||
: location.pathname === "/"
|
||||
? [<Home className="w-4 h-4" />, "Home"]
|
||||
|
||||
@@ -192,6 +192,7 @@ export const useResourceParamType = () => {
|
||||
const type = useParams().type;
|
||||
if (!type) return undefined;
|
||||
if (type === "server-templates") return "ServerTemplate";
|
||||
if (type === "resource-syncs") return "ResourceSync";
|
||||
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 (
|
||||
update.target.type === "System" &&
|
||||
update.operation.includes("Variable")
|
||||
|
||||
@@ -22,6 +22,7 @@ export const RESOURCE_TARGETS: UsableResource[] = [
|
||||
"Builder",
|
||||
"Alerter",
|
||||
"ServerTemplate",
|
||||
"ResourceSync",
|
||||
];
|
||||
|
||||
export function env_to_text(envVars: Types.EnvironmentVar[] | undefined) {
|
||||
@@ -97,6 +98,7 @@ export const convertTsMsToLocalUnixTsInSecs = (ts: number) =>
|
||||
|
||||
export const usableResourcePath = (resource: UsableResource) => {
|
||||
if (resource === "ServerTemplate") return "server-templates";
|
||||
if (resource === "ResourceSync") return "resource-syncs";
|
||||
return `${resource.toLowerCase()}s`;
|
||||
};
|
||||
|
||||
@@ -173,3 +175,21 @@ export const filterBySplit = <T>(
|
||||
: 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 = () => {
|
||||
const type = useResourceParamType()!;
|
||||
const name = type === "ServerTemplate" ? "Server Template" : type;
|
||||
const name =
|
||||
type === "ServerTemplate"
|
||||
? "Server Template"
|
||||
: type === "ResourceSync"
|
||||
? "Resource Sync"
|
||||
: type;
|
||||
useSetTitle(name + "s");
|
||||
const Components = ResourceComponents[type];
|
||||
const [search, set] = useState("");
|
||||
|
||||
Reference in New Issue
Block a user