Config state temp2

This commit is contained in:
space-nuko
2023-05-28 16:48:33 -05:00
parent 8fc4b74aed
commit 4d8390115d
3 changed files with 146 additions and 88 deletions

View File

@@ -1,97 +1,10 @@
import { debounce } from '$lib/utils';
import { get, writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import { z, type ZodTypeAny } from "zod"
type ConfigDefType = "boolean" | "number" | "string" | "string[]";
// A simple parameter description interface
interface ConfigDef<IdType, TypeType extends ConfigDefType, ValueType> {
// The `IdType` is necessary to get a stricter type
// parameter instead of a generic `id: string;`. This will be needed
// later when we infer the type of the `config` object.
name: IdType;
type: TypeType,
description?: string,
defaultValue: ValueType,
}
type ConfigDefBoolean<IdType> = ConfigDef<IdType, "boolean", boolean>;
type ConfigDefNumber<IdType> = ConfigDef<IdType, "number", number>;
type ConfigDefString<IdType> = ConfigDef<IdType, "string", string>;
type ConfigDefStringArray<IdType> = ConfigDef<IdType, "string[]", string[]>;
// Configuration parameters ------------------------------------
const defComfyUIHostname: ConfigDefString<"comfyUIHostname"> = {
name: "comfyUIHostname",
type: "string",
defaultValue: "localhost",
description: "Backend domain for ComfyUI",
};
const defComfyUIPort: ConfigDefNumber<"comfyUIPort"> = {
name: "comfyUIPort",
type: "number",
defaultValue: 8188,
description: "Backend port for ComfyUI",
};
const defAlwaysStripUserState: ConfigDefBoolean<"alwaysStripUserState"> = {
name: "alwaysStripUserState",
type: "boolean",
defaultValue: false,
description: "Strip user state even if saving to local storage"
};
const defPromptForWorkflowName: ConfigDefBoolean<"promptForWorkflowName"> = {
name: "promptForWorkflowName",
type: "boolean",
defaultValue: false,
description: "When saving, always prompt for a name to save the workflow as",
};
const defConfirmWhenUnloadingUnsavedChanges: ConfigDefBoolean<"confirmWhenUnloadingUnsavedChanges"> = {
name: "confirmWhenUnloadingUnsavedChanges",
type: "boolean",
defaultValue: true,
description: "When closing the tab, open the confirmation window if there's unsaved changes"
};
const defBuiltInTemplates: ConfigDefStringArray<"builtInTemplates"> = {
name: "builtInTemplates",
type: "string[]",
defaultValue: [],
description: "Basenames of templates that can be loaded from public/templates. Saves LocalStorage space.",
};
const defCacheBuiltInResources: ConfigDefBoolean<"cacheBuiltInResources"> = {
name: "cacheBuiltInResources",
type: "boolean",
defaultValue: true,
description: "Cache loading of built-in resources to save network use"
};
export const CONFIG_DEFS = [
defComfyUIHostname,
defComfyUIPort,
defAlwaysStripUserState,
defPromptForWorkflowName,
defConfirmWhenUnloadingUnsavedChanges,
defBuiltInTemplates,
defCacheBuiltInResources,
] as const;
type Config<T extends ReadonlyArray<Readonly<ConfigDef<string, ConfigDefType, any>>>> = {
[K in T[number]["name"]]: Extract<T[number], { name: K }>["defaultValue"]
} extends infer O
? { [P in keyof O]: O[P] }
: never;
type ConfigState = Config<typeof CONFIG_DEFS>
type ConfigStateOps = {
getBackendURL: () => string,
save: () => void,
@@ -110,6 +23,90 @@ const store: Writable<ConfigState> = writable(
cacheBuiltInResources: true,
})
type Conf2 = {
name: string;
type: ZodTypeAny;
defaultValue: any;
description: string;
};
const def2ComfyUIHostname: Conf2 = {
name: 'backend.comfyUIHostname',
type: z.string(),
defaultValue: 'localhost',
description: 'Backend domain for ComfyUI',
};
const def2ComfyUIPort: Conf2 = {
name: 'backend.comfyUIPort',
type: z.number(),
defaultValue: 8188,
description: 'Backend port for ComfyUI',
};
const def2AlwaysStripUserState: Conf2 = {
name: 'behavior.alwaysStripUserState',
type: z.boolean(),
defaultValue: false,
description: 'Strip user state even if saving to local storage',
};
export const allconfs: ReadonlyArray<Conf2> = [
def2ComfyUIHostname,
def2ComfyUIPort,
def2AlwaysStripUserState,
] as const;
const confItems: any = {};
const confDefaults: any = {}
for (const item of allconfs) {
const trail = item.name.split('.');
let theI = confItems;
let theDef = confDefaults;
for (const category of trail.slice(0, -1)) {
theI[category] ||= { __category__: true };
theI = theI[category];
theDef[category] ||= {};
theDef = theDef[category];
}
const optionName = trail[trail.length - 1];
theI[optionName] = item;
theDef[optionName] = item.defaultValue;
}
function recurse(item: Record<string, any>, trail: string[] = []): ZodTypeAny {
let defaultValue = confDefaults
for (const name of trail) {
defaultValue = defaultValue[name];
}
for (const [key, value] of Object.entries(item)) {
if (value.__category__) {
delete value['__category__'];
item[key] = recurse(value, trail.concat(key));
} else {
const result = value.type.safeParse(value.defaultValue);
if (!result.success) {
throw new Error(
`Default value for config item ${value.name} did not pass type matcher: ${result.error}`
);
}
item[key] = value.type.catch(value.defaultValue);
}
}
return z.object(item).catch({ ...defaultValue });
}
export const Config2 = recurse(confItems);
export type ConfigStore = z.infer<typeof Config2>;
const stor: ConfigStore = {
backend: {},
a: "foo"
}
function getBackendURL(): string {
const state = get(store);
return `${window.location.protocol}//${state.comfyUIHostname}:${state.comfyUIPort}`

View File

@@ -0,0 +1,60 @@
import { get } from "svelte/store";
import configState, { Config2 } from "$lib/stores/configState"
import { expect } from 'vitest';
import UnitTest from "../UnitTest";
import { Watch } from "@litegraph-ts/nodes-basic";
export default class configStateTests extends UnitTest {
test__parse__parsesBasic() {
const testConf = {
backend: {
comfyUIHostname: 'test',
comfyUIPort: 8187,
},
behavior: {
alwaysStripUserState: false,
},
};
expect(Config2.safeParse(testConf).success).toEqual(true);
}
test__parse__parsesFallbacks() {
const testConf = {
backend: {},
behavior: {}
};
const result = Config2.safeParse(testConf)
console.warn(result)
expect(result.success).toEqual(true);
expect(result.data).toEqual({
backend: {
comfyUIHostname: "localhost",
comfyUIPort: 8188
},
behavior: {
alwaysStripUserState: false
}
});
}
test__parse__parsesFallbacks2() {
const testConf = "foo";
const result = Config2.safeParse(testConf)
console.warn(result)
expect(result.success).toEqual(true);
expect(result.data).toEqual({
backend: {
comfyUIHostname: "localhost",
comfyUIPort: 8188
},
behavior: {
alwaysStripUserState: false
}
});
}
}

View File

@@ -3,3 +3,4 @@ export { default as ComfyGraphTests } from "./ComfyGraphTests"
export { default as parseA1111Tests } from "./parseA1111Tests"
export { default as convertA1111ToStdPromptTests } from "./convertA1111ToStdPromptTests"
export { default as convertVanillaWorkflowTest } from "./convertVanillaWorkflowTests"
export { default as configStateTests } from "./stores/configStateTests"