Skip to content

Commit

Permalink
refactor(web): use defaultvalues in react-hook-form
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephKav committed Apr 3, 2024
1 parent d388bfe commit e2802e7
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const BooleanWithDefault: FC<Props> = ({

return (
<Col
xs={12}
className="pt-1 pb-1"
style={{ display: "flex", alignItems: "center" }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,8 @@ const sendableTimeout = (
let timeout = differenceInMilliseconds(nextRunnable, now);
// if we're already after nextRunnable, just wait a second
if (now > nextRunnable) timeout = 1000;
const timer = setTimeout(function () {
setSendable(true);
}, timeout);
return () => {
clearTimeout(timer);
};
const timer = setTimeout(() => setSendable(true), timeout);
return () => clearTimeout(timer);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export const Loading: FC<Props> = ({ name }) => {
"Options:",
"Latest Version:",
"Deployed Version:",
"Commands:",
"WebHooks:",
"Command:",
"WebHook:",
"Notify:",
"Dashboard:",
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ const Notify: FC<Props> = ({
else if (itemType && (NotifyTypesConst as string[]).includes(itemName))
setValue(`${name}.type`, itemName);
// Trigger validation on name/type
setTimeout(() => {
const timeout = setTimeout(() => {
if (itemName !== "") trigger(`${name}.name`);
trigger(`${name}.type`);
}, 25);
return () => clearTimeout(timeout);
}, [itemName]);
const header = useMemo(
() => `${name.split(".").slice(-1)}: (${itemType}) ${itemName}`,
Expand Down
54 changes: 6 additions & 48 deletions web/ui/react-app/src/components/modals/service-edit/service.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { FC, useEffect, useMemo, useState } from "react";
import { FormGroup, Stack } from "react-bootstrap";
import {
ServiceEditAPIType,
ServiceEditOtherData,
ServiceEditType,
} from "types/service-edit";
import { ServiceEditOtherData, ServiceEditType } from "types/service-edit";

import EditServiceCommands from "components/modals/service-edit/commands";
import EditServiceDashboard from "components/modals/service-edit/dashboard";
Expand All @@ -13,17 +8,15 @@ import EditServiceLatestVersion from "components/modals/service-edit/latest-vers
import EditServiceNotifys from "components/modals/service-edit/notifys";
import EditServiceOptions from "components/modals/service-edit/options";
import EditServiceWebHooks from "components/modals/service-edit/webhooks";
import { FC } from "react";
import { FormItem } from "components/generic/form";
import { Loading } from "./loading";
import { WebHookType } from "types/config";
import { convertAPIServiceDataEditToUI } from "components/modals/service-edit/util";
import { fetchJSON } from "utils";
import { useFormContext } from "react-hook-form";
import { useQuery } from "@tanstack/react-query";
import { useWebSocket } from "contexts/websocket";

interface Props {
name: string;
defaultData: ServiceEditType;
otherOptionsData: ServiceEditOtherData;
}

/**
Expand All @@ -32,45 +25,10 @@ interface Props {
* @param name - The name of the service
* @returns The form fields for creating/editing a service
*/
const EditService: FC<Props> = ({ name }) => {
const { reset } = useFormContext();
const [loading, setLoading] = useState(true);

const { data: otherOptionsData, isFetched: isFetchedOtherOptionsData } =
useQuery({
queryKey: ["service/edit", "detail"],
queryFn: () =>
fetchJSON<ServiceEditOtherData>({ url: "api/v1/service/edit" }),
});
const { data: serviceData, isSuccess: isSuccessServiceData } = useQuery({
queryKey: ["service/edit", { id: name }],
queryFn: () =>
fetchJSON<ServiceEditAPIType>({ url: `api/v1/service/edit/${name}` }),
enabled: !!name,
refetchOnMount: "always",
});

const defaultData: ServiceEditType = useMemo(
() => convertAPIServiceDataEditToUI(name, serviceData, otherOptionsData),
[serviceData, otherOptionsData]
);
const EditService: FC<Props> = ({ name, defaultData, otherOptionsData }) => {
const { monitorData } = useWebSocket();

useEffect(() => {
// If we're loading and have finished fetching the service data
// (or don't have name = resetting for close)
if (
(loading && isSuccessServiceData && isFetchedOtherOptionsData) ||
!name
) {
reset(defaultData);
setTimeout(() => setLoading(false), 100);
}
}, [defaultData]);

return loading ? (
<Loading name={name} />
) : (
return (
<Stack gap={3}>
<FormGroup className="mb-2">
<FormItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ import {
WebHookType,
} from "types/config";
import {
NotifyEditType,
ServiceEditAPIType,
ServiceEditOtherData,
ServiceEditType,
WebHookEditType,
} from "types/service-edit";
import { firstNonDefault, firstNonEmpty, isEmptyOrNull } from "utils";
import {
firstNonDefault,
firstNonEmpty,
isEmptyArray,
isEmptyOrNull,
} from "utils";

import { urlCommandsTrimArray } from "./url-command-trim";

Expand Down Expand Up @@ -73,61 +80,76 @@ export const convertAPIServiceDataEditToUI = (
command: serviceData?.command?.map((args) => ({
args: args.map((arg) => ({ arg })),
})),
webhook: serviceData?.webhook?.map((item) => {
// Determine webhook name and type
const whName = item.name ?? "";
const whType = item.type ?? "";

// Construct custom headers
const customHeaders = item.custom_headers
? item.custom_headers.map((header, index) => ({
...header,
oldIndex: index,
}))
: firstNonEmpty(
otherOptionsData?.webhook?.[whName]?.custom_headers,
(
otherOptionsData?.defaults?.webhook?.[whType] as
| WebHookType
| undefined
)?.custom_headers,
(
otherOptionsData?.hard_defaults?.webhook?.[whType] as
| WebHookType
| undefined
)?.custom_headers
).map(() => ({ key: "", value: "" }));

// Return modified item
return {
...item,
custom_headers: customHeaders,
oldIndex: item.name,
};
}),
notify: serviceData?.notify?.map((item) => ({
...item,
oldIndex: item.name,
url_fields: {
...convertNotifyURLFields(
item.name ?? "",
item.type,
item.url_fields,
otherOptionsData
),
},
params: {
avatar: "", // controlled param
color: "", // ^
icon: "", // ^
...convertNotifyParams(
item.name ?? "",
item.type,
item.params,
otherOptionsData
),
},
})),
webhook: serviceData.webhook
? Object.entries(serviceData.webhook).reduce(
(acc: WebHookEditType[], [_key, value]) => {
// Determine webhook name and type
const whName = value.name ?? "";
const whType = value.type ?? "";

// Construct custom headers
const customHeaders = !isEmptyArray(value.custom_headers)
? value.custom_headers?.map((header, index) => ({
...header,
oldIndex: index,
}))
: firstNonEmpty(
otherOptionsData?.webhook?.[whName]?.custom_headers,
(
otherOptionsData?.defaults?.webhook?.[whType] as
| WebHookType
| undefined
)?.custom_headers,
(
otherOptionsData?.hard_defaults?.webhook?.[whType] as
| WebHookType
| undefined
)?.custom_headers
).map(() => ({ key: "", value: "" }));

const transformedWebhook = {
...value,
custom_headers: customHeaders,
oldIndex: whName,
};
return [...acc, transformedWebhook];
},
[]
)
: [],
notify: serviceData.notify
? Object.entries(serviceData.notify).reduce(
(acc: NotifyEditType[], [_key, value]) => {
// Determine notify name and type
const notifyName = value.name ?? "";
const notifyType = value.type ?? "";

const transformedNotify = {
...value,
id: notifyName,
url_fields: convertNotifyURLFields(
notifyName,
notifyType,
value.url_fields,
otherOptionsData
),
params: {
avatar: "", // controlled param
color: "", // ^
icon: "", // ^
...convertNotifyParams(
notifyName,
notifyType,
value.params,
otherOptionsData
),
},
};
return [...acc, transformedNotify];
},
[]
)
: [],
dashboard: {
auto_approve: undefined,
icon: "",
Expand Down Expand Up @@ -213,11 +235,14 @@ export const convertHeadersFromString = (

// convert from a JSON string
try {
return Object.entries(JSON.parse(s)).map(([key, value], i) => ({
id: usingStr ? i : undefined,
key: usingStr ? key : "",
value: usingStr ? value : "",
})) as HeaderType[];
return Object.entries(JSON.parse(s)).map(([key, value], i) => {
const id = usingStr ? { id: i } : {};
return {
...id,
key: usingStr ? key : "",
value: usingStr ? value : "",
};
}) as HeaderType[];
} catch (error) {
return [];
}
Expand Down Expand Up @@ -253,19 +278,19 @@ export const convertOpsGenieTargetFromString = (
obj: { id: string; type: string; name: string; username: string },
i: number
) => {
const id = usingStr ? i : undefined;
const id = usingStr ? { id: i } : {};
// team/user - id
if (obj.id) {
return {
id: id,
...id,
type: obj.type,
sub_type: "id",
value: usingStr ? obj.id : "",
};
} else {
// team/user - username/name
return {
id: id,
...id,
type: obj.type,
sub_type: obj.type === "user" ? "username" : "name",
value: usingStr ? obj.name || obj.username : "",
Expand Down Expand Up @@ -304,12 +329,12 @@ export const convertNtfyActionsFromString = (
// convert from a JSON string
try {
return JSON.parse(s).map((obj: NotifyNtfyAction, i: number) => {
const id = usingStr ? i : undefined;
const id = usingStr ? { id: i } : {};

// View
if (obj.action === "view")
return {
id: id,
...id,
action: obj.action,
label: usingStr ? obj.label : "",
url: usingStr ? obj.url : "",
Expand All @@ -318,7 +343,7 @@ export const convertNtfyActionsFromString = (
// HTTP
if (obj.action === "http")
return {
id: id,
...id,
action: obj.action,
label: usingStr ? obj.label : "",
url: usingStr ? obj.url : "",
Expand All @@ -333,7 +358,7 @@ export const convertNtfyActionsFromString = (
// Broadcast
if (obj.action === "broadcast")
return {
id: id,
...id,
action: obj.action,
label: usingStr ? obj.label : "",
intent: usingStr ? obj.intent : "",
Expand All @@ -345,7 +370,7 @@ export const convertNtfyActionsFromString = (

// Unknown action
return {
id: id,
...id,
...obj,
};
}) as NotifyNtfyAction[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,9 @@ const VersionWithRefresh: FC<Props> = ({ vType, serviceName, original }) => {
refetchSemanticVersioning();
refetchData();
// setTimeout to allow time for refetches ^
setTimeout(() => {
refetchVersion();
});
const timeout = setTimeout(() => refetchVersion());
setLastFetched(currentTime);
return () => clearTimeout(timeout);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ const EditServiceWebHook: FC<Props> = ({
useEffect(() => {
if (mains?.[itemName]?.type !== undefined)
setValue(`${name}.type`, mains[itemName].type);
setTimeout(() => {
const timeout = setTimeout(() => {
if (itemName !== "") trigger(`${name}.name`);
trigger(`${name}.type`);
}, 25);
return () => clearTimeout(timeout);
}, [itemName]);

const header = useMemo(
Expand Down
Loading

0 comments on commit e2802e7

Please sign in to comment.