fix(app): persist session tab info (#34934)
This commit is contained in:
parent
ae259d87f0
commit
64fd7a2027
3 changed files with 50 additions and 11 deletions
|
|
@ -246,18 +246,21 @@ export function TabNavItem(props: {
|
||||||
}}
|
}}
|
||||||
class="flex h-full min-w-0 flex-1 flex-row items-center gap-1.5 text-[13px] font-medium text-v2-text-text-faint group-data-[active='true']:text-v2-text-text-base group-data-[editing='true']:text-v2-text-text-base [-webkit-user-drag:none]"
|
class="flex h-full min-w-0 flex-1 flex-row items-center gap-1.5 text-[13px] font-medium text-v2-text-text-faint group-data-[active='true']:text-v2-text-text-base group-data-[editing='true']:text-v2-text-text-base [-webkit-user-drag:none]"
|
||||||
>
|
>
|
||||||
<Show when={props.session()}>
|
<span data-slot="project-avatar-slot" class="flex size-4 shrink-0 items-center justify-center">
|
||||||
{(session) => (
|
<Show
|
||||||
<span data-slot="project-avatar-slot">
|
when={props.session()}
|
||||||
|
fallback={<span class="block size-4 rounded-[3px] border border-v2-border-border-muted" aria-hidden="true" />}
|
||||||
|
>
|
||||||
|
{(session) => (
|
||||||
<SessionTabAvatar
|
<SessionTabAvatar
|
||||||
project={project()}
|
project={project()}
|
||||||
directory={session().directory}
|
directory={session().directory}
|
||||||
sessionId={session().id}
|
sessionId={session().id}
|
||||||
server={props.server}
|
server={props.server}
|
||||||
/>
|
/>
|
||||||
</span>
|
)}
|
||||||
)}
|
</Show>
|
||||||
</Show>
|
</span>
|
||||||
<span
|
<span
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
titleEl = el
|
titleEl = el
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ function SessionTabSlot(props: {
|
||||||
let ref!: HTMLDivElement
|
let ref!: HTMLDivElement
|
||||||
const sdk = createMemo(() => props.serverCtx()?.sdk ?? null)
|
const sdk = createMemo(() => props.serverCtx()?.sdk ?? null)
|
||||||
const cachedSession = createMemo(() => props.serverCtx()?.sync.session.peek(props.tab.sessionId))
|
const cachedSession = createMemo(() => props.serverCtx()?.sync.session.peek(props.tab.sessionId))
|
||||||
|
const persisted = createMemo(() => tabs.info[props.id])
|
||||||
const [loadedSession] = createResource(
|
const [loadedSession] = createResource(
|
||||||
() => {
|
() => {
|
||||||
const ctx = props.serverCtx()
|
const ctx = props.serverCtx()
|
||||||
|
|
@ -71,8 +72,10 @@ function SessionTabSlot(props: {
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
const value = session()
|
const value = session()
|
||||||
|
if (!value) return
|
||||||
|
tabs.rememberSessionInfo(props.tab, value)
|
||||||
const current = sdk()
|
const current = sdk()
|
||||||
if (!value || !current) return
|
if (!current) return
|
||||||
createTabPromptState(tabs, props.tab, current.scope, {
|
createTabPromptState(tabs, props.tab, current.scope, {
|
||||||
dir: base64Encode(value.directory),
|
dir: base64Encode(value.directory),
|
||||||
id: value.id,
|
id: value.id,
|
||||||
|
|
@ -86,7 +89,7 @@ function SessionTabSlot(props: {
|
||||||
data-tab-key={props.id}
|
data-tab-key={props.id}
|
||||||
data-active={props.active()}
|
data-active={props.active()}
|
||||||
class="relative flex w-56 min-w-7 max-w-56 flex-shrink"
|
class="relative flex w-56 min-w-7 max-w-56 flex-shrink"
|
||||||
classList={{ hidden: !session() && !missingSession() }}
|
classList={{ hidden: !session() && !missingSession() && !persisted()?.title }}
|
||||||
>
|
>
|
||||||
<TabNavItem
|
<TabNavItem
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
|
|
@ -95,7 +98,7 @@ function SessionTabSlot(props: {
|
||||||
href={tabHref(props.tab)}
|
href={tabHref(props.tab)}
|
||||||
server={props.tab.server}
|
server={props.tab.server}
|
||||||
session={session}
|
session={session}
|
||||||
fallbackTitle={missingSession() ? language.t("session.tab.unknown") : undefined}
|
fallbackTitle={persisted()?.title ?? (missingSession() ? language.t("session.tab.unknown") : undefined)}
|
||||||
onTitleChange={(title) => {
|
onTitleChange={(title) => {
|
||||||
const value = session()
|
const value = session()
|
||||||
const ctx = props.serverCtx()
|
const ctx = props.serverCtx()
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@ export type DraftTab = {
|
||||||
|
|
||||||
export type Tab = SessionTab | DraftTab
|
export type Tab = SessionTab | DraftTab
|
||||||
|
|
||||||
|
export type TabInfo = {
|
||||||
|
title?: string
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
|
||||||
type RecentTab = {
|
type RecentTab = {
|
||||||
key?: string
|
key?: string
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +69,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
createStore<Tab[]>([]),
|
createStore<Tab[]>([]),
|
||||||
)
|
)
|
||||||
const [recent, setRecent, , recentReady] = persisted(Persist.window("tabs.recent"), createStore<RecentTab>({}))
|
const [recent, setRecent, , recentReady] = persisted(Persist.window("tabs.recent"), createStore<RecentTab>({}))
|
||||||
|
const [info, setInfo] = persisted(Persist.window("tabs.info"), createStore<Record<string, TabInfo>>({}))
|
||||||
const [closed, setClosed, , closedReady] = persisted(Persist.window("tabs.closed"), createStore<ClosedTab[]>([]))
|
const [closed, setClosed, , closedReady] = persisted(Persist.window("tabs.closed"), createStore<ClosedTab[]>([]))
|
||||||
|
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
|
|
@ -102,6 +108,15 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
for (const key of draftPersistedKeys()) removePersisted(Persist.draft(draftID, key), platform)
|
for (const key of draftPersistedKeys()) removePersisted(Persist.draft(draftID, key), platform)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeInfo = (key: string) => {
|
||||||
|
if (!info[key]) return
|
||||||
|
setInfo(
|
||||||
|
produce((draft) => {
|
||||||
|
delete draft[key]
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
onCleanup(memory.dispose)
|
onCleanup(memory.dispose)
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -110,11 +125,19 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
const next = store.filter((tab) => servers.has(tab.server))
|
const next = store.filter((tab) => servers.has(tab.server))
|
||||||
if (next.length !== store.length) {
|
if (next.length !== store.length) {
|
||||||
for (const tab of store) {
|
for (const tab of store) {
|
||||||
if (!servers.has(tab.server)) memory.remove(tabKey(tab))
|
if (!servers.has(tab.server)) {
|
||||||
|
const key = tabKey(tab)
|
||||||
|
memory.remove(key)
|
||||||
|
removeInfo(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setStore(() => next)
|
setStore(() => next)
|
||||||
}
|
}
|
||||||
if (recent.key && !next.some((tab) => tabKey(tab) === recent.key)) setRecentKey(undefined)
|
if (recent.key && !next.some((tab) => tabKey(tab) === recent.key)) setRecentKey(undefined)
|
||||||
|
const keys = new Set(next.map(tabKey))
|
||||||
|
for (const key of Object.keys(info)) {
|
||||||
|
if (!keys.has(key)) removeInfo(key)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -150,6 +173,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
if (nextTab) navigateTab(nextTab)
|
if (nextTab) navigateTab(nextTab)
|
||||||
}).finally(() => closing.delete(key))
|
}).finally(() => closing.delete(key))
|
||||||
memory.remove(key)
|
memory.remove(key)
|
||||||
|
removeInfo(key)
|
||||||
if (draftID) removeDraftPersisted(draftID)
|
if (draftID) removeDraftPersisted(draftID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,6 +288,7 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
const removed = store.filter((tab) => tab.server === key).map(tabKey)
|
const removed = store.filter((tab) => tab.server === key).map(tabKey)
|
||||||
setStore((tabs) => tabs.filter((tab) => tab.server !== key))
|
setStore((tabs) => tabs.filter((tab) => tab.server !== key))
|
||||||
for (const key of removed) memory.remove(key)
|
for (const key of removed) memory.remove(key)
|
||||||
|
for (const key of removed) removeInfo(key)
|
||||||
if (recent.key && removed.includes(recent.key)) setRecentKey(undefined)
|
if (recent.key && removed.includes(recent.key)) setRecentKey(undefined)
|
||||||
for (const draftID of drafts) removeDraftPersisted(draftID)
|
for (const draftID of drafts) removeDraftPersisted(draftID)
|
||||||
if (server.key === key) navigate("/")
|
if (server.key === key) navigate("/")
|
||||||
|
|
@ -318,6 +343,14 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
if (recent.key && removed.includes(recent.key)) setRecentKey(undefined)
|
if (recent.key && removed.includes(recent.key)) setRecentKey(undefined)
|
||||||
})
|
})
|
||||||
for (const key of removed) memory.remove(key)
|
for (const key of removed) memory.remove(key)
|
||||||
|
for (const key of removed) removeInfo(key)
|
||||||
|
},
|
||||||
|
rememberSessionInfo(tab: SessionTab, session: Session) {
|
||||||
|
const key = tabKey(tab)
|
||||||
|
const next = { title: session.title, directory: session.directory }
|
||||||
|
const current = info[key]
|
||||||
|
if (current?.title === next.title && current.directory === next.directory) return
|
||||||
|
setInfo(key, next)
|
||||||
},
|
},
|
||||||
select: navigateTab,
|
select: navigateTab,
|
||||||
remember(tab: Tab) {
|
remember(tab: Tab) {
|
||||||
|
|
@ -342,6 +375,6 @@ export const { use: useTabs, provider: TabsProvider } = createSimpleContext({
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...actions, store, ready, recentReady }
|
return { ...actions, store, info, ready, recentReady }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue