diff --git a/docs/docs/releasenotes.mdx b/docs/docs/releasenotes.mdx index a805a03d6..41411bb3f 100644 --- a/docs/docs/releasenotes.mdx +++ b/docs/docs/releasenotes.mdx @@ -25,6 +25,7 @@ New minor release that introduces Wave's connected computing extensions. We've i - [bugfix] Presets directory was not loading correctly on Windows - [bugfix] Magnified blocks were not showing correct on startup - [bugfix] Window opacity and background color was not getting applied properly in all cases +- [bugfix] Fix terminal theming when applying global defaults [#1287](https://github.com/wavetermdev/waveterm/issues/1287) - MacOS 10.15 (Catalina) is no longer supported - Other bug fixes, docs improvements, and dependency bumps diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index cbfdc779e..53fe90da3 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -246,7 +246,7 @@ function useBlockMetaKeyAtom(blockId: string, key: T): const settingsAtomCache = new Map>(); -function makeOverrideConfigAtom(blockId: string, key: T): Atom { +function getOverrideConfigAtom(blockId: string, key: T): Atom { const blockCache = getSingleBlockAtomCache(blockId); const overrideAtomName = "#settingsoverride-" + key; let overrideAtom = blockCache.get(overrideAtomName); @@ -271,7 +271,7 @@ function makeOverrideConfigAtom(blockId: string, k } function useOverrideConfigAtom(blockId: string, key: T): SettingsType[T] { - return useAtomValue(makeOverrideConfigAtom(blockId, key)); + return useAtomValue(getOverrideConfigAtom(blockId, key)); } function getSettingsKeyAtom(key: T): Atom { @@ -636,6 +636,7 @@ export { getConnStatusAtom, getHostName, getObjectId, + getOverrideConfigAtom, getSettingsKeyAtom, getUserName, globalStore, @@ -643,7 +644,6 @@ export { initGlobalWaveEventSubs, isDev, loadConnStatus, - makeOverrideConfigAtom, openLink, PLATFORM, pushFlashError, diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index c5914258e..66474b5fb 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -11,14 +11,16 @@ import { DefaultRouter, TabRpcClient } from "@/app/store/wshrpcutil"; import { TermWshClient } from "@/app/view/term/term-wsh"; import { VDomModel } from "@/app/view/vdom/vdom-model"; import { - WOS, atoms, getBlockComponentModel, + getBlockMetaKeyAtom, getConnStatusAtom, + getOverrideConfigAtom, getSettingsKeyAtom, globalStore, useBlockAtom, useSettingsPrefixAtom, + WOS, } from "@/store/global"; import * as services from "@/store/services"; import * as keyutil from "@/util/keyutil"; @@ -28,7 +30,7 @@ import * as jotai from "jotai"; import * as React from "react"; import { TermStickers } from "./termsticker"; import { TermThemeUpdater } from "./termtheme"; -import { computeTheme } from "./termutil"; +import { computeTheme, DefaultTermTheme } from "./termutil"; import { TermWrap } from "./termwrap"; import "./xterm.css"; @@ -138,16 +140,17 @@ class TermViewModel { } return true; }); + this.termThemeNameAtom = useBlockAtom(blockId, "termthemeatom", () => { + return jotai.atom((get) => { + return get(getOverrideConfigAtom(this.blockId, "term:theme")) ?? DefaultTermTheme; + }); + }); this.blockBg = jotai.atom((get) => { - const blockData = get(this.blockAtom); const fullConfig = get(atoms.fullConfigAtom); - let themeName: string = get(getSettingsKeyAtom("term:theme")); - if (blockData?.meta?.["term:theme"]) { - themeName = blockData.meta["term:theme"]; - } - const theme = computeTheme(fullConfig, themeName); - if (theme != null && theme.background != null) { - return { bg: theme.background }; + const themeName = get(this.termThemeNameAtom); + const [_, bgcolor] = computeTheme(fullConfig, themeName); + if (bgcolor != null) { + return { bg: bgcolor }; } return null; }); @@ -169,13 +172,6 @@ class TermViewModel { return rtnFontSize; }); }); - this.termThemeNameAtom = useBlockAtom(blockId, "termthemeatom", () => { - return jotai.atom((get) => { - const blockData = get(this.blockAtom); - const settingsKeyAtom = getSettingsKeyAtom("term:theme"); - return blockData?.meta?.["term:theme"] ?? get(settingsKeyAtom) ?? "default-dark"; - }); - }); this.noPadding = jotai.atom(true); this.endIconButtons = jotai.atom((get) => { const blockData = get(this.blockAtom); @@ -329,7 +325,7 @@ class TermViewModel { const fullConfig = globalStore.get(atoms.fullConfigAtom); const termThemes = fullConfig?.termthemes ?? {}; const termThemeKeys = Object.keys(termThemes); - const curThemeName = globalStore.get(this.termThemeNameAtom); + const curThemeName = globalStore.get(getBlockMetaKeyAtom(this.blockId, "term:theme")); const defaultFontSize = globalStore.get(getSettingsKeyAtom("term:fontsize")) ?? 12; const blockData = globalStore.get(this.blockAtom); const overrideFontSize = blockData?.meta?.["term:fontsize"]; @@ -346,6 +342,12 @@ class TermViewModel { click: () => this.setTerminalTheme(themeName), }; }); + submenu.unshift({ + label: "Default", + type: "checkbox", + checked: curThemeName == null, + click: () => this.setTerminalTheme(null), + }); const fontSizeSubMenu: ContextMenuItem[] = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18].map( (fontSize: number) => { return { @@ -551,9 +553,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { React.useEffect(() => { const fullConfig = globalStore.get(atoms.fullConfigAtom); - const termTheme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]); - const themeCopy = { ...termTheme }; - themeCopy.background = "#00000000"; + const termThemeName = globalStore.get(model.termThemeNameAtom); + const [termTheme, _] = computeTheme(fullConfig, termThemeName); let termScrollback = 1000; if (termSettings?.["term:scrollback"]) { termScrollback = Math.floor(termSettings["term:scrollback"]); @@ -572,7 +573,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { blockId, connectElemRef.current, { - theme: themeCopy, + theme: termTheme, fontSize: termFontSize, fontFamily: termSettings?.["term:fontfamily"] ?? "Hack", drawBoldTextInBrightColors: false, @@ -650,7 +651,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { return (
- + @@ -659,4 +660,4 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { ); }; -export { TermViewModel, TerminalView, makeTerminalModel }; +export { makeTerminalModel, TerminalView, TermViewModel }; diff --git a/frontend/app/view/term/termtheme.ts b/frontend/app/view/term/termtheme.ts index c18543b71..8852ae15a 100644 --- a/frontend/app/view/term/termtheme.ts +++ b/frontend/app/view/term/termtheme.ts @@ -1,41 +1,28 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { TermViewModel } from "@/app/view/term/term"; +import { computeTheme } from "@/app/view/term/termutil"; import { TermWrap } from "@/app/view/term/termwrap"; -import { atoms, WOS } from "@/store/global"; -import * as util from "@/util/util"; +import { atoms } from "@/store/global"; import { useAtomValue } from "jotai"; import { useEffect } from "react"; interface TermThemeProps { blockId: string; termRef: React.RefObject; + model: TermViewModel; } -const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => { +const TermThemeUpdater = ({ blockId, model, termRef }: TermThemeProps) => { const fullConfig = useAtomValue(atoms.fullConfigAtom); - const termthemes = fullConfig?.termthemes; - const [blockData] = WOS.useWaveObjectValue(WOS.makeORef("block", blockId)); - let defaultThemeName = "default-dark"; - let themeName = blockData.meta?.["term:theme"] ?? "default-dark"; - - const defaultTheme: TermThemeType = termthemes?.[defaultThemeName] || ({} as any); - const theme: TermThemeType = termthemes?.[themeName] || ({} as any); - + const blockTermTheme = useAtomValue(model.termThemeNameAtom); + const [theme, _] = computeTheme(fullConfig, blockTermTheme); useEffect(() => { - const combinedTheme = { ...defaultTheme }; - for (const key in theme) { - if (!util.isBlank(theme[key])) { - combinedTheme[key] = theme[key]; - } - } if (termRef.current?.terminal) { - let themeCopy = { ...combinedTheme }; - themeCopy.background = "#00000000"; - termRef.current.terminal.options.theme = themeCopy; + termRef.current.terminal.options.theme = theme; } - }, [defaultTheme, theme]); - + }, [theme]); return null; }; diff --git a/frontend/app/view/term/termutil.ts b/frontend/app/view/term/termutil.ts index 395ebc53e..1bed0e6d5 100644 --- a/frontend/app/view/term/termutil.ts +++ b/frontend/app/view/term/termutil.ts @@ -1,20 +1,18 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import * as util from "@/util/util"; +export const DefaultTermTheme = "default-dark"; -function computeTheme(fullConfig: FullConfigType, themeName: string): TermThemeType { - let defaultThemeName = "default-dark"; - themeName = themeName ?? "default-dark"; - 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])) { - combinedTheme[key] = theme[key]; - } +// returns (theme, bgcolor) +function computeTheme(fullConfig: FullConfigType, themeName: string): [TermThemeType, string] { + let theme: TermThemeType = fullConfig?.termthemes?.[themeName]; + if (theme == null) { + theme = fullConfig?.termthemes?.[DefaultTermTheme] || ({} as any); } - return combinedTheme; + const themeCopy = { ...theme }; + let bgcolor = themeCopy.background; + themeCopy.background = "#00000000"; + return [themeCopy, bgcolor]; } export { computeTheme };