Skip to content

Commit

Permalink
feat(sdl): persist sdl builder form to localstorage
Browse files Browse the repository at this point in the history
refs #88
  • Loading branch information
ygrishajev committed May 22, 2024
1 parent bf7445f commit 3aa89d1
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 7 deletions.
17 changes: 12 additions & 5 deletions deploy-web/src/components/sdl/SimpleSdlBuilderForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ import { PreviewSdl } from "./PreviewSdl";
import { SaveTemplateModal } from "./SaveTemplateModal";
import { useSnackbar } from "notistack";
import { Snackbar } from "../shared/Snackbar";
import useFormPersist from "@src/hooks/useFormPersist";

type Props = {};

const DEFAULT_SERVICES = {
services: [{ ...defaultService }]
};

export const SimpleSDLBuilderForm: React.FunctionComponent<Props> = ({}) => {
const [error, setError] = useState(null);
const [templateMetadata, setTemplateMetadata] = useState<ITemplate | null>(null);
Expand All @@ -44,10 +49,12 @@ export const SimpleSDLBuilderForm: React.FunctionComponent<Props> = ({}) => {
const [sdlBuilderSdl, setSdlBuilderSdl] = useAtom(sdlStore.sdlBuilderSdl);
const { data: gpuModels } = useGpuModels();
const { enqueueSnackbar } = useSnackbar();
const { handleSubmit, reset, control, trigger, watch, setValue } = useForm<SdlBuilderFormValues>({
defaultValues: {
services: [{ ...defaultService }]
}
const { handleSubmit, reset, control, trigger, watch, setValue } = useForm<SdlBuilderFormValues>();
useFormPersist("sdl-builder-form", {
watch,
setValue,
defaultValues: DEFAULT_SERVICES,
storage: typeof window === "undefined" ? undefined : window.localStorage
});
const {
fields: services,
Expand Down Expand Up @@ -288,7 +295,7 @@ export const SimpleSDLBuilderForm: React.FunctionComponent<Props> = ({}) => {
</div>
</div>

{services.map((service, serviceIndex) => (
{_services?.map((service, serviceIndex) => (
<SimpleServiceFormControl
key={service.id}
serviceIndex={serviceIndex}
Expand Down
93 changes: 93 additions & 0 deletions deploy-web/src/hooks/useFormPersist.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { useEffect } from "react";
import { SetFieldValue } from "react-hook-form";

export interface FormPersistConfig {
storage?: Storage;
watch: (names?: string | string[]) => any;
setValue: SetFieldValue<any>;
exclude?: string[];
onDataRestored?: (data: any) => void;
validate?: boolean;
dirty?: boolean;
touch?: boolean;
onTimeout?: () => void;
timeout?: number;
defaultValues?: any;
}

const useFormPersist = (
name: string,
{
storage,
watch,
setValue,
exclude = [],
onDataRestored,
validate = false,
dirty = false,
touch = false,
onTimeout,
timeout,
defaultValues
}: FormPersistConfig
) => {
const watchedValues = watch();

const getStorage = () => storage || window.sessionStorage;

const clearStorage = () => getStorage().removeItem(name);

useEffect(() => {
const str = getStorage().getItem(name);
const parsed = str ? JSON.parse(str) : defaultValues;

if (parsed) {
const { _timestamp = null, ...values } = parsed;
const dataRestored: { [key: string]: any } = {};
const currTimestamp = Date.now();

if (timeout && currTimestamp - _timestamp > timeout) {
onTimeout && onTimeout();
clearStorage();
return;
}

Object.keys(values).forEach(key => {
const shouldSet = !exclude.includes(key);
if (shouldSet) {
dataRestored[key] = values[key];
setValue(key, values[key], {
shouldValidate: validate,
shouldDirty: dirty,
shouldTouch: touch
});
}
});

if (onDataRestored) {
onDataRestored(dataRestored);
}
}
}, [storage, name, onDataRestored, setValue, defaultValues]);

useEffect(() => {
const values = exclude.length
? Object.entries(watchedValues)
.filter(([key]) => !exclude.includes(key))
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {})
: Object.assign({}, watchedValues);

if (Object.entries(values).length) {
if (timeout !== undefined) {
values._timestamp = Date.now();
}
getStorage().setItem(name, JSON.stringify(values));
}
}, [watchedValues, timeout]);

return {
clear: () => getStorage().removeItem(name)
};
};

export default useFormPersist;
4 changes: 2 additions & 2 deletions provider-proxy/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3aa89d1

Please sign in to comment.