refactor(ui): keep locale bootstrap branch focused
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
import { Component, For, Show, Suspense, createMemo, createEffect, createSignal, lazy, onMount, onCleanup } from "solid-js"
|
import { Component, For, Show, createMemo, createEffect, createSignal, onMount, onCleanup } from "solid-js"
|
||||||
import { Dialog } from "@kobalte/core/dialog"
|
import { Dialog } from "@kobalte/core/dialog"
|
||||||
import { Toaster } from "solid-toast"
|
import { Toaster } from "solid-toast"
|
||||||
import useMediaQuery from "@suid/material/useMediaQuery"
|
import useMediaQuery from "@suid/material/useMediaQuery"
|
||||||
import { Minimize2 } from "lucide-solid"
|
import { Minimize2 } from "lucide-solid"
|
||||||
import AlertDialog from "./components/alert-dialog"
|
import AlertDialog from "./components/alert-dialog"
|
||||||
|
import FolderSelectionView from "./components/folder-selection-view"
|
||||||
import { showConfirmDialog } from "./stores/alerts"
|
import { showConfirmDialog } from "./stores/alerts"
|
||||||
import InstanceTabs from "./components/instance-tabs"
|
import InstanceTabs from "./components/instance-tabs"
|
||||||
|
import InstanceDisconnectedModal from "./components/instance-disconnected-modal"
|
||||||
import InstanceShell from "./components/instance/instance-shell2"
|
import InstanceShell from "./components/instance/instance-shell2"
|
||||||
|
import { SettingsScreen } from "./components/settings-screen"
|
||||||
import { InstanceMetadataProvider } from "./lib/contexts/instance-metadata-context"
|
import { InstanceMetadataProvider } from "./lib/contexts/instance-metadata-context"
|
||||||
import { initMarkdown } from "./lib/markdown"
|
import { initMarkdown } from "./lib/markdown"
|
||||||
import { initGithubStars } from "./stores/github-stars"
|
import { initGithubStars } from "./stores/github-stars"
|
||||||
@@ -51,16 +54,10 @@ import {
|
|||||||
} from "./stores/sessions"
|
} from "./stores/sessions"
|
||||||
|
|
||||||
import { getInstanceSessionIndicatorStatus } from "./stores/session-status"
|
import { getInstanceSessionIndicatorStatus } from "./stores/session-status"
|
||||||
import { openSettings, settingsOpen } from "./stores/settings-screen"
|
import { openSettings } from "./stores/settings-screen"
|
||||||
|
|
||||||
const log = getLogger("actions")
|
const log = getLogger("actions")
|
||||||
|
|
||||||
const LazyFolderSelectionView = lazy(() => import("./components/folder-selection-view"))
|
|
||||||
const LazyInstanceDisconnectedModal = lazy(() => import("./components/instance-disconnected-modal"))
|
|
||||||
const LazySettingsScreen = lazy(() =>
|
|
||||||
import("./components/settings-screen").then((module) => ({ default: module.SettingsScreen })),
|
|
||||||
)
|
|
||||||
|
|
||||||
const App: Component = () => {
|
const App: Component = () => {
|
||||||
const { isDark } = useTheme()
|
const { isDark } = useTheme()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -412,16 +409,12 @@ const App: Component = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Show when={Boolean(disconnectedInstance())}>
|
<InstanceDisconnectedModal
|
||||||
<Suspense fallback={null}>
|
open={Boolean(disconnectedInstance())}
|
||||||
<LazyInstanceDisconnectedModal
|
folder={disconnectedInstance()?.folder}
|
||||||
open={Boolean(disconnectedInstance())}
|
reason={disconnectedInstance()?.reason}
|
||||||
folder={disconnectedInstance()?.folder}
|
onClose={handleDisconnectedInstanceClose}
|
||||||
reason={disconnectedInstance()?.reason}
|
/>
|
||||||
onClose={handleDisconnectedInstanceClose}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Dialog open={Boolean(launchError())} modal>
|
<Dialog open={Boolean(launchError())} modal>
|
||||||
<Dialog.Portal>
|
<Dialog.Portal>
|
||||||
@@ -534,37 +527,29 @@ const App: Component = () => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<div class="flex-1 min-h-0" />}>
|
<FolderSelectionView
|
||||||
<LazyFolderSelectionView
|
onSelectFolder={handleSelectFolder}
|
||||||
onSelectFolder={handleSelectFolder}
|
isLoading={isSelectingFolder()}
|
||||||
isLoading={isSelectingFolder()}
|
/>
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={showFolderSelection()}>
|
<Show when={showFolderSelection()}>
|
||||||
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
|
<div class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center">
|
||||||
<div class="w-full h-full relative">
|
<div class="w-full h-full relative">
|
||||||
<Suspense fallback={<div class="w-full h-full" />}>
|
<FolderSelectionView
|
||||||
<LazyFolderSelectionView
|
onSelectFolder={handleSelectFolder}
|
||||||
onSelectFolder={handleSelectFolder}
|
isLoading={isSelectingFolder()}
|
||||||
isLoading={isSelectingFolder()}
|
onClose={() => {
|
||||||
onClose={() => {
|
setShowFolderSelection(false)
|
||||||
setShowFolderSelection(false)
|
clearLaunchError()
|
||||||
clearLaunchError()
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={settingsOpen()}>
|
<SettingsScreen />
|
||||||
<Suspense fallback={null}>
|
|
||||||
<LazySettingsScreen />
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<AlertDialog />
|
<AlertDialog />
|
||||||
|
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
For,
|
For,
|
||||||
Show,
|
Show,
|
||||||
Suspense,
|
|
||||||
createEffect,
|
createEffect,
|
||||||
createMemo,
|
createMemo,
|
||||||
createSignal,
|
createSignal,
|
||||||
lazy,
|
|
||||||
onCleanup,
|
onCleanup,
|
||||||
onMount,
|
onMount,
|
||||||
type Accessor,
|
type Accessor,
|
||||||
@@ -24,7 +22,11 @@ import { keyboardRegistry, type KeyboardShortcut } from "../../lib/keyboard-regi
|
|||||||
|
|
||||||
import { isOpen as isCommandPaletteOpen, hideCommandPalette, showCommandPalette } from "../../stores/command-palette"
|
import { isOpen as isCommandPaletteOpen, hideCommandPalette, showCommandPalette } from "../../stores/command-palette"
|
||||||
import Kbd from "../kbd"
|
import Kbd from "../kbd"
|
||||||
|
import InstanceWelcomeView from "../instance-welcome-view"
|
||||||
|
import InfoView from "../info-view"
|
||||||
|
import CommandPalette from "../command-palette"
|
||||||
import PermissionNotificationBanner from "../permission-notification-banner"
|
import PermissionNotificationBanner from "../permission-notification-banner"
|
||||||
|
import PermissionApprovalModal from "../permission-approval-modal"
|
||||||
import SessionView from "../session/session-view"
|
import SessionView from "../session/session-view"
|
||||||
import { formatTokenTotal } from "../../lib/formatters"
|
import { formatTokenTotal } from "../../lib/formatters"
|
||||||
import ContextMeter from "../context-meter"
|
import ContextMeter from "../context-meter"
|
||||||
@@ -32,10 +34,12 @@ import { sseManager } from "../../lib/sse-manager"
|
|||||||
import { getLogger } from "../../lib/logger"
|
import { getLogger } from "../../lib/logger"
|
||||||
import { serverApi } from "../../lib/api-client"
|
import { serverApi } from "../../lib/api-client"
|
||||||
import { loadBackgroundProcesses } from "../../stores/background-processes"
|
import { loadBackgroundProcesses } from "../../stores/background-processes"
|
||||||
|
import { BackgroundProcessOutputDialog } from "../background-process-output-dialog"
|
||||||
import { useI18n } from "../../lib/i18n"
|
import { useI18n } from "../../lib/i18n"
|
||||||
import { getPermissionQueueLength, getQuestionQueueLength } from "../../stores/instances"
|
import { getPermissionQueueLength, getQuestionQueueLength } from "../../stores/instances"
|
||||||
import SessionSidebar from "./shell/SessionSidebar"
|
import SessionSidebar from "./shell/SessionSidebar"
|
||||||
import { useSessionSidebarRequests } from "./shell/useSessionSidebarRequests"
|
import { useSessionSidebarRequests } from "./shell/useSessionSidebarRequests"
|
||||||
|
import RightPanel from "./shell/right-panel/RightPanel"
|
||||||
import { useDrawerChrome } from "./shell/useDrawerChrome"
|
import { useDrawerChrome } from "./shell/useDrawerChrome"
|
||||||
import { getSessionStatus } from "../../stores/session-status"
|
import { getSessionStatus } from "../../stores/session-status"
|
||||||
import { Maximize2, ShieldAlert } from "lucide-solid"
|
import { Maximize2, ShieldAlert } from "lucide-solid"
|
||||||
@@ -56,19 +60,6 @@ import { useInstanceSessionContext } from "./shell/useInstanceSessionContext"
|
|||||||
|
|
||||||
const log = getLogger("session")
|
const log = getLogger("session")
|
||||||
|
|
||||||
const LazyInstanceWelcomeView = lazy(() => import("../instance-welcome-view"))
|
|
||||||
const LazyInfoView = lazy(() => import("../info-view"))
|
|
||||||
const LazyCommandPalette = lazy(() => import("../command-palette"))
|
|
||||||
const LazyBackgroundProcessOutputDialog = lazy(() =>
|
|
||||||
import("../background-process-output-dialog").then((module) => ({ default: module.BackgroundProcessOutputDialog })),
|
|
||||||
)
|
|
||||||
const LazyPermissionApprovalModal = lazy(() => import("../permission-approval-modal"))
|
|
||||||
const LazyRightPanel = lazy(() => import("./shell/right-panel/RightPanel"))
|
|
||||||
|
|
||||||
function RightPanelFallback() {
|
|
||||||
return <div class="flex-1 min-h-0" />
|
|
||||||
}
|
|
||||||
|
|
||||||
interface InstanceShellProps {
|
interface InstanceShellProps {
|
||||||
instance: Instance
|
instance: Instance
|
||||||
// Provided by App-level instance tabs; lets us pause heavy rendering
|
// Provided by App-level instance tabs; lets us pause heavy rendering
|
||||||
@@ -503,30 +494,28 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
role="presentation"
|
role="presentation"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<Suspense fallback={<RightPanelFallback />}>
|
<RightPanel
|
||||||
<LazyRightPanel
|
t={t}
|
||||||
t={t}
|
instanceId={props.instance.id}
|
||||||
instanceId={props.instance.id}
|
instance={props.instance}
|
||||||
instance={props.instance}
|
activeSessionId={activeSessionIdForInstance}
|
||||||
activeSessionId={activeSessionIdForInstance}
|
activeSession={activeSessionForInstance}
|
||||||
activeSession={activeSessionForInstance}
|
activeSessionDiffs={activeSessionDiffs}
|
||||||
activeSessionDiffs={activeSessionDiffs}
|
latestTodoState={latestTodoState}
|
||||||
latestTodoState={latestTodoState}
|
backgroundProcessList={backgroundProcessList}
|
||||||
backgroundProcessList={backgroundProcessList}
|
onOpenBackgroundOutput={openBackgroundOutput}
|
||||||
onOpenBackgroundOutput={openBackgroundOutput}
|
onStopBackgroundProcess={stopBackgroundProcess}
|
||||||
onStopBackgroundProcess={stopBackgroundProcess}
|
onTerminateBackgroundProcess={terminateBackgroundProcess}
|
||||||
onTerminateBackgroundProcess={terminateBackgroundProcess}
|
isPhoneLayout={isPhoneLayout}
|
||||||
isPhoneLayout={isPhoneLayout}
|
rightDrawerWidth={rightDrawerWidth}
|
||||||
rightDrawerWidth={rightDrawerWidth}
|
rightDrawerWidthInitialized={rightDrawerWidthInitialized}
|
||||||
rightDrawerWidthInitialized={rightDrawerWidthInitialized}
|
rightDrawerState={rightDrawerState}
|
||||||
rightDrawerState={rightDrawerState}
|
rightPinned={rightPinned}
|
||||||
rightPinned={rightPinned}
|
onCloseRightDrawer={closeRightDrawer}
|
||||||
onCloseRightDrawer={closeRightDrawer}
|
onPinRightDrawer={pinRightDrawer}
|
||||||
onPinRightDrawer={pinRightDrawer}
|
onUnpinRightDrawer={unpinRightDrawer}
|
||||||
onUnpinRightDrawer={unpinRightDrawer}
|
setContentEl={setRightDrawerContentEl}
|
||||||
setContentEl={setRightDrawerContentEl}
|
/>
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -566,32 +555,28 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={rightOpen() || rightPinned()} fallback={<RightPanelFallback />}>
|
<RightPanel
|
||||||
<Suspense fallback={<RightPanelFallback />}>
|
t={t}
|
||||||
<LazyRightPanel
|
instanceId={props.instance.id}
|
||||||
t={t}
|
instance={props.instance}
|
||||||
instanceId={props.instance.id}
|
activeSessionId={activeSessionIdForInstance}
|
||||||
instance={props.instance}
|
activeSession={activeSessionForInstance}
|
||||||
activeSessionId={activeSessionIdForInstance}
|
activeSessionDiffs={activeSessionDiffs}
|
||||||
activeSession={activeSessionForInstance}
|
latestTodoState={latestTodoState}
|
||||||
activeSessionDiffs={activeSessionDiffs}
|
backgroundProcessList={backgroundProcessList}
|
||||||
latestTodoState={latestTodoState}
|
onOpenBackgroundOutput={openBackgroundOutput}
|
||||||
backgroundProcessList={backgroundProcessList}
|
onStopBackgroundProcess={stopBackgroundProcess}
|
||||||
onOpenBackgroundOutput={openBackgroundOutput}
|
onTerminateBackgroundProcess={terminateBackgroundProcess}
|
||||||
onStopBackgroundProcess={stopBackgroundProcess}
|
isPhoneLayout={isPhoneLayout}
|
||||||
onTerminateBackgroundProcess={terminateBackgroundProcess}
|
rightDrawerWidth={rightDrawerWidth}
|
||||||
isPhoneLayout={isPhoneLayout}
|
rightDrawerWidthInitialized={rightDrawerWidthInitialized}
|
||||||
rightDrawerWidth={rightDrawerWidth}
|
rightDrawerState={rightDrawerState}
|
||||||
rightDrawerWidthInitialized={rightDrawerWidthInitialized}
|
rightPinned={rightPinned}
|
||||||
rightDrawerState={rightDrawerState}
|
onCloseRightDrawer={closeRightDrawer}
|
||||||
rightPinned={rightPinned}
|
onPinRightDrawer={pinRightDrawer}
|
||||||
onCloseRightDrawer={closeRightDrawer}
|
onUnpinRightDrawer={unpinRightDrawer}
|
||||||
onPinRightDrawer={pinRightDrawer}
|
setContentEl={setRightDrawerContentEl}
|
||||||
onUnpinRightDrawer={unpinRightDrawer}
|
/>
|
||||||
setContentEl={setRightDrawerContentEl}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
||||||
)
|
)
|
||||||
@@ -849,9 +834,7 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="info-view-pane flex flex-col flex-1 min-h-0 overflow-y-auto">
|
<div class="info-view-pane flex flex-col flex-1 min-h-0 overflow-y-auto">
|
||||||
<Suspense fallback={<div class="flex-1 min-h-0" />}>
|
<InfoView instanceId={props.instance.id} />
|
||||||
<LazyInfoView instanceId={props.instance.id} />
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -867,49 +850,30 @@ const InstanceShell2: Component<InstanceShellProps> = (props) => {
|
|||||||
class="instance-shell2 flex flex-col flex-1 min-h-0"
|
class="instance-shell2 flex flex-col flex-1 min-h-0"
|
||||||
data-instance-id={props.instance.id}
|
data-instance-id={props.instance.id}
|
||||||
>
|
>
|
||||||
<Show
|
<Show when={hasSessions()} fallback={<InstanceWelcomeView instance={props.instance} />}>
|
||||||
when={hasSessions()}
|
|
||||||
fallback={
|
|
||||||
<Suspense fallback={<div class="flex-1 min-h-0" />}>
|
|
||||||
<LazyInstanceWelcomeView instance={props.instance} />
|
|
||||||
</Suspense>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{sessionLayout}
|
{sessionLayout}
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={paletteOpen()}>
|
<CommandPalette
|
||||||
<Suspense fallback={null}>
|
open={paletteOpen()}
|
||||||
<LazyCommandPalette
|
onClose={() => hideCommandPalette(props.instance.id)}
|
||||||
open={paletteOpen()}
|
commands={instancePaletteCommands()}
|
||||||
onClose={() => hideCommandPalette(props.instance.id)}
|
onExecute={props.onExecuteCommand}
|
||||||
commands={instancePaletteCommands()}
|
/>
|
||||||
onExecute={props.onExecuteCommand}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={showBackgroundOutput()}>
|
<BackgroundProcessOutputDialog
|
||||||
<Suspense fallback={null}>
|
open={showBackgroundOutput()}
|
||||||
<LazyBackgroundProcessOutputDialog
|
instanceId={props.instance.id}
|
||||||
open={showBackgroundOutput()}
|
process={selectedBackgroundProcess()}
|
||||||
instanceId={props.instance.id}
|
onClose={closeBackgroundOutput}
|
||||||
process={selectedBackgroundProcess()}
|
/>
|
||||||
onClose={closeBackgroundOutput}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={permissionModalOpen()}>
|
<PermissionApprovalModal
|
||||||
<Suspense fallback={null}>
|
instanceId={props.instance.id}
|
||||||
<LazyPermissionApprovalModal
|
isOpen={permissionModalOpen()}
|
||||||
instanceId={props.instance.id}
|
onClose={() => setPermissionModalOpen(false)}
|
||||||
isOpen={permissionModalOpen()}
|
/>
|
||||||
onClose={() => setPermissionModalOpen(false)}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</Show>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,30 +2,10 @@ import { createEffect, createSignal, type Accessor } from "solid-js"
|
|||||||
import { messageStoreBus } from "../../../stores/message-v2/bus"
|
import { messageStoreBus } from "../../../stores/message-v2/bus"
|
||||||
import { clearSessionRenderCache } from "../../message-block"
|
import { clearSessionRenderCache } from "../../message-block"
|
||||||
import { getLogger } from "../../../lib/logger"
|
import { getLogger } from "../../../lib/logger"
|
||||||
import { runtimeEnv } from "../../../lib/runtime-env"
|
|
||||||
|
|
||||||
const log = getLogger("session")
|
const log = getLogger("session")
|
||||||
|
|
||||||
function getSessionCacheLimit() {
|
const SESSION_CACHE_LIMIT = 5
|
||||||
if (runtimeEnv.platform === "mobile") {
|
|
||||||
return 2
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtimeEnv.host === "tauri") {
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof navigator !== "undefined") {
|
|
||||||
const deviceMemory = (navigator as Navigator & { deviceMemory?: number }).deviceMemory
|
|
||||||
if (typeof deviceMemory === "number" && deviceMemory <= 4) {
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 5
|
|
||||||
}
|
|
||||||
|
|
||||||
const SESSION_CACHE_LIMIT = getSessionCacheLimit()
|
|
||||||
|
|
||||||
type SessionCacheOptions = {
|
type SessionCacheOptions = {
|
||||||
instanceId: Accessor<string>
|
instanceId: Accessor<string>
|
||||||
|
|||||||
@@ -131,15 +131,9 @@ export const SessionView: Component<SessionViewProps> = (props) => {
|
|||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const currentSession = session()
|
const currentSession = session()
|
||||||
if (!currentSession) {
|
if (currentSession) {
|
||||||
return
|
loadMessages(props.instanceId, currentSession.id).catch((error) => log.error("Failed to load messages", error))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.isActive === false) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMessages(props.instanceId, currentSession.id).catch((error) => log.error("Failed to load messages", error))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function registerPromptInputApi(api: PromptInputApi) {
|
function registerPromptInputApi(api: PromptInputApi) {
|
||||||
|
|||||||
Reference in New Issue
Block a user