diff --git a/shared/constants/remote-actions.tsx b/shared/constants/remote-actions.tsx index 0e7128d1b3fa..176427d4368e 100644 --- a/shared/constants/remote-actions.tsx +++ b/shared/constants/remote-actions.tsx @@ -18,7 +18,6 @@ export const pinentryOnCancel = 'remote:pinentryOnCancel' export const pinentryOnSubmit = 'remote:pinentryOnSubmit' export const powerMonitorEvent = 'remote:powerMonitorEvent' export const previewConversation = 'remote:previewConversation' -export const remoteWindowWantsProps = 'remote:remoteWindowWantsProps' export const saltpackFileOpen = 'remote:saltpackFileOpen' export const setCriticalUpdate = 'remote:setCriticalUpdate' export const showMain = 'remote:showMain' @@ -53,11 +52,6 @@ export const createUpdateWindowState = (payload: { y: number } }) => ({payload, type: updateWindowState}) as const -/** - * remote electron window wants props sent - */ -export const createRemoteWindowWantsProps = (payload: {readonly component: string; readonly param: string}) => - ({payload, type: remoteWindowWantsProps}) as const export const createCloseUnlockFolders = (payload?: undefined) => ({payload, type: closeUnlockFolders}) as const export const createDumpLogs = (payload: {readonly reason: 'quitting through menu'}) => @@ -124,7 +118,6 @@ export type PinentryOnCancelPayload = ReturnType export type PinentryOnSubmitPayload = ReturnType export type PowerMonitorEventPayload = ReturnType export type PreviewConversationPayload = ReturnType -export type RemoteWindowWantsPropsPayload = ReturnType export type SaltpackFileOpenPayload = ReturnType export type SetCriticalUpdatePayload = ReturnType export type ShowMainPayload = ReturnType @@ -156,7 +149,6 @@ export type Actions = | PinentryOnSubmitPayload | PowerMonitorEventPayload | PreviewConversationPayload - | RemoteWindowWantsPropsPayload | SaltpackFileOpenPayload | SetCriticalUpdatePayload | ShowMainPayload diff --git a/shared/desktop/app/ipc-handlers.desktop.tsx b/shared/desktop/app/ipc-handlers.desktop.tsx index 0d94e66a83e0..969814e6b9c9 100644 --- a/shared/desktop/app/ipc-handlers.desktop.tsx +++ b/shared/desktop/app/ipc-handlers.desktop.tsx @@ -12,6 +12,12 @@ import {isDarwin, isLinux, isWindows, socketPath, fileUIName, dokanPath, windows import {ctlQuit} from './ctl.desktop' import logger from '@/logger' import {htmlURL, preloadPath} from './html-root.desktop' +import { + cacheRemoteProps, + getCachedRemoteProps, + getRemoteWindow, + registerRemoteWindow, +} from './remote-windows.desktop' import * as RPCTypes from '@/constants/rpc/rpc-gen' import {ensureError} from '@/util/errors' import type {Action} from '../app/ipctypes' @@ -19,15 +25,7 @@ import type {Engine} from '@/engine' import {showDevTools, skipSecondaryDevtools, allowMultipleInstances} from '@/local-debug' const remoteURL = (windowComponent: string, windowParam: string) => - htmlURL(windowComponent, `param=${windowParam}`) - -const findRemoteComponent = (windowComponent: string, windowParam: string) => { - const url = remoteURL(windowComponent, windowParam) - return Electron.BrowserWindow.getAllWindows().find(w => { - const wc = w.webContents - return wc.getURL() === url - }) -} + htmlURL('remote', `component=${windowComponent}¶m=${windowParam}`) const winCheckRPCOwnership = async () => { const {env} = KB2.constants @@ -172,11 +170,6 @@ const openInDefaultDirectory = async (openPath: string) => { } } -const timeoutPromise = async (timeMs: number) => - new Promise(resolve => { - setTimeout(() => resolve(), timeMs) - }) - export const setupIPCHandlers = (deps: { getMainWindow: () => Electron.BrowserWindow | null markAppStartedUp: () => void @@ -523,22 +516,18 @@ export const setupIPCHandlers = (deps: { break } case 'rendererNewProps': { - // this can be racy so we try a few - let count = 0 - while (count < 5) { - const w = findRemoteComponent(action.payload.windowComponent, action.payload.windowParam) - if (w) { - w.webContents.send('KBprops', action.payload.propsStr) - break - } else { - await timeoutPromise(500) - } - ++count - } + const {windowComponent, windowParam, propsStr} = action.payload + // cache so a window that hasn't finished loading can pull these when it's ready + cacheRemoteProps(windowComponent, windowParam, propsStr) + getRemoteWindow(windowComponent, windowParam)?.webContents.send('KBprops', propsStr) break } + case 'getRemoteProps': { + const {windowComponent, windowParam} = action.payload + return getCachedRemoteProps(windowComponent, windowParam) ?? '' + } case 'closeRenderer': { - const w = findRemoteComponent(action.payload.windowComponent ?? '', action.payload.windowParam ?? '') + const w = getRemoteWindow(action.payload.windowComponent ?? '', action.payload.windowParam ?? '') w?.close() break } @@ -559,6 +548,7 @@ export const setupIPCHandlers = (deps: { } const remoteWindow = new Electron.BrowserWindow(opts) + registerRemoteWindow(action.payload.windowComponent, action.payload.windowParam ?? '', remoteWindow) remoteWindow.on('show', () => { R.remoteDispatch(RemoteGen.createUpdateWindowShown({component: action.payload.windowComponent})) diff --git a/shared/desktop/app/ipctypes.tsx b/shared/desktop/app/ipctypes.tsx index 233fa8d77a19..933d7891c419 100644 --- a/shared/desktop/app/ipctypes.tsx +++ b/shared/desktop/app/ipctypes.tsx @@ -39,6 +39,13 @@ export type Action = windowParam: string } } + | { + type: 'getRemoteProps' + payload: { + windowComponent: string + windowParam: string + } + } | {type: 'showMainWindow'} | {type: 'showContextMenu'; payload: {url: string}} | {type: 'setupPreloadKB2'} diff --git a/shared/desktop/app/menu-bar.desktop.tsx b/shared/desktop/app/menu-bar.desktop.tsx index 4624eaeb344b..5a27684b543e 100644 --- a/shared/desktop/app/menu-bar.desktop.tsx +++ b/shared/desktop/app/menu-bar.desktop.tsx @@ -8,6 +8,7 @@ import {menubar} from 'menubar' import {showDevTools, skipSecondaryDevtools} from '@/local-debug' import {getMainWindow} from './main-window.desktop' import {htmlURL, preloadPath} from './html-root.desktop' +import {registerRemoteWindow} from './remote-windows.desktop' import path from 'path' import type {BadgeType} from '@/stores/notifications' @@ -40,7 +41,7 @@ const getIcons = (iconType: BadgeType, badges: number) => { } } -const htmlFile = htmlURL('menubar', 'param=menubar') +const htmlFile = htmlURL('remote', 'component=menubar¶m=menubar') let badgeType: BadgeType = 'regular' let badges = 0 @@ -130,20 +131,15 @@ const MenuBar = () => { }) mb.on('ready', () => { + if (mb.window) { + registerRemoteWindow('menubar', 'menubar', mb.window) + } mb.window?.setVisibleOnAllWorkspaces(true, {visibleOnFullScreen: true, skipTransformProcessType: true}) mb.window ?.loadURL(htmlFile) .then(() => {}) .catch(() => {}) - // ask for an update in case we missed one - R.remoteDispatch( - RemoteGen.createRemoteWindowWantsProps({ - component: 'menubar', - param: '', - }) - ) - mb.tray.setIgnoreDoubleClickEvents(true) if (showDevTools && !skipSecondaryDevtools) { diff --git a/shared/desktop/app/remote-windows.desktop.tsx b/shared/desktop/app/remote-windows.desktop.tsx new file mode 100644 index 000000000000..3687b92bbeff --- /dev/null +++ b/shared/desktop/app/remote-windows.desktop.tsx @@ -0,0 +1,35 @@ +// Registry of remote BrowserWindows and the last props sent to each. +// The main process is the source of truth: the main window pushes props here, +// and remote windows pull the cached value when they load (or reload), so no +// handshake back to the main window is needed. +import type * as Electron from 'electron' + +const windows = new Map() +const propsCache = new Map() + +const windowKey = (windowComponent: string, windowParam: string) => `${windowComponent}:${windowParam}` + +export const registerRemoteWindow = ( + windowComponent: string, + windowParam: string, + win: Electron.BrowserWindow +) => { + const key = windowKey(windowComponent, windowParam) + windows.set(key, win) + win.on('closed', () => { + if (windows.get(key) === win) { + windows.delete(key) + propsCache.delete(key) + } + }) +} + +export const getRemoteWindow = (windowComponent: string, windowParam: string) => + windows.get(windowKey(windowComponent, windowParam)) + +export const cacheRemoteProps = (windowComponent: string, windowParam: string, propsStr: string) => { + propsCache.set(windowKey(windowComponent, windowParam), propsStr) +} + +export const getCachedRemoteProps = (windowComponent: string, windowParam: string) => + propsCache.get(windowKey(windowComponent, windowParam)) diff --git a/shared/desktop/package.desktop.mts b/shared/desktop/package.desktop.mts index cce68d6d7a2c..15c99ab92c21 100644 --- a/shared/desktop/package.desktop.mts +++ b/shared/desktop/package.desktop.mts @@ -270,7 +270,7 @@ function postPack(appPaths: Array, plat: string, arch: string) { } const subdir = plat === 'darwin' ? 'Keybase.app/Contents/Resources' : 'resources' const dir = path.join(appPaths[0]!, subdir, 'app/desktop/dist') - const modules = ['node', 'main', 'tracker', 'menubar', 'unlock-folders', 'pinentry'] + const modules = ['node', 'main', 'remote'] const files = [ ...modules.map(p => p + '.bundle.js'), ...modules.filter(p => p !== 'node').map(p => p + '.html'), diff --git a/shared/desktop/remote/component-loader.desktop.tsx b/shared/desktop/remote/component-loader.desktop.tsx index 23e17aed8e73..3879a39f0d0a 100644 --- a/shared/desktop/remote/component-loader.desktop.tsx +++ b/shared/desktop/remote/component-loader.desktop.tsx @@ -9,7 +9,12 @@ import ErrorBoundary from '@/common-adapters/error-boundary' import KB2 from '@/util/electron' import {setServiceDecoration} from '@/common-adapters/markdown/react' import ServiceDecoration from '@/common-adapters/markdown/service-decoration' -import {type RemoteComponentName, useRemotePropsReceiver} from './remote-component.desktop' +import { + getRemoteComponentParam, + type RemoteComponentName, + useRemoteDarkModeSync, + useRemotePropsReceiver, +} from './remote-component.desktop' setServiceDecoration(ServiceDecoration) @@ -29,6 +34,7 @@ type Props

= { function RemoteComponentLoader

(p: Props

) { const {Component, component, param, showOnProps} = p const value = useRemotePropsReceiver

({component, param, showOnProps}) + useRemoteDarkModeSync(value?.darkMode) if (!value) return null @@ -66,7 +72,6 @@ const styles = Kb.Styles.styleSheetCreate( export default function loadRemoteComponent

(options: { Component: React.ComponentType

component: RemoteComponentName - param?: string style?: Kb.Styles.StylesCrossPlatform showOnProps?: boolean }) { @@ -77,7 +82,7 @@ export default function loadRemoteComponent

(options: { Component={options.Component} component={options.component} - param={options.param ?? ''} + param={getRemoteComponentParam()} style={options.style} showOnProps={options.showOnProps ?? true} /> diff --git a/shared/desktop/remote/main.desktop.tsx b/shared/desktop/remote/main.desktop.tsx new file mode 100644 index 000000000000..d51c4aa7f61f --- /dev/null +++ b/shared/desktop/remote/main.desktop.tsx @@ -0,0 +1,32 @@ +// Entry point for all remote render windows. The window's URL says which +// component to load: remote.html?component=¶m= +import '../renderer/globals.desktop' +import {waitOnKB2Loaded} from '@/util/electron' + +waitOnKB2Loaded(() => { + const component = new URLSearchParams(window.location.search).get('component') + switch (component) { + case 'menubar': + import('@/menubar/main2.desktop') + .then(() => {}) + .catch(() => {}) + break + case 'pinentry': + import('@/pinentry/main2.desktop') + .then(() => {}) + .catch(() => {}) + break + case 'tracker': + import('@/tracker/main2.desktop') + .then(() => {}) + .catch(() => {}) + break + case 'unlock-folders': + import('@/unlock-folders/main2.desktop') + .then(() => {}) + .catch(() => {}) + break + default: + console.error('remote window loaded with unknown component', component) + } +}) diff --git a/shared/desktop/remote/proxies.desktop.tsx b/shared/desktop/remote/proxies.desktop.tsx index aab2df6a6134..6c2acc0e8a32 100644 --- a/shared/desktop/remote/proxies.desktop.tsx +++ b/shared/desktop/remote/proxies.desktop.tsx @@ -1,17 +1,15 @@ -import * as Kb from '@/common-adapters' import RemoteMenubar from '@/menubar/remote-proxy.desktop' import RemoteProfile from '@/tracker/remote-proxy.desktop' import RemotePinentry from '@/pinentry/remote-proxy.desktop' import RemoteUnlockFolders from '@/unlock-folders/remote-proxy.desktop' const RemoteProxies = () => ( - + <> - + ) -const style = {display: 'none' as const} export default RemoteProxies diff --git a/shared/desktop/remote/remote-component.desktop.tsx b/shared/desktop/remote/remote-component.desktop.tsx index 5104fac159af..10127c0d4ce6 100644 --- a/shared/desktop/remote/remote-component.desktop.tsx +++ b/shared/desktop/remote/remote-component.desktop.tsx @@ -1,11 +1,9 @@ import * as React from 'react' import logger from '@/logger' -import * as R from '@/constants/remote' -import * as RemoteGen from '@/constants/remote-actions' import {useDarkModeState} from '@/stores/darkmode' import KB2 from '@/util/electron' -const {ipcRendererOn, showInactive} = KB2.functions +const {getRemoteProps, ipcRendererOn, showInactive} = KB2.functions export const remoteComponentNames = ['unlock-folders', 'menubar', 'pinentry', 'tracker'] as const export type RemoteComponentName = (typeof remoteComponentNames)[number] @@ -16,56 +14,41 @@ type UseRemotePropsReceiverOptions = { showOnProps?: boolean } -type RemotePropsReceiverState

= { - component: RemoteComponentName - param: string - value: P | null -} - export const getRemoteComponentParam = () => new URLSearchParams(window!.location.search).get('param') ?? '' -export const useRemoteDarkModeSync = (darkMode: boolean) => { +// darkMode rides along in the serialized props envelope; undefined until props arrive +export const useRemoteDarkModeSync = (darkMode?: boolean) => { const setSystemDarkMode = useDarkModeState(s => s.dispatch.setSystemDarkMode) React.useEffect(() => { - setSystemDarkMode(darkMode) + if (darkMode !== undefined) { + setSystemDarkMode(darkMode) + } }, [darkMode, setSystemDarkMode]) } -export const RemoteDarkModeSync = (p: {children: React.ReactNode; darkMode: boolean}) => { - useRemoteDarkModeSync(p.darkMode) - return <>{p.children} -} - export const useRemotePropsReceiver = (options: UseRemotePropsReceiverOptions) => { const {component, param, showOnProps = true} = options - const [propsState, setPropsState] = React.useState>(() => ({ - component, - param, - value: null, - })) - const currentPropsState = - propsState.component === component && propsState.param === param - ? propsState - : {component, param, value: null} - if (currentPropsState !== propsState) { - setPropsState(currentPropsState) - } - const value = currentPropsState.value + const [value, setValue] = React.useState<(P & {darkMode: boolean}) | null>(null) const hasShownWindow = React.useRef(false) React.useEffect(() => { - hasShownWindow.current = false - - const unsubscribe = ipcRendererOn?.('KBprops', (_event: unknown, raw: unknown) => { + const onProps = (raw: string) => { + if (!raw) return try { - setPropsState({component, param, value: JSON.parse(raw as string) as P}) + setValue(JSON.parse(raw) as P & {darkMode: boolean}) } catch (error) { logger.error('remote props parse failed', component, param, error) } - }) + } - R.remoteDispatch(RemoteGen.createRemoteWindowWantsProps({component, param})) + // subscribe before pulling so an update can't slip between the two + const unsubscribe = ipcRendererOn?.('KBprops', (_event: unknown, raw: unknown) => { + onProps(raw as string) + }) + getRemoteProps?.(component, param) + .then(onProps) + .catch(() => {}) return () => unsubscribe?.() }, [component, param]) diff --git a/shared/desktop/remote/use-serialize-props.desktop.tsx b/shared/desktop/remote/use-serialize-props.desktop.tsx index 3670bad2f9a5..65c623cb0966 100644 --- a/shared/desktop/remote/use-serialize-props.desktop.tsx +++ b/shared/desktop/remote/use-serialize-props.desktop.tsx @@ -1,46 +1,34 @@ -// This hook sends props to a remote window -// Listens for requests from the main process (which proxies requests from other windows) to kick off an update +// This hook sends props to a remote window. The main process caches the last +// value sent per window, so a window that (re)loads pulls the cached props +// itself and no handshake back to this window is needed. import * as React from 'react' import * as C from '@/constants' import KB2 from '@/util/electron' -import {useConfigState} from '@/stores/config' +import {useColorScheme} from 'react-native' import type {RemoteComponentName} from './remote-component.desktop' const {rendererNewProps} = KB2.functions -// set this to true to see details of the serialization process -const debugSerializer: boolean = __DEV__ && (false as boolean) -if (debugSerializer) { - console.log('\n\n\n\n\n\nDEBUGGING REMOTE SERIALIZER') -} - export default function useSerializeProps

( props: P, windowComponent: RemoteComponentName, windowParam: string ) { const lastSent = React.useRef('') - const lastForceUpdate = React.useRef(-1) - const currentForceUpdate = useConfigState( - s => s.remoteWindowNeedsProps.get(windowComponent)?.get(windowParam) ?? 0 - ) - const propsStr = JSON.stringify(props) + const darkMode = useColorScheme() === 'dark' + const propsStr = JSON.stringify({...props, darkMode}) const throttledSend = C.useThrottledCallback( - (nextPropsStr: string, forceUpdateVersion: number) => { - if (nextPropsStr === lastSent.current && forceUpdateVersion === lastForceUpdate.current) return - if (debugSerializer) { - console.log('[useSerializeProps]: throttled send', nextPropsStr.length) - } + (nextPropsStr: string) => { + if (nextPropsStr === lastSent.current) return rendererNewProps?.({propsStr: nextPropsStr, windowComponent, windowParam}) lastSent.current = nextPropsStr - lastForceUpdate.current = forceUpdateVersion }, 1000, {leading: true} ) React.useEffect(() => { - throttledSend(propsStr, currentForceUpdate) - }, [currentForceUpdate, propsStr, throttledSend]) + throttledSend(propsStr) + }, [propsStr, throttledSend]) } diff --git a/shared/desktop/renderer/preload.desktop.tsx b/shared/desktop/renderer/preload.desktop.tsx index e76e48730c34..4746044e6915 100644 --- a/shared/desktop/renderer/preload.desktop.tsx +++ b/shared/desktop/renderer/preload.desktop.tsx @@ -82,6 +82,9 @@ if (isRenderer) { getPathForFile: (file: File) => { return Electron.webUtils.getPathForFile(file) }, + getRemoteProps: async (windowComponent: string, windowParam: string) => { + return invoke({payload: {windowComponent, windowParam}, type: 'getRemoteProps'}) + }, getPathType: async (path: string) => { return await invoke({ payload: {path}, diff --git a/shared/desktop/renderer/remote-event-handler.desktop.test.tsx b/shared/desktop/renderer/remote-event-handler.desktop.test.tsx index 9098035a878e..e2d6d9e53017 100644 --- a/shared/desktop/renderer/remote-event-handler.desktop.test.tsx +++ b/shared/desktop/renderer/remote-event-handler.desktop.test.tsx @@ -88,12 +88,13 @@ test('owner handlers stop after unregister', () => { expect(listener).not.toHaveBeenCalled() }) -test('resetAllStores clears registered owner handlers', () => { +test('owner handlers survive store resets (proxies stay mounted across logout)', () => { const listener = jest.fn() - registerRemoteActionHandler('tracker', listener) + const unregister = registerRemoteActionHandler('tracker', listener) resetAllStores() eventFromRemoteWindows(RemoteGen.createTrackerIgnore({guiID: 'gui-2'})) - expect(listener).not.toHaveBeenCalled() + expect(listener).toHaveBeenCalledWith(RemoteGen.createTrackerIgnore({guiID: 'gui-2'})) + unregister() }) diff --git a/shared/desktop/renderer/remote-event-handler.desktop.tsx b/shared/desktop/renderer/remote-event-handler.desktop.tsx index da90aebb720c..9d95fb2a45e1 100644 --- a/shared/desktop/renderer/remote-event-handler.desktop.tsx +++ b/shared/desktop/renderer/remote-event-handler.desktop.tsx @@ -18,7 +18,6 @@ import {makeUUID} from '@/util/uuid' import {dumpLogs, showMain} from '@/util/storeless-actions' import * as FSConstants from '@/constants/fs' import {openPathInSystemFileManagerDesktop} from '@/util/fs-storeless-actions' -import * as Z from '@/util/zustand' type RemoteActionOwner = 'pinentry' | 'tracker' @@ -31,57 +30,25 @@ type OwnerActionMap = { | RemoteGen.TrackerLoadPayload } -type OwnerEntry = { - handler: (action: OwnerActionMap[RemoteActionOwner]) => void - token: number -} +type OwnerHandler = (action: OwnerActionMap[RemoteActionOwner]) => void -type RemoteActionHandlerStore = { - dispatch: { - resetState: () => void - } - nextOwnerToken: number - ownerHandlers: Map -} - -const useRemoteActionHandlerState = Z.createZustand( - 'desktop-remote-action-handlers', - set => { - const resetState = () => { - set(s => { - s.nextOwnerToken = 0 - s.ownerHandlers = new Map() - }) - } - return { - dispatch: {resetState}, - nextOwnerToken: 0, - ownerHandlers: new Map(), - } - } -) +// module-level on purpose: these route actions to always-mounted proxy components, +// so they must survive the store reset that happens at logout +const ownerHandlers = new Map() const dispatchRemoteActionToOwner = (owner: K, action: OwnerActionMap[K]) => { - const entry = useRemoteActionHandlerState.getState().ownerHandlers.get(owner) - ;(entry?.handler as ((action: OwnerActionMap[K]) => void) | undefined)?.(action) + ;(ownerHandlers.get(owner) as ((action: OwnerActionMap[K]) => void) | undefined)?.(action) } export const registerRemoteActionHandler = ( owner: K, handler: (action: OwnerActionMap[K]) => void ) => { - let token = 0 - useRemoteActionHandlerState.setState(s => { - s.nextOwnerToken += 1 - token = s.nextOwnerToken - s.ownerHandlers.set(owner, {handler: handler as OwnerEntry['handler'], token}) - }) + ownerHandlers.set(owner, handler as OwnerHandler) return () => { - useRemoteActionHandlerState.setState(s => { - if (s.ownerHandlers.get(owner)?.token === token) { - s.ownerHandlers.delete(owner) - } - }) + if (ownerHandlers.get(owner) === handler) { + ownerHandlers.delete(owner) + } } } @@ -235,11 +202,6 @@ export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { case RemoteGen.dumpLogs: ignorePromise(dumpLogs(action.payload.reason)) break - case RemoteGen.remoteWindowWantsProps: - useConfigState - .getState() - .dispatch.remoteWindowNeedsProps(action.payload.component, action.payload.param) - break case RemoteGen.updateWindowMaxState: useShellState.getState().dispatch.setWindowMaximized(action.payload.max) break diff --git a/shared/desktop/webpack.config.mts b/shared/desktop/webpack.config.mts index 02f8fcb5f208..845e8d81a54d 100644 --- a/shared/desktop/webpack.config.mts +++ b/shared/desktop/webpack.config.mts @@ -45,10 +45,8 @@ const resourceAssetDirectories = [ path.resolve(__dirname, '../images/illustrations'), path.resolve(__dirname, '../images/install'), ] -const entryOverride: Record = {main: 'desktop/renderer'} -const viewEntries = debugUnusedChunks - ? ['main'] - : ['main', 'menubar', 'pinentry', 'unlock-folders', 'tracker'] +const entryOverride: Record = {main: 'desktop/renderer', remote: 'desktop/remote'} +const viewEntries = debugUnusedChunks ? ['main'] : ['main', 'remote'] type DesktopConfiguration = Configuration & { devServer?: WebpackDevServerConfiguration diff --git a/shared/menubar/index.desktop.tsx b/shared/menubar/index.desktop.tsx index dc521e3e78f7..04225f362f16 100644 --- a/shared/menubar/index.desktop.tsx +++ b/shared/menubar/index.desktop.tsx @@ -63,7 +63,6 @@ export type Props = { showingDiskSpaceBanner: boolean totalSyncingBytes: number username: string - darkMode: boolean } // Simple avatar via httpSrv diff --git a/shared/menubar/main.desktop.tsx b/shared/menubar/main.desktop.tsx deleted file mode 100644 index aac114683bf5..000000000000 --- a/shared/menubar/main.desktop.tsx +++ /dev/null @@ -1,6 +0,0 @@ -// Entry point for the menubar render window -import '../desktop/renderer/globals.desktop' -import {waitOnKB2Loaded} from '@/util/electron' -waitOnKB2Loaded(() => { - import('./main2.desktop').then(() => {}).catch(() => {}) -}) diff --git a/shared/menubar/main2.desktop.tsx b/shared/menubar/main2.desktop.tsx index 783998e6ee85..0c9b2c0fb11c 100644 --- a/shared/menubar/main2.desktop.tsx +++ b/shared/menubar/main2.desktop.tsx @@ -1,14 +1,7 @@ import Menubar from './index.desktop' import loadRemoteComponent from '../desktop/remote/component-loader.desktop' -import {RemoteDarkModeSync} from '../desktop/remote/remote-component.desktop' import type {Props} from './index.desktop' -const RemoteMenubar = (p: Props) => ( - - - -) - // This is to keep that arrow and gap on top w/ transparency const style = { borderTopLeftRadius: 4, @@ -21,7 +14,7 @@ const style = { } as const loadRemoteComponent({ - Component: RemoteMenubar, + Component: Menubar, component: 'menubar', showOnProps: false, style, diff --git a/shared/menubar/remote-proxy.desktop.tsx b/shared/menubar/remote-proxy.desktop.tsx index 69e10e464049..04989dfbc818 100644 --- a/shared/menubar/remote-proxy.desktop.tsx +++ b/shared/menubar/remote-proxy.desktop.tsx @@ -8,7 +8,6 @@ import * as React from 'react' import KB2 from '@/util/electron' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' import type {Props, Conversation, RemoteTlfUpdates} from './index.desktop' -import {useColorScheme} from 'react-native' import {useFsErrorActionOrThrow} from '@/fs/common/error-state' import {useCurrentUserState} from '@/stores/current-user' import {useFollowerState} from '@/stores/followers' @@ -359,7 +358,6 @@ function useMenubarRemoteProps(): Props { ) useEnsureWidgetData(loggedIn, inboxHasLoaded, widgetList, inboxRefresh) const conversationsToSend = useWidgetConversationList(widgetList, badgeState) - const isDarkMode = useColorScheme() === 'dark' const {diskSpaceStatus, showingBanner} = overallSyncStatus const menuWindowShownCount = windowShownCount.get('menu') ?? 0 const kbfsEnabled = useMenubarSfmiEnabled( @@ -398,7 +396,6 @@ function useMenubarRemoteProps(): Props { ...upDown, conversationsToSend, daemonHandshakeState, - darkMode: isDarkMode, diskSpaceStatus, following, httpSrvAddress: httpSrv.address, diff --git a/shared/pinentry/main.desktop.tsx b/shared/pinentry/main.desktop.tsx deleted file mode 100644 index 946161bd056c..000000000000 --- a/shared/pinentry/main.desktop.tsx +++ /dev/null @@ -1,4 +0,0 @@ -// Entry point for the pinentry render window -import '../desktop/renderer/globals.desktop' -import {waitOnKB2Loaded} from '@/util/electron' -waitOnKB2Loaded(() => require('./main2.desktop') as () => void) diff --git a/shared/pinentry/main2.desktop.tsx b/shared/pinentry/main2.desktop.tsx index 1daefa0231cd..76c087186a5a 100644 --- a/shared/pinentry/main2.desktop.tsx +++ b/shared/pinentry/main2.desktop.tsx @@ -3,11 +3,9 @@ import * as RemoteGen from '@/constants/remote-actions' import type * as T from '@/constants/types' import Pinentry from './index.desktop' import loadRemoteComponent from '../desktop/remote/component-loader.desktop' -import {getRemoteComponentParam, RemoteDarkModeSync} from '../desktop/remote/remote-component.desktop' export type ProxyProps = { cancelLabel?: string - darkMode: boolean prompt: string retryLabel?: string showTyping?: T.RPCGen.Feature @@ -16,21 +14,15 @@ export type ProxyProps = { windowTitle: string } -const RemotePinentry = (p: ProxyProps) => { - const {darkMode, ...rest} = p - return ( - - R.remoteDispatch(RemoteGen.createPinentryOnCancel())} - onSubmit={(password: string) => R.remoteDispatch(RemoteGen.createPinentryOnSubmit({password}))} - /> - - ) -} +const RemotePinentry = (p: ProxyProps) => ( + R.remoteDispatch(RemoteGen.createPinentryOnCancel())} + onSubmit={(password: string) => R.remoteDispatch(RemoteGen.createPinentryOnSubmit({password}))} + /> +) loadRemoteComponent({ Component: RemotePinentry, component: 'pinentry', - param: getRemoteComponentParam(), }) diff --git a/shared/pinentry/remote-proxy.desktop.tsx b/shared/pinentry/remote-proxy.desktop.tsx index 9ce692699d75..4029ed1f6b25 100644 --- a/shared/pinentry/remote-proxy.desktop.tsx +++ b/shared/pinentry/remote-proxy.desktop.tsx @@ -7,7 +7,6 @@ import {useEngineActionListener} from '@/engine/action-listener' import logger from '@/logger' import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' -import {useColorScheme} from 'react-native' import * as React from 'react' import {useConfigState} from '@/stores/config' import type {ProxyProps} from './main2.desktop' @@ -117,12 +116,10 @@ const PinentryProxy = () => { } const {cancelLabel, prompt, retryLabel, showTyping, submitLabel, type, windowTitle} = currentPopupState const show = type !== T.RPCGen.PassphraseType.none - const darkMode = useColorScheme() === 'dark' if (show) { return ( > revokedTrigger: number runtimeStats?: T.RPCGen.RuntimeStats startup: { @@ -83,7 +82,6 @@ const initialStore: Store = { outOfDate: false, updating: false, }, - remoteWindowNeedsProps: new Map(), revokedTrigger: 0, startup: { conversation: noConversationIDKey, @@ -109,7 +107,6 @@ export type State = Store & { onEngineIncoming: (action: EngineGen.Actions) => void powerMonitorEvent: (event: string) => void resetState: (isDebug?: boolean) => void - remoteWindowNeedsProps: (component: string, params: string) => void resetRevokedSelf: () => void revoke: (deviceName: string, wasCurrentDevice: boolean) => void refreshAccounts: () => Promise @@ -447,13 +444,6 @@ export const useConfigState = Z.createZustand('config', (set, get) => { inflightRefreshAccounts = undefined } }, - remoteWindowNeedsProps: (component, params) => { - set(s => { - const map = s.remoteWindowNeedsProps.get(component) ?? new Map() - map.set(params, (map.get(params) ?? 0) + 1) - s.remoteWindowNeedsProps.set(component, map) - }) - }, resetRevokedSelf: () => { set(s => { s.justRevokedSelf = '' diff --git a/shared/stores/tests/config.test.ts b/shared/stores/tests/config.test.ts index 4130ba253f39..1df0b762284f 100644 --- a/shared/stores/tests/config.test.ts +++ b/shared/stores/tests/config.test.ts @@ -14,7 +14,6 @@ const resetConfigState = () => { outOfDate: false, updating: false, }, - remoteWindowNeedsProps: new Map(), startup: { conversation: noConversationIDKey, followUser: '', @@ -34,18 +33,6 @@ afterEach(() => { resetConfigState() }) -test('remoteWindowNeedsProps counts requests per component and params', () => { - const {dispatch} = useConfigState.getState() - - dispatch.remoteWindowNeedsProps('remote-profile', '{"username":"alice"}') - dispatch.remoteWindowNeedsProps('remote-profile', '{"username":"alice"}') - dispatch.remoteWindowNeedsProps('remote-profile', '{"username":"bob"}') - - const counts = useConfigState.getState().remoteWindowNeedsProps.get('remote-profile') - expect(counts?.get('{"username":"alice"}')).toBe(2) - expect(counts?.get('{"username":"bob"}')).toBe(1) -}) - test('setStartupDetails only records the first startup payload', () => { const {dispatch} = useConfigState.getState() diff --git a/shared/tracker/main.desktop.tsx b/shared/tracker/main.desktop.tsx deleted file mode 100644 index d92ac3514cb7..000000000000 --- a/shared/tracker/main.desktop.tsx +++ /dev/null @@ -1,6 +0,0 @@ -// Entry point for the tracker render window -import '../desktop/renderer/globals.desktop' -import {waitOnKB2Loaded} from '@/util/electron' -waitOnKB2Loaded(() => { - import('./main2.desktop').then(() => {}).catch(() => {}) -}) diff --git a/shared/tracker/main2.desktop.tsx b/shared/tracker/main2.desktop.tsx index a634e52e54f6..4bef4591bb68 100644 --- a/shared/tracker/main2.desktop.tsx +++ b/shared/tracker/main2.desktop.tsx @@ -4,7 +4,6 @@ import * as R from '@/constants/remote' import * as RemoteGen from '../constants/remote-actions' import Tracker from './index.desktop' import loadRemoteComponent from '../desktop/remote/component-loader.desktop' -import {getRemoteComponentParam, RemoteDarkModeSync} from '../desktop/remote/remote-component.desktop' import type {Props as TrackerProps} from './index.desktop' import KB2 from '@/util/electron' @@ -13,41 +12,38 @@ const {closeWindow} = KB2.functions type ProxyProps = Omit const RemoteTracker = (p: ProxyProps) => ( - - R.remoteDispatch(RemoteGen.createTrackerChangeFollow({follow: true, guiID: p.guiID}))} - onChat={() => { - R.remoteDispatch(RemoteGen.createShowMain()) - R.remoteDispatch(RemoteGen.createPreviewConversation({participant: p.trackerUsername})) - }} - onClose={() => { - R.remoteDispatch(RemoteGen.createTrackerCloseTracker({guiID: p.guiID})) - closeWindow?.() - }} - onFollow={() => R.remoteDispatch(RemoteGen.createTrackerChangeFollow({follow: true, guiID: p.guiID}))} - onIgnoreFor24Hours={() => R.remoteDispatch(RemoteGen.createTrackerIgnore({guiID: p.guiID}))} - onReload={() => - R.remoteDispatch( - RemoteGen.createTrackerLoad({ - assertion: p.trackerUsername, - forceDisplay: true, - fromDaemon: false, - guiID: C.generateGUIID(), - ignoreCache: true, - inTracker: true, - reason: '', - }) - ) - } - /> - + R.remoteDispatch(RemoteGen.createTrackerChangeFollow({follow: true, guiID: p.guiID}))} + onChat={() => { + R.remoteDispatch(RemoteGen.createShowMain()) + R.remoteDispatch(RemoteGen.createPreviewConversation({participant: p.trackerUsername})) + }} + onClose={() => { + R.remoteDispatch(RemoteGen.createTrackerCloseTracker({guiID: p.guiID})) + closeWindow?.() + }} + onFollow={() => R.remoteDispatch(RemoteGen.createTrackerChangeFollow({follow: true, guiID: p.guiID}))} + onIgnoreFor24Hours={() => R.remoteDispatch(RemoteGen.createTrackerIgnore({guiID: p.guiID}))} + onReload={() => + R.remoteDispatch( + RemoteGen.createTrackerLoad({ + assertion: p.trackerUsername, + forceDisplay: true, + fromDaemon: false, + guiID: C.generateGUIID(), + ignoreCache: true, + inTracker: true, + reason: '', + }) + ) + } + /> ) loadRemoteComponent({ Component: RemoteTracker, component: 'tracker', - param: getRemoteComponentParam(), style: Kb.Styles.platformStyles({ isElectron: { backgroundColor: Kb.Styles.globalColors.transparent, diff --git a/shared/tracker/remote-proxy.desktop.tsx b/shared/tracker/remote-proxy.desktop.tsx index 879a07fc378f..f69fe121b032 100644 --- a/shared/tracker/remote-proxy.desktop.tsx +++ b/shared/tracker/remote-proxy.desktop.tsx @@ -5,7 +5,6 @@ import * as T from '@/constants/types' import {generateGUIID, ignorePromise} from '@/constants/utils' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' -import {useColorScheme} from 'react-native' import {useUsersState} from '@/stores/users' import {useFollowerState} from '@/stores/followers' import {useCurrentUserState} from '@/stores/current-user' @@ -67,7 +66,6 @@ const RemoteTracker = (props: {details: T.Tracker.Details; trackerUsername: stri const following = useFollowerState(s => s.following) const username = useCurrentUserState(s => s.username) const httpSrv = useConfigState(s => s.httpSrv) - const isDarkMode = useColorScheme() === 'dark' const windowComponent = 'tracker' const windowParam = trackerUsername @@ -84,7 +82,6 @@ const RemoteTracker = (props: {details: T.Tracker.Details; trackerUsername: stri assertions: details.assertions ? [...details.assertions.values()] : undefined, bio: details.bio, blocked: blockMap.get(trackerUsername)?.chatBlocked || false, - darkMode: isDarkMode, followThem: following.has(trackerUsername), followersCount: details.followersCount, followingCount: details.followingCount, diff --git a/shared/unlock-folders/main.desktop.tsx b/shared/unlock-folders/main.desktop.tsx deleted file mode 100644 index f32552456c90..000000000000 --- a/shared/unlock-folders/main.desktop.tsx +++ /dev/null @@ -1,4 +0,0 @@ -// Entry point for the unlock folders render window -import '../desktop/renderer/globals.desktop' -import {waitOnKB2Loaded} from '@/util/electron' -waitOnKB2Loaded(() => require('./main2.desktop') as () => void) diff --git a/shared/unlock-folders/main2.desktop.tsx b/shared/unlock-folders/main2.desktop.tsx index 08f4fcaf1012..ec8daceb6cae 100644 --- a/shared/unlock-folders/main2.desktop.tsx +++ b/shared/unlock-folders/main2.desktop.tsx @@ -3,11 +3,9 @@ import * as R from '@/constants/remote' import * as RemoteGen from '../constants/remote-actions' import UnlockFolders from './index.desktop' import loadRemoteComponent from '../desktop/remote/component-loader.desktop' -import {RemoteDarkModeSync} from '../desktop/remote/remote-component.desktop' import type {UnlockFolderDevice} from './store' export type ProxyProps = { - darkMode: boolean devices: ReadonlyArray paperKeyError: string waiting: boolean @@ -16,7 +14,7 @@ export type ProxyProps = { type Phase = 'promptOtherDevice' | 'paperKeyInput' | 'success' const UnlockFoldersWrapper = (p: ProxyProps) => { - const {darkMode, devices, waiting, paperKeyError: _error} = p + const {devices, waiting, paperKeyError: _error} = p const [phase, setPhase] = React.useState('promptOtherDevice') const [paperKeyError, setPaperKeyError] = React.useState(_error) @@ -37,21 +35,19 @@ const UnlockFoldersWrapper = (p: ProxyProps) => { }, [phase]) return ( - - setPhase('promptOtherDevice')} - onClose={() => R.remoteDispatch(RemoteGen.createCloseUnlockFolders())} - onContinueFromPaperKey={(paperKey: string) => - R.remoteDispatch(RemoteGen.createUnlockFoldersSubmitPaperKey({paperKey})) - } - onFinish={() => R.remoteDispatch(RemoteGen.createCloseUnlockFolders())} - toPaperKeyInput={() => setPhase('paperKeyInput')} - /> - + setPhase('promptOtherDevice')} + onClose={() => R.remoteDispatch(RemoteGen.createCloseUnlockFolders())} + onContinueFromPaperKey={(paperKey: string) => + R.remoteDispatch(RemoteGen.createUnlockFoldersSubmitPaperKey({paperKey})) + } + onFinish={() => R.remoteDispatch(RemoteGen.createCloseUnlockFolders())} + toPaperKeyInput={() => setPhase('paperKeyInput')} + /> ) } diff --git a/shared/unlock-folders/remote-proxy.desktop.tsx b/shared/unlock-folders/remote-proxy.desktop.tsx index 0c678752e716..78793b176fce 100644 --- a/shared/unlock-folders/remote-proxy.desktop.tsx +++ b/shared/unlock-folders/remote-proxy.desktop.tsx @@ -2,7 +2,6 @@ import * as C from '@/constants' import {useEngineActionListener} from '@/engine/action-listener' import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' -import {useColorScheme} from 'react-native' import {handleUnlockFoldersEngineAction} from './engine-actions.desktop' import type {ProxyProps} from './main2.desktop' import {useUnlockFoldersState} from './store' @@ -33,7 +32,6 @@ const UnlockRemoteProxy = () => { })) ) const waiting = C.Waiting.useAnyWaiting('unlock-folders:waiting') - const isDarkMode = useColorScheme() === 'dark' useEngineActionListener('keybase.1.rekeyUI.refresh', action => { handleUnlockFoldersEngineAction(action, open) @@ -44,14 +42,7 @@ const UnlockRemoteProxy = () => { }) if (devices.length) { - return ( - - ) + return } return null } diff --git a/shared/util/electron.tsx b/shared/util/electron.tsx index e7c1eba88282..d95be2ac6b00 100644 --- a/shared/util/electron.tsx +++ b/shared/util/electron.tsx @@ -79,6 +79,7 @@ export type KB2 = { ipcRendererOn?: (channel: string, cb: (event: unknown, action: unknown) => void) => (() => void) | undefined hideWindow?: () => void getPathType?: (path: string) => Promise<'file' | 'directory'> + getRemoteProps?: (windowComponent: string, windowParam: string) => Promise // defined for both always mainWindowDispatch: (action: Actions) => void mainWindowDispatchEngineIncoming?: (data: Uint8Array) => void