Skip to content

Commit 02416fa

Browse files
wangzexiZexi
authored andcommitted
fix: keep opened project metadata single-sourced
refactor(desktop): store local server config in electron store fix: restore remote desktop session handling on upstream dev
1 parent 6420f61 commit 02416fa

32 files changed

Lines changed: 356 additions & 190 deletions

File tree

packages/app/src/app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ function ConnectionError(props: { onRetry?: () => void; onServerSelected?: (key:
287287
function ServerKey(props: ParentProps) {
288288
const server = useServer()
289289
return (
290-
<Show when={server.key} keyed>
290+
<Show when={server.connectionKey} keyed>
291291
{props.children}
292292
</Show>
293293
)

packages/app/src/components/dialog-select-file.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { useLanguage } from "@/context/language"
1717
import { useSessionLayout } from "@/pages/session/session-layout"
1818
import { createSessionTabs } from "@/pages/session/helpers"
1919
import { decode64 } from "@/utils/base64"
20+
import { sessionListItems } from "@/utils/session-list"
2021
import { getRelativeTime } from "@/utils/time"
2122

2223
type EntryType = "command" | "file" | "session"
@@ -210,7 +211,7 @@ function createSessionEntries(props: {
210211
return props.globalSDK.client.session
211212
.list({ directory, roots: true })
212213
.then((x) =>
213-
(x.data ?? [])
214+
sessionListItems(x.data)
214215
.filter((s) => !!s?.id)
215216
.map((s) => ({
216217
id: s.id,

packages/app/src/components/dialog-select-server.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { createEffect, createMemo, createResource, createSignal, onCleanup, Show
1414
import { createStore, reconcile } from "solid-js/store"
1515
import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row"
1616
import { useLanguage } from "@/context/language"
17-
import { type InboundServerConfig, usePlatform } from "@/context/platform"
17+
import { type LocalServerConfig, usePlatform } from "@/context/platform"
1818
import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
1919
import { type ServerHealth, useCheckServerHealth } from "@/utils/server-health"
2020

@@ -275,8 +275,8 @@ export function DialogSelectServer() {
275275
const { defaultKey, canDefault, setDefault } = useDefaultServer()
276276
const { previewStatus } = useServerPreview()
277277
const checkServerHealth = useCheckServerHealth()
278-
const [inboundConfig] = createResource(() => platform.getInboundServerConfig?.())
279-
const [savedInboundConfig, setSavedInboundConfig] = createSignal<InboundServerConfig>()
278+
const [localServerConfig] = createResource(() => platform.getLocalServerConfig?.())
279+
const [savedLocalServerConfig, setSavedLocalServerConfig] = createSignal<LocalServerConfig>()
280280
const [store, setStore] = createStore({
281281
status: {} as Record<ServerConnection.Key, ServerHealth | undefined>,
282282
addServer: {
@@ -432,10 +432,10 @@ export function DialogSelectServer() {
432432

433433
const current = createMemo(() => items().find((x) => ServerConnection.key(x) === server.key) ?? items()[0])
434434
const canEditInbound = createMemo(
435-
() => !!platform.getInboundServerConfig && !!platform.setInboundServerConfig && server.list.some((item) => item.type === "sidecar"),
435+
() => !!platform.getLocalServerConfig && !!platform.setLocalServerConfig && server.list.some((item) => item.type === "sidecar"),
436436
)
437437
const localServerDetails = createMemo(() => {
438-
const config = platform.inboundRuntimeServerConfig?.()
438+
const config = platform.localServerRuntimeConfig?.()
439439
if (!config?.enabled || config.port === null) return
440440
return {
441441
name: "Local Server",
@@ -598,7 +598,7 @@ export function DialogSelectServer() {
598598
status: store.status[ServerConnection.key(conn)]?.healthy,
599599
})
600600
}
601-
const syncInboundForm = (config: InboundServerConfig) => {
601+
const syncInboundForm = (config: LocalServerConfig) => {
602602
setStore("inboundServer", {
603603
open: true,
604604
enabled: config.enabled,
@@ -613,7 +613,7 @@ export function DialogSelectServer() {
613613
const startInboundEdit = () => {
614614
resetAdd()
615615
resetEdit()
616-
const config = savedInboundConfig() ?? inboundConfig.latest
616+
const config = savedLocalServerConfig() ?? localServerConfig.latest
617617
if (config) {
618618
syncInboundForm(config)
619619
return
@@ -644,7 +644,7 @@ export function DialogSelectServer() {
644644
})
645645
}
646646
const saveInboundConfig = async () => {
647-
if (!platform.setInboundServerConfig) return
647+
if (!platform.setLocalServerConfig) return
648648

649649
const port = parseInboundPort(store.inboundServer.port)
650650
if (store.inboundServer.enabled && port === null) {
@@ -664,7 +664,7 @@ export function DialogSelectServer() {
664664
password: store.inboundServer.password.trim(),
665665
port: port ?? null,
666666
}
667-
const current = savedInboundConfig() ?? inboundConfig.latest
667+
const current = savedLocalServerConfig() ?? localServerConfig.latest
668668
const changed =
669669
!current ||
670670
current.enabled !== next.enabled ||
@@ -679,8 +679,8 @@ export function DialogSelectServer() {
679679

680680
setStore("inboundServer", "saving", true)
681681
try {
682-
await platform.setInboundServerConfig(next)
683-
setSavedInboundConfig(next)
682+
await platform.setLocalServerConfig(next)
683+
setSavedLocalServerConfig(next)
684684
showToast({
685685
variant: "success",
686686
icon: "circle-check",
@@ -745,7 +745,7 @@ export function DialogSelectServer() {
745745
})
746746
createEffect(() => {
747747
if (!store.inboundServer.open || store.inboundServer.hydrated) return
748-
const config = savedInboundConfig() ?? inboundConfig()
748+
const config = savedLocalServerConfig() ?? localServerConfig()
749749
if (!config) return
750750
syncInboundForm(config)
751751
})
@@ -791,7 +791,7 @@ export function DialogSelectServer() {
791791
port={store.inboundServer.port}
792792
portError={store.inboundServer.portError}
793793
busy={store.inboundServer.saving}
794-
loading={inboundConfig.state === "pending"}
794+
loading={localServerConfig.state === "pending"}
795795
onEnabledChange={setInboundEnabled}
796796
onUsernameChange={(value) => setStore("inboundServer", "username", value)}
797797
onPasswordChange={(value) => setStore("inboundServer", "password", value)}

packages/app/src/context/global-sync.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,40 @@ describe("loadRootSessionsWithFallback", () => {
6161
{ directory: "dir", roots: true },
6262
])
6363
})
64+
65+
test("normalizes v2 session list responses", async () => {
66+
const result = await loadRootSessionsWithFallback({
67+
directory: "dir",
68+
limit: 10,
69+
list: async () => ({
70+
data: {
71+
items: [
72+
{
73+
id: "ses_1",
74+
slug: "ses-1",
75+
projectID: "proj_1",
76+
directory: "/tmp/project",
77+
title: "Session",
78+
version: "1",
79+
time: { created: 1, updated: 1 },
80+
},
81+
],
82+
},
83+
}),
84+
})
85+
86+
expect(result.data).toEqual([
87+
{
88+
id: "ses_1",
89+
slug: "ses-1",
90+
projectID: "proj_1",
91+
directory: "/tmp/project",
92+
title: "Session",
93+
version: "1",
94+
time: { created: 1, updated: 1 },
95+
},
96+
])
97+
})
6498
})
6599

66100
describe("estimateRootSessionTotal", () => {

packages/app/src/context/global-sync.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { trimSessions } from "./global-sync/session-trim"
3232
import type { ProjectMeta } from "./global-sync/types"
3333
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
3434
import { formatServerError } from "@/utils/server-errors"
35+
import { sessionListItems } from "@/utils/session-list"
3536
import { queryOptions, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
3637
import { createRefreshQueue } from "./global-sync/queue"
3738
import { directoryKey } from "./global-sync/utils"
@@ -257,7 +258,7 @@ function createGlobalSync() {
257258
list: (query) => globalSDK.client.session.list(query),
258259
})
259260
.then((x) => {
260-
const nonArchived = (x.data ?? [])
261+
const nonArchived = sessionListItems(x.data)
261262
.filter((s) => !!s?.id)
262263
.filter((s) => !s.time?.archived)
263264
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))

packages/app/src/context/global-sync/session-load.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import type { RootLoadArgs } from "./types"
2+
import { sessionListItems } from "@/utils/session-list"
23

34
export async function loadRootSessionsWithFallback(input: RootLoadArgs) {
45
try {
56
const result = await input.list({ directory: input.directory, roots: true, limit: input.limit })
67
return {
7-
data: result.data,
8+
data: sessionListItems(result.data),
89
limit: input.limit,
910
limited: true,
1011
} as const
1112
} catch {
1213
const result = await input.list({ directory: input.directory, roots: true })
1314
return {
14-
data: result.data,
15+
data: sessionListItems(result.data),
1516
limit: input.limit,
1617
limited: false,
1718
} as const

packages/app/src/context/global-sync/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export type DisposeCheck = {
124124
export type RootLoadArgs = {
125125
directory: string
126126
limit: number
127-
list: (query: { directory: string; roots: true; limit?: number }) => Promise<{ data?: Session[] }>
127+
list: (query: { directory: string; roots: true; limit?: number }) => Promise<{ data?: Session[] | { items?: Session[] } }>
128128
}
129129

130130
export type RootLoadResult = {

packages/app/src/context/opened-projects.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export type ConfigProjectEntry = {
1515
icon?: {
1616
color?: string
1717
override?: string
18-
emoji?: string
1918
}
2019
commands?: {
2120
start?: string
@@ -53,7 +52,7 @@ export const { use: useOpenedProjects, provider: OpenedProjectsProvider } = crea
5352
})
5453
}
5554

56-
const queryKey = createMemo(() => ["opened-projects", server.key] as const)
55+
const queryKey = createMemo(() => ["opened-projects", server.connectionKey] as const)
5756

5857
const query = createQuery(() => ({
5958
queryKey: queryKey(),

packages/app/src/context/platform.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type OpenDirectoryPickerOptions = { title?: string; multiple?: boolean }
88
type OpenFilePickerOptions = { title?: string; multiple?: boolean; accept?: string[]; extensions?: string[] }
99
type SaveFilePickerOptions = { title?: string; defaultPath?: string }
1010
type UpdateInfo = { updateAvailable: boolean; version?: string }
11-
export type InboundServerConfig = {
11+
export type LocalServerConfig = {
1212
enabled: boolean
1313
username: string
1414
password: string
@@ -82,17 +82,14 @@ export type Platform = {
8282
/** Set the preferred display backend (desktop only) */
8383
setDisplayBackend?(backend: DisplayBackend): Promise<void>
8484

85-
/** Get inbound sidecar config (desktop only) */
86-
getInboundServerConfig?(): Promise<InboundServerConfig>
85+
/** Get local server config (desktop only) */
86+
getLocalServerConfig?(): Promise<LocalServerConfig>
8787

88-
/** Get the inbound config currently used by the running sidecar (desktop only) */
89-
getInboundRuntimeServerConfig?(): Promise<InboundServerConfig>
88+
/** The local server config currently used by the running sidecar (desktop only) */
89+
localServerRuntimeConfig?: Accessor<LocalServerConfig | undefined>
9090

91-
/** The inbound config currently used by the running sidecar (desktop only) */
92-
inboundRuntimeServerConfig?: Accessor<InboundServerConfig | undefined>
93-
94-
/** Set inbound sidecar config (desktop only) */
95-
setInboundServerConfig?(config: InboundServerConfig): Promise<void>
91+
/** Set local server config (desktop only) */
92+
setLocalServerConfig?(config: LocalServerConfig): Promise<void>
9693

9794
/** Parse markdown to HTML using native parser (desktop only, returns unprocessed code blocks) */
9895
parseMarkdown?(markdown: string): Promise<string>

packages/app/src/context/server.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
205205
const current: Accessor<ServerConnection.Any | undefined> = createMemo(
206206
() => allServers().find((s) => ServerConnection.key(s) === state.active) ?? allServers()[0],
207207
)
208+
const connectionKey = createMemo(() => {
209+
const conn = current()
210+
if (!conn) return state.active
211+
return [ServerConnection.key(conn), conn.http.url, conn.http.username ?? "", conn.http.password ?? ""].join("\0")
212+
})
208213

209214
createEffect(() => {
210215
const current_ = current()
@@ -230,6 +235,9 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
230235
get key() {
231236
return state.active
232237
},
238+
get connectionKey() {
239+
return connectionKey()
240+
},
233241
get name() {
234242
return serverName(current())
235243
},

0 commit comments

Comments
 (0)