new config system (#283)

This commit is contained in:
Mike Sawka
2024-08-27 18:49:49 -07:00
committed by GitHub
parent c9c555452a
commit 8630e23239
40 changed files with 1102 additions and 895 deletions
+8 -7
View File
@@ -5,7 +5,7 @@ import { appHandleKeyDown, appHandleKeyUp } from "@/app/appkey";
import { useWaveObjectValue } from "@/app/store/wos";
import { Workspace } from "@/app/workspace/workspace";
import { ContextMenuModel } from "@/store/contextmenu";
import { PLATFORM, WOS, atoms, getApi, globalStore } from "@/store/global";
import { PLATFORM, WOS, atoms, getApi, globalStore, useSettingsPrefixAtom } from "@/store/global";
import { getWebServerEndpoint } from "@/util/endpoints";
import * as keyutil from "@/util/keyutil";
import * as util from "@/util/util";
@@ -80,12 +80,13 @@ function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
}
function AppSettingsUpdater() {
const settings = jotai.useAtomValue(atoms.settingsConfigAtom);
const windowSettings = useSettingsPrefixAtom("window");
React.useEffect(() => {
const isTransparentOrBlur = (settings?.window?.transparent || settings?.window?.blur) ?? false;
const opacity = util.boundNumber(settings?.window?.opacity ?? 0.8, 0, 1);
let baseBgColor = settings?.window?.bgcolor;
console.log("window settings", settings.window);
const isTransparentOrBlur =
(windowSettings?.["window:transparent"] || windowSettings?.["window:blur"]) ?? false;
const opacity = util.boundNumber(windowSettings?.["window:opacity"] ?? 0.8, 0, 1);
let baseBgColor = windowSettings?.["window:bgcolor"];
console.log("window settings", windowSettings);
if (isTransparentOrBlur) {
document.body.classList.add("is-transparent");
const rootStyles = getComputedStyle(document.documentElement);
@@ -99,7 +100,7 @@ function AppSettingsUpdater() {
document.body.classList.remove("is-transparent");
document.body.style.opacity = null;
}
}, [settings?.window]);
}, [windowSettings]);
return null;
}
+4 -5
View File
@@ -12,7 +12,7 @@ import {
import { Button } from "@/app/element/button";
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
import { ContextMenuModel } from "@/app/store/contextmenu";
import { atoms, globalStore, useBlockAtom, WOS } from "@/app/store/global";
import { atoms, globalStore, useBlockAtom, useSettingsKeyAtom, WOS } from "@/app/store/global";
import * as services from "@/app/store/services";
import { WshServer } from "@/app/store/wshserver";
import { MagnifyIcon } from "@/element/magnify";
@@ -132,7 +132,8 @@ const BlockFrame_Header = ({
}: BlockFrameProps & { changeConnModalAtom: jotai.PrimitiveAtom<boolean> }) => {
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
const viewName = util.useAtomValueSafe(viewModel.viewName) ?? blockViewToName(blockData?.meta?.view);
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
const showBlockIds = jotai.useAtomValue(useSettingsKeyAtom("blockheader:showblockids"));
const settingsConfig = jotai.useAtomValue(atoms.settingsAtom);
const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
@@ -190,9 +191,7 @@ const BlockFrame_Header = ({
<div className="block-frame-default-header-iconview">
{viewIconElem}
<div className="block-frame-view-type">{viewName}</div>
{settingsConfig?.blockheader?.showblockids && (
<div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>
)}
{showBlockIds && <div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>}
</div>
<div className="block-frame-textelems-wrapper">{headerTextElems}</div>
-25
View File
@@ -135,31 +135,6 @@ export function getBlockHeaderIcon(blockIcon: string, blockData: Block): React.R
return blockIconElem;
}
export function getBlockHeaderText(blockIcon: string, blockData: Block, settings: SettingsConfigType): React.ReactNode {
if (!blockData) {
return "no block data";
}
let blockIdStr = "";
if (settings?.blockheader?.showblockids) {
blockIdStr = ` [${blockData.oid.substring(0, 8)}]`;
}
let blockIconElem = getBlockHeaderIcon(blockIcon, blockData);
if (!util.isBlank(blockData?.meta?.title)) {
try {
const rtn = processTitleString(blockData.meta.title) ?? [];
return [blockIconElem, ...rtn, blockIdStr == "" ? null : blockIdStr];
} catch (e) {
console.error("error processing title", blockData.meta.title, e);
return [blockIconElem, blockData.meta.title + blockIdStr];
}
}
let viewString = blockData?.meta?.view;
if (blockData?.meta?.controller == "cmd") {
viewString = "cmd";
}
return [blockIconElem, viewString + blockIdStr];
}
export const IconButton = React.memo(({ decl, className }: { decl: HeaderIconButton; className?: string }) => {
const buttonRef = React.useRef<HTMLDivElement>(null);
useLongClick(buttonRef, decl.click, decl.longClick);
+44 -13
View File
@@ -96,7 +96,10 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
}
return WOS.getObjectValue(WOS.makeORef("workspace", windowData.workspaceid), get);
});
const settingsConfigAtom = jotai.atom(null) as jotai.PrimitiveAtom<SettingsConfigType>;
const fullConfigAtom = jotai.atom(null) as jotai.PrimitiveAtom<FullConfigType>;
const settingsAtom = jotai.atom((get) => {
return get(fullConfigAtom)?.settings ?? {};
}) as jotai.Atom<SettingsType>;
const tabAtom: jotai.Atom<Tab> = jotai.atom((get) => {
const windowData = get(windowDataAtom);
if (windowData == null) {
@@ -121,7 +124,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
} catch (_) {
// do nothing
}
const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsConfigAtom).window.reducedmotion);
const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsAtom)?.["window:reducedmotion"]);
const typeAheadModalAtom = jotai.atom({});
atoms = {
// initialized in wave.ts (will not be null inside of application)
@@ -131,7 +134,8 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
client: clientAtom,
waveWindow: windowDataAtom,
workspace: workspaceAtom,
settingsConfigAtom,
fullConfigAtom,
settingsAtom,
tabAtom,
activeTabId: activeTabIdAtom,
isFullScreen: isFullScreenAtom,
@@ -271,19 +275,35 @@ function useBlockCache<T>(blockId: string, name: string, makeFn: () => T): T {
const settingsAtomCache = new Map<string, jotai.Atom<any>>();
function useSettingsAtom<T>(name: string, settingsFn: (settings: SettingsConfigType) => T): jotai.Atom<T> {
let atom = settingsAtomCache.get(name);
function useSettingsKeyAtom<T extends keyof SettingsType>(key: T): jotai.Atom<SettingsType[T]> {
let atom = settingsAtomCache.get(key) as jotai.Atom<SettingsType[T]>;
if (atom == null) {
atom = jotai.atom((get) => {
const settings = get(atoms.settingsConfigAtom);
const settings = get(atoms.settingsAtom);
if (settings == null) {
return null;
}
return settingsFn(settings);
}) as jotai.Atom<T>;
settingsAtomCache.set(name, atom);
return settings[key];
});
settingsAtomCache.set(key, atom);
}
return atom as jotai.Atom<T>;
return atom;
}
function useSettingsPrefixAtom(prefix: string): jotai.Atom<SettingsType> {
// TODO: use a shallow equal here to make this more efficient
let atom = settingsAtomCache.get(prefix + ":");
if (atom == null) {
atom = jotai.atom((get) => {
const settings = get(atoms.settingsAtom);
if (settings == null) {
return {};
}
return util.getPrefixedSettings(settings, prefix);
});
settingsAtomCache.set(prefix + ":", atom);
}
return atom;
}
const blockAtomCache = new Map<string, Map<string, jotai.Atom<any>>>();
@@ -337,7 +357,7 @@ function handleWSEventMessage(msg: WSEventType) {
return;
}
if (msg.eventtype == "config") {
globalStore.set(atoms.settingsConfigAtom, msg.data.settings);
globalStore.set(atoms.fullConfigAtom, (msg.data as WatcherUpdate).fullconfig);
return;
}
if (msg.eventtype == "userinput") {
@@ -474,8 +494,17 @@ function isDev() {
return cachedIsDev;
}
let cachedUserName: string = null;
function getUserName(): string {
if (cachedUserName == null) {
cachedUserName = getApi().getUserName();
}
return cachedUserName;
}
async function openLink(uri: string) {
if (globalStore.get(atoms.settingsConfigAtom)?.web?.openlinksinternally) {
if (globalStore.get(atoms.settingsAtom)?.["web:openlinksinternally"]) {
const blockDef: BlockDef = {
meta: {
view: "web",
@@ -563,6 +592,7 @@ export {
getEventSubject,
getFileSubject,
getObjectId,
getUserName,
getViewModel,
globalStore,
globalWS,
@@ -581,7 +611,8 @@ export {
useBlockAtom,
useBlockCache,
useBlockDataLoaded,
useSettingsAtom,
useSettingsKeyAtom,
useSettingsPrefixAtom,
waveEventSubscribe,
waveEventUnsubscribe,
WOS,
+2 -9
View File
@@ -53,16 +53,12 @@ export const ClientService = new ClientServiceType();
// fileservice.FileService (file)
class FileServiceType {
AddWidget(arg1: WidgetsConfigType): Promise<void> {
return WOS.callBackendService("file", "AddWidget", Array.from(arguments))
}
// delete file
DeleteFile(connection: string, path: string): Promise<void> {
return WOS.callBackendService("file", "DeleteFile", Array.from(arguments))
}
GetSettingsConfig(): Promise<SettingsConfigType> {
return WOS.callBackendService("file", "GetSettingsConfig", Array.from(arguments))
GetFullConfig(): Promise<FullConfigType> {
return WOS.callBackendService("file", "GetFullConfig", Array.from(arguments))
}
GetWaveFile(arg1: string, arg2: string): Promise<any> {
return WOS.callBackendService("file", "GetWaveFile", Array.from(arguments))
@@ -72,9 +68,6 @@ class FileServiceType {
ReadFile(connection: string, path: string): Promise<FullFile> {
return WOS.callBackendService("file", "ReadFile", Array.from(arguments))
}
RemoveWidget(arg1: number): Promise<void> {
return WOS.callBackendService("file", "RemoveWidget", Array.from(arguments))
}
// save file
SaveFile(connection: string, path: string, data64: string): Promise<void> {
+8 -8
View File
@@ -139,33 +139,33 @@ const Tab = React.memo(
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
e.preventDefault();
let menu: ContextMenuItem[] = [];
const settings = globalStore.get(atoms.settingsConfigAtom);
console.log("settings", settings);
const fullConfig = globalStore.get(atoms.fullConfigAtom);
const bgPresets: string[] = [];
for (const key in settings?.presets ?? {}) {
for (const key in fullConfig?.presets ?? {}) {
if (key.startsWith("bg@")) {
bgPresets.push(key);
}
}
bgPresets.sort((a, b) => {
const aOrder = settings.presets[a]["display:order"] ?? 0;
const bOrder = settings.presets[b]["display:order"] ?? 0;
const aOrder = fullConfig.presets[a]["display:order"] ?? 0;
const bOrder = fullConfig.presets[b]["display:order"] ?? 0;
return aOrder - bOrder;
});
console.log("bgPresets", bgPresets);
menu.push({ label: "Copy TabId", click: () => navigator.clipboard.writeText(id) });
menu.push({ type: "separator" });
if (bgPresets.length > 0) {
const submenu: ContextMenuItem[] = [];
const oref = WOS.makeORef("tab", id);
for (const presetName of bgPresets) {
const preset = settings.presets[presetName];
const preset = fullConfig.presets[presetName];
if (preset == null) {
continue;
}
submenu.push({
label: preset["display:name"] ?? presetName,
click: () => services.ObjectService.UpdateObjectMeta(oref, preset),
click: () => {
services.ObjectService.UpdateObjectMeta(oref, preset);
},
});
}
menu.push({ label: "Backgrounds", type: "submenu", submenu });
@@ -134,11 +134,11 @@ function DirectoryTable({
setSelectedPath,
setRefreshVersion,
}: DirectoryTableProps) {
const settings = jotai.useAtomValue(atoms.settingsConfigAtom);
const fullConfig = jotai.useAtomValue(atoms.fullConfigAtom);
const getIconFromMimeType = useCallback(
(mimeType: string): string => {
while (mimeType.length > 0) {
let icon = settings.mimetypes?.[mimeType]?.icon ?? null;
let icon = fullConfig.mimetypes?.[mimeType]?.icon ?? null;
if (isIconValid(icon)) {
return `fa fa-solid fa-${icon} fa-fw`;
}
@@ -146,14 +146,14 @@ function DirectoryTable({
}
return "fa fa-solid fa-file fa-fw";
},
[settings.mimetypes]
[fullConfig.mimetypes]
);
const getIconColor = useCallback(
(mimeType: string): string => {
let iconColor = settings.mimetypes?.[mimeType]?.color ?? "inherit";
let iconColor = fullConfig.mimetypes?.[mimeType]?.color ?? "inherit";
return iconColor;
},
[settings.mimetypes]
[fullConfig.mimetypes]
);
const columns = useMemo(
() => [
@@ -208,7 +208,7 @@ function DirectoryTable({
}),
columnHelper.accessor("path", {}),
],
[settings]
[fullConfig]
);
const table = useReactTable({
+9 -11
View File
@@ -3,7 +3,7 @@
import { WshServer } from "@/app/store/wshserver";
import { VDomView } from "@/app/view/term/vdom";
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsAtom } from "@/store/global";
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsPrefixAtom } from "@/store/global";
import * as services from "@/store/services";
import * as keyutil from "@/util/keyutil";
import * as util from "@/util/util";
@@ -135,8 +135,8 @@ class TermViewModel {
});
this.blockBg = jotai.atom((get) => {
const blockData = get(this.blockAtom);
const settings = globalStore.get(atoms.settingsConfigAtom);
const theme = computeTheme(settings, blockData?.meta?.["term:theme"]);
const fullConfig = get(atoms.fullConfigAtom);
const theme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]);
if (theme != null && theme.background != null) {
return { bg: theme.background };
}
@@ -203,9 +203,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
const htmlElemFocusRef = React.useRef<HTMLInputElement>(null);
model.htmlElemFocusRef = htmlElemFocusRef;
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
const termSettingsAtom = useSettingsAtom<TerminalConfigType>("term", (settings: SettingsConfigType) => {
return settings?.term;
});
const termSettingsAtom = useSettingsPrefixAtom("term");
const termSettings = jotai.useAtomValue(termSettingsAtom);
React.useEffect(() => {
@@ -240,8 +238,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
}
return true;
}
const settings = globalStore.get(atoms.settingsConfigAtom);
const termTheme = computeTheme(settings, blockData?.meta?.["term:theme"]);
const fullConfig = globalStore.get(atoms.fullConfigAtom);
const termTheme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]);
const themeCopy = { ...termTheme };
themeCopy.background = "#00000000";
const termWrap = new TermWrap(
@@ -249,8 +247,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
connectElemRef.current,
{
theme: themeCopy,
fontSize: termSettings?.fontsize ?? 12,
fontFamily: termSettings?.fontfamily ?? "Hack",
fontSize: termSettings?.["term:fontsize"] ?? 12,
fontFamily: termSettings?.["term:fontfamily"] ?? "Hack",
drawBoldTextInBrightColors: false,
fontWeight: "normal",
fontWeightBold: "bold",
@@ -258,7 +256,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
},
{
keydownHandler: handleTerminalKeydown,
useWebGl: !termSettings?.disablewebgl,
useWebGl: !termSettings?.["term:disablewebgl"],
}
);
(window as any).term = termWrap;
+2 -1
View File
@@ -13,7 +13,8 @@ interface TermThemeProps {
}
const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => {
const { termthemes } = useAtomValue(atoms.settingsConfigAtom);
const fullConfig = useAtomValue(atoms.fullConfigAtom);
const termthemes = fullConfig?.termthemes;
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
let defaultThemeName = "default-dark";
let themeName = blockData.meta?.["term:theme"] ?? "default-dark";
+3 -3
View File
@@ -3,11 +3,11 @@
import * as util from "@/util/util";
function computeTheme(settings: SettingsConfigType, themeName: string): TermThemeType {
function computeTheme(fullConfig: FullConfigType, themeName: string): TermThemeType {
let defaultThemeName = "default-dark";
themeName = themeName ?? "default-dark";
const defaultTheme: TermThemeType = settings?.termthemes?.[defaultThemeName] || ({} as any);
const theme: TermThemeType = settings?.termthemes?.[themeName] || ({} as any);
const defaultTheme: TermThemeType = fullConfig?.termthemes?.[defaultThemeName] || ({} as any);
const theme: TermThemeType = fullConfig?.termthemes?.[themeName] || ({} as any);
const combinedTheme = { ...defaultTheme };
for (const key in theme) {
if (!util.isBlank(theme[key])) {
+11 -8
View File
@@ -3,7 +3,7 @@
import { Markdown } from "@/app/element/markdown";
import { TypingIndicator } from "@/app/element/typingindicator";
import { WOS, atoms, fetchWaveFile, globalStore } from "@/store/global";
import { WOS, atoms, fetchWaveFile, getUserName, globalStore } from "@/store/global";
import * as services from "@/store/services";
import { WshServer } from "@/store/wshserver";
import * as jotai from "jotai";
@@ -107,7 +107,7 @@ export class WaveAiModel implements ViewModel {
const viewTextChildren: HeaderElem[] = [
{
elemtype: "text",
text: get(atoms.settingsConfigAtom).ai?.model ?? "gpt-3.5-turbo",
text: get(atoms.settingsAtom)["ai:model"] ?? "gpt-3.5-turbo",
},
];
return viewTextChildren;
@@ -152,18 +152,21 @@ export class WaveAiModel implements ViewModel {
};
addMessage(newMessage);
// send message to backend and get response
const settings = globalStore.get(atoms.settingsConfigAtom);
const settings = globalStore.get(atoms.settingsAtom);
const opts: OpenAIOptsType = {
model: settings.ai.model,
apitoken: settings.ai.apitoken,
maxtokens: settings.ai.maxtokens,
timeout: settings.ai.timeoutms / 1000,
baseurl: settings.ai.baseurl,
model: settings["ai:model"],
apitoken: settings["ai:apitoken"],
maxtokens: settings["ai:maxtokens"],
timeout: settings["ai:timeoutms"] / 1000,
baseurl: settings["ai:baseurl"],
};
const newPrompt: OpenAIPromptMessageType = {
role: "user",
content: text,
};
if (newPrompt.name == "*username") {
newPrompt.name = getUserName();
}
let temp = async () => {
const history = await this.fetchAiData();
const beMsg: OpenAiStreamRequest = {
+29 -7
View File
@@ -14,10 +14,28 @@ import "./workspace.less";
const iconRegex = /^[a-z0-9-]+$/;
function keyLen(obj: Object): number {
if (obj == null) {
return 0;
}
return Object.keys(obj).length;
}
function sortByDisplayOrder(wmap: { [key: string]: WidgetConfigType }): WidgetConfigType[] {
if (wmap == null) {
return [];
}
const wlist = Object.values(wmap);
wlist.sort((a, b) => {
return a["display:order"] - b["display:order"];
});
return wlist;
}
const Widgets = React.memo(() => {
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
const fullConfig = jotai.useAtomValue(atoms.fullConfigAtom);
const newWidgetModalVisible = React.useState(false);
const helpWidget: WidgetsConfigType = {
const helpWidget: WidgetConfigType = {
icon: "circle-question",
label: "help",
blockdef: {
@@ -26,13 +44,17 @@ const Widgets = React.memo(() => {
},
},
};
const showHelp = settingsConfig?.["widget:showhelp"] ?? true;
const showDivider = settingsConfig?.defaultwidgets?.length > 0 && settingsConfig?.widgets?.length > 0;
const showHelp = fullConfig?.settings?.["widget:showhelp"] ?? true;
const showDivider = keyLen(fullConfig?.defaultwidgets) > 0 && keyLen(fullConfig?.widgets) > 0;
const defaultWidgets = sortByDisplayOrder(fullConfig?.defaultwidgets);
const widgets = sortByDisplayOrder(fullConfig?.widgets);
return (
<div className="workspace-widgets">
{settingsConfig?.defaultwidgets?.map((data, idx) => <Widget key={`defwidget-${idx}`} widget={data} />)}
{defaultWidgets.map((data, idx) => (
<Widget key={`defwidget-${idx}`} widget={data} />
))}
{showDivider ? <div className="widget-divider" /> : null}
{settingsConfig?.widgets?.map((data, idx) => <Widget key={`widget-${idx}`} widget={data} />)}
{widgets?.map((data, idx) => <Widget key={`widget-${idx}`} widget={data} />)}
{showHelp ? (
<>
<div className="widget-spacer" />
@@ -61,7 +83,7 @@ function getIconClass(icon: string): string {
return `fa fa-solid fa-${icon} fa-fw`;
}
const Widget = React.memo(({ widget }: { widget: WidgetsConfigType }) => {
const Widget = React.memo(({ widget }: { widget: WidgetConfigType }) => {
return (
<div
className="widget"
+3 -3
View File
@@ -12,7 +12,8 @@ declare global {
uiContext: jotai.Atom<UIContext>; // driven from windowId, activetabid, etc.
waveWindow: jotai.Atom<WaveWindow>; // driven from WOS
workspace: jotai.Atom<Workspace>; // driven from WOS
settingsConfigAtom: jotai.PrimitiveAtom<SettingsConfigType>; // driven from WOS, settings -- updated via WebSocket
fullConfigAtom: jotai.PrimitiveAtom<FullConfigType>; // driven from WOS, settings -- updated via WebSocket
settingsAtom: jotai.Atom<SettingsType>; // derrived from fullConfig
tabAtom: jotai.Atom<Tab>; // driven from WOS
activeTabId: jotai.Atom<string>; // derrived from windowDataAtom
isFullScreen: jotai.PrimitiveAtom<boolean>;
@@ -49,10 +50,9 @@ declare global {
getAuthKey(): string;
getIsDev(): boolean;
getCursorPoint: () => Electron.Point;
getPlatform: () => NodeJS.Platform;
getEnv: (varName: string) => string;
getUserName: () => string;
showContextMenu: (menu?: ElectronContextMenuItem[]) => void;
onContextMenuClick: (callback: (id: string) => void) => void;
onNavigate: (callback: (url: string) => void) => void;
+55 -67
View File
@@ -5,22 +5,6 @@
declare global {
// wconfig.AiConfigType
type AiConfigType = {
baseurl: string;
apitoken: string;
model: string;
maxtokens: number;
timeoutms: number;
};
// wconfig.AutoUpdateOpts
type AutoUpdateOpts = {
enabled: boolean;
intervalms: number;
installonquit: boolean;
};
// waveobj.Block
type Block = WaveObj & {
blockdef: BlockDef;
@@ -41,11 +25,6 @@ declare global {
meta?: MetaType;
};
// wconfig.BlockHeaderOpts
type BlockHeaderOpts = {
showblockids: boolean;
};
// webcmd.BlockInputWSCommand
type BlockInputWSCommand = {
wscommand: "blockinput";
@@ -157,6 +136,12 @@ declare global {
meta: MetaType;
};
// wconfig.ConfigError
type ConfigError = {
file: string;
err: string;
};
// wshrpc.ConnStatus
type ConnStatus = {
status: string;
@@ -201,6 +186,17 @@ declare global {
ijsonbudget?: number;
};
// wconfig.FullConfigType
type FullConfigType = {
settings: SettingsType;
mimetypes: {[key: string]: MimeTypeConfigType};
defaultwidgets: {[key: string]: WidgetConfigType};
widgets: {[key: string]: WidgetConfigType};
presets: {[key: string]: MetaType};
termthemes: {[key: string]: TermThemeType};
configerrors: ConfigError[];
};
// fileservice.FullFile
type FullFile = {
info: FileInfo;
@@ -235,6 +231,8 @@ declare global {
connection?: string;
history?: string[];
"history:forward"?: string[];
"display:name"?: string;
"display:order"?: number;
icon?: string;
"icon:color"?: string;
frame?: boolean;
@@ -363,21 +361,37 @@ declare global {
termsize: TermSize;
};
// wconfig.SettingsConfigType
type SettingsConfigType = {
mimetypes: {[key: string]: MimeTypeConfigType};
term: TerminalConfigType;
ai: AiConfigType;
defaultwidgets: WidgetsConfigType[];
widgets: WidgetsConfigType[];
"widget:showhelp": boolean;
blockheader: BlockHeaderOpts;
autoupdate: AutoUpdateOpts;
termthemes: {[key: string]: TermThemeType};
window: WindowSettingsType;
web: WebConfigType;
telemetry: TelemetrySettingsType;
presets?: {[key: string]: MetaType};
// wconfig.SettingsType
type SettingsType = {
"ai:*"?: boolean;
"ai:baseurl"?: string;
"ai:apitoken"?: string;
"ai:name"?: string;
"ai:model"?: string;
"ai:maxtokens"?: number;
"ai:timeoutms"?: number;
"term:*"?: boolean;
"term:fontsize"?: number;
"term:fontfamily"?: string;
"term:disablewebgl"?: boolean;
"web:*"?: boolean;
"web:openlinksinternally"?: boolean;
"blockheader:*"?: boolean;
"blockheader:showblockids"?: boolean;
"autoupdate:*"?: boolean;
"autoupdate:enabled"?: boolean;
"autoupdate:intervalms"?: number;
"autoupdate:installonquit"?: boolean;
"widget:*"?: boolean;
"widget:showhelp"?: boolean;
"window:*"?: boolean;
"window:transparent"?: boolean;
"window:blur"?: boolean;
"window:opacity"?: number;
"window:bgcolor"?: string;
"window:reducedmotion"?: boolean;
"telemetry:*"?: boolean;
"telemetry:enabled"?: boolean;
};
// waveobj.StickerClickOptsType
@@ -415,11 +429,6 @@ declare global {
blockids: string[];
};
// wconfig.TelemetrySettingsType
type TelemetrySettingsType = {
enabled: boolean;
};
// waveobj.TermSize
type TermSize = {
rows: number;
@@ -452,13 +461,6 @@ declare global {
cursorAccent: string;
};
// wconfig.TerminalConfigType
type TerminalConfigType = {
fontsize?: number;
fontfamily?: string;
disablewebgl: boolean;
};
// wshrpc.TimeSeriesData
type TimeSeriesData = {
ts: number;
@@ -543,8 +545,7 @@ declare global {
// wconfig.WatcherUpdate
type WatcherUpdate = {
settings: SettingsConfigType;
error: string;
fullconfig: FullConfigType;
};
// wshrpc.WaveEvent
@@ -599,11 +600,6 @@ declare global {
args: any[];
};
// wconfig.WebConfigType
type WebConfigType = {
openlinksinternally: boolean;
};
// service.WebReturnType
type WebReturnType = {
success?: boolean;
@@ -612,9 +608,10 @@ declare global {
updates?: WaveObjUpdate[];
};
// wconfig.WidgetsConfigType
type WidgetsConfigType = {
icon: string;
// wconfig.WidgetConfigType
type WidgetConfigType = {
"display:order"?: number;
icon?: string;
color?: string;
label?: string;
description?: string;
@@ -627,15 +624,6 @@ declare global {
height: number;
};
// wconfig.WindowSettingsType
type WindowSettingsType = {
transparent: boolean;
blur: boolean;
opacity: number;
bgcolor: string;
reducedmotion: boolean;
};
// waveobj.Workspace
type Workspace = WaveObj & {
name: string;
+14
View File
@@ -242,6 +242,19 @@ function atomWithDebounce<T>(initialValue: T, delayMilliseconds = 500): AtomWith
};
}
function getPrefixedSettings(settings: SettingsType, prefix: string): SettingsType {
const rtn: SettingsType = {};
if (settings == null || isBlank(prefix)) {
return rtn;
}
for (const key in settings) {
if (key == prefix || key.startsWith(prefix + ":")) {
rtn[key] = settings[key];
}
}
return rtn;
}
export {
atomWithDebounce,
atomWithThrottle,
@@ -249,6 +262,7 @@ export {
base64ToString,
boundNumber,
fireAndForget,
getPrefixedSettings,
getPromiseState,
getPromiseValue,
isBlank,
+3 -3
View File
@@ -57,9 +57,9 @@ document.addEventListener("DOMContentLoaded", async () => {
initWS();
await loadConnStatus();
subscribeToConnEvents();
const settings = await services.FileService.GetSettingsConfig();
console.log("settings", settings);
globalStore.set(atoms.settingsConfigAtom, settings);
const fullConfig = await services.FileService.GetFullConfig();
console.log("fullconfig", fullConfig);
globalStore.set(atoms.fullConfigAtom, fullConfig);
services.ObjectService.SetActiveTab(waveWindow.activetabid); // no need to wait
const reactElem = React.createElement(App, null, null);
const elem = document.getElementById("main");