app: better loading (#23489)
This commit is contained in:
parent
84e322b0fd
commit
687b758882
@ -1,6 +1,6 @@
|
|||||||
import { useFilteredList } from "@opencode-ai/ui/hooks"
|
import { useFilteredList } from "@opencode-ai/ui/hooks"
|
||||||
import { useSpring } from "@opencode-ai/ui/motion-spring"
|
import { useSpring } from "@opencode-ai/ui/motion-spring"
|
||||||
import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal } from "solid-js"
|
import { createEffect, on, Component, Show, onCleanup, createMemo, createSignal, createResource } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { useLocal } from "@/context/local"
|
import { useLocal } from "@/context/local"
|
||||||
import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file"
|
import { selectionFromLines, type SelectedLineRange, useFile } from "@/context/file"
|
||||||
@ -54,7 +54,7 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments"
|
|||||||
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
|
import { PromptDragOverlay } from "./prompt-input/drag-overlay"
|
||||||
import { promptPlaceholder } from "./prompt-input/placeholder"
|
import { promptPlaceholder } from "./prompt-input/placeholder"
|
||||||
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
import { ImagePreview } from "@opencode-ai/ui/image-preview"
|
||||||
import { useQuery } from "@tanstack/solid-query"
|
import { useQueries, useQuery } from "@tanstack/solid-query"
|
||||||
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
|
import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap"
|
||||||
|
|
||||||
interface PromptInputProps {
|
interface PromptInputProps {
|
||||||
@ -1252,16 +1252,21 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory))
|
const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({
|
||||||
|
queries: [loadAgentsQuery(sdk.directory), loadProvidersQuery(null), loadProvidersQuery(sdk.directory)],
|
||||||
|
}))
|
||||||
|
|
||||||
const agentsLoading = () => agentsQuery.isLoading
|
const agentsLoading = () => agentsQuery.isLoading
|
||||||
|
|
||||||
const globalProvidersQuery = useQuery(() => loadProvidersQuery(null))
|
|
||||||
const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory))
|
|
||||||
|
|
||||||
const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
|
const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading
|
||||||
|
|
||||||
|
const [promptReady] = createResource(
|
||||||
|
() => prompt.ready().promise,
|
||||||
|
(p) => p,
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
|
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
|
||||||
|
{(promptReady(), null)}
|
||||||
<PromptPopover
|
<PromptPopover
|
||||||
popover={store.popover}
|
popover={store.popover}
|
||||||
setSlashPopoverRef={(el) => (slashPopoverRef = el)}
|
setSlashPopoverRef={(el) => (slashPopoverRef = el)}
|
||||||
@ -1358,15 +1363,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
}}
|
}}
|
||||||
style={{ "padding-bottom": space }}
|
style={{ "padding-bottom": space }}
|
||||||
/>
|
/>
|
||||||
<Show when={!prompt.dirty()}>
|
<div
|
||||||
<div
|
class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"
|
||||||
class="absolute top-0 inset-x-0 pl-3 pr-2 pt-2 text-14-regular text-text-weak pointer-events-none whitespace-nowrap truncate"
|
classList={{ "font-mono!": store.mode === "shell" }}
|
||||||
classList={{ "font-mono!": store.mode === "shell" }}
|
style={{ "padding-bottom": space, display: prompt.dirty() ? "none" : undefined }}
|
||||||
style={{ "padding-bottom": space }}
|
>
|
||||||
>
|
{placeholder()}
|
||||||
{placeholder()}
|
</div>
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -1457,7 +1460,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
|
<div class="flex items-center gap-1.5 min-w-0 flex-1 h-7">
|
||||||
<Show when={!agentsLoading()}>
|
<Show when={!agentsLoading()}>
|
||||||
<div data-component="prompt-agent-control">
|
<div data-component="prompt-agent-control" style={{ animation: "fade-in 0.3s" }}>
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
placement="top"
|
placement="top"
|
||||||
gutter={4}
|
gutter={4}
|
||||||
@ -1483,7 +1486,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
</Show>
|
</Show>
|
||||||
<Show when={!providersLoading()}>
|
<Show when={!providersLoading()}>
|
||||||
<Show when={store.mode !== "shell"}>
|
<Show when={store.mode !== "shell"}>
|
||||||
<div data-component="prompt-model-control">
|
<div data-component="prompt-model-control" style={{ animation: "fade-in 0.3s" }}>
|
||||||
<Show
|
<Show
|
||||||
when={providers.paid().length > 0}
|
when={providers.paid().length > 0}
|
||||||
fallback={
|
fallback={
|
||||||
@ -1554,7 +1557,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
</TooltipKeybind>
|
</TooltipKeybind>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<div data-component="prompt-variant-control">
|
<div data-component="prompt-variant-control" style={{ animation: "fade-in 0.3s" }}>
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
placement="top"
|
placement="top"
|
||||||
gutter={4}
|
gutter={4}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import type {
|
|||||||
} from "@opencode-ai/sdk/v2/client"
|
} from "@opencode-ai/sdk/v2/client"
|
||||||
import { showToast } from "@opencode-ai/ui/toast"
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||||
import { createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
|
import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
|
||||||
import { createStore, produce, reconcile } from "solid-js/store"
|
import { createStore, produce, reconcile } from "solid-js/store"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { Persist, persisted } from "@/utils/persist"
|
import { Persist, persisted } from "@/utils/persist"
|
||||||
@ -223,16 +223,18 @@ function createGlobalSync() {
|
|||||||
limit,
|
limit,
|
||||||
permission: store.permission,
|
permission: store.permission,
|
||||||
})
|
})
|
||||||
setStore(
|
batch(() => {
|
||||||
"sessionTotal",
|
setStore(
|
||||||
estimateRootSessionTotal({
|
"sessionTotal",
|
||||||
count: nonArchived.length,
|
estimateRootSessionTotal({
|
||||||
limit: x.limit,
|
count: nonArchived.length,
|
||||||
limited: x.limited,
|
limit: x.limit,
|
||||||
}),
|
limited: x.limited,
|
||||||
)
|
}),
|
||||||
setStore("session", reconcile(sessions, { key: "id" }))
|
)
|
||||||
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
setStore("session", reconcile(sessions, { key: "id" }))
|
||||||
|
cleanupDroppedSessionCaches(store, setStore, sessions, setSessionTodo)
|
||||||
|
})
|
||||||
sessionMeta.set(directory, { limit })
|
sessionMeta.set(directory, { limit })
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import type { State, VcsCache } from "./types"
|
|||||||
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
|
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
|
||||||
import { formatServerError } from "@/utils/server-errors"
|
import { formatServerError } from "@/utils/server-errors"
|
||||||
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
|
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
|
||||||
import { loadSessionsQuery } from "../global-sync"
|
|
||||||
|
|
||||||
type GlobalStore = {
|
type GlobalStore = {
|
||||||
ready: boolean
|
ready: boolean
|
||||||
@ -82,6 +81,9 @@ export async function bootstrapGlobal(input: {
|
|||||||
input.setGlobalStore("config", x.data!)
|
input.setGlobalStore("config", x.data!)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
const slow = [
|
||||||
() =>
|
() =>
|
||||||
input.queryClient.fetchQuery({
|
input.queryClient.fetchQuery({
|
||||||
...loadProvidersQuery(null),
|
...loadProvidersQuery(null),
|
||||||
@ -93,9 +95,6 @@ export async function bootstrapGlobal(input: {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
]
|
|
||||||
|
|
||||||
const slow = [
|
|
||||||
() =>
|
() =>
|
||||||
retry(() =>
|
retry(() =>
|
||||||
input.globalSDK.path.get().then((x) => {
|
input.globalSDK.path.get().then((x) => {
|
||||||
@ -183,8 +182,43 @@ function warmSessions(input: {
|
|||||||
export const loadProvidersQuery = (directory: string | null) =>
|
export const loadProvidersQuery = (directory: string | null) =>
|
||||||
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
|
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
|
||||||
|
|
||||||
export const loadAgentsQuery = (directory: string | null) =>
|
export const loadAgentsQuery = (
|
||||||
queryOptions<null>({ queryKey: [directory, "agents"], queryFn: skipToken })
|
directory: string | null,
|
||||||
|
sdk?: OpencodeClient,
|
||||||
|
transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
|
||||||
|
) =>
|
||||||
|
queryOptions<null>({
|
||||||
|
queryKey: [directory, "agents"],
|
||||||
|
queryFn:
|
||||||
|
sdk && transform
|
||||||
|
? () =>
|
||||||
|
retry(() =>
|
||||||
|
sdk.app
|
||||||
|
.agents()
|
||||||
|
.then(transform)
|
||||||
|
.then(() => null),
|
||||||
|
)
|
||||||
|
: skipToken,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const loadPathQuery = (
|
||||||
|
directory: string | null,
|
||||||
|
sdk?: OpencodeClient,
|
||||||
|
transform?: (x: Awaited<ReturnType<OpencodeClient["path"]["get"]>>) => void,
|
||||||
|
) =>
|
||||||
|
queryOptions<Path>({
|
||||||
|
queryKey: [directory, "path"],
|
||||||
|
queryFn:
|
||||||
|
sdk && transform
|
||||||
|
? () =>
|
||||||
|
retry(() =>
|
||||||
|
sdk.path.get().then(async (x) => {
|
||||||
|
transform(x)
|
||||||
|
return x.data!
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: skipToken,
|
||||||
|
})
|
||||||
|
|
||||||
export async function bootstrapDirectory(input: {
|
export async function bootstrapDirectory(input: {
|
||||||
directory: string
|
directory: string
|
||||||
@ -222,45 +256,27 @@ export async function bootstrapDirectory(input: {
|
|||||||
input.setStore("lsp", [])
|
input.setStore("lsp", [])
|
||||||
if (loading) input.setStore("status", "partial")
|
if (loading) input.setStore("status", "partial")
|
||||||
|
|
||||||
const fast = [() => Promise.resolve(input.loadSessions(input.directory))]
|
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
||||||
|
providerRev.set(input.directory, rev)
|
||||||
const errs = errors(await runAll(fast))
|
|
||||||
if (errs.length > 0) {
|
|
||||||
console.error("Failed to bootstrap instance", errs[0])
|
|
||||||
const project = getFilename(input.directory)
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
|
||||||
description: formatServerError(errs[0], input.translate),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
const slow = [
|
const slow = [
|
||||||
|
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||||
() =>
|
() =>
|
||||||
input.queryClient.ensureQueryData({
|
input.queryClient.ensureQueryData(
|
||||||
...loadAgentsQuery(input.directory),
|
loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))),
|
||||||
queryFn: () =>
|
),
|
||||||
retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))).then(
|
|
||||||
() => null,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
|
||||||
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
|
||||||
() =>
|
!seededProject &&
|
||||||
seededProject
|
(() => retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id))),
|
||||||
? Promise.resolve()
|
!seededPath &&
|
||||||
: retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
|
(() =>
|
||||||
() =>
|
input.queryClient.ensureQueryData(
|
||||||
seededPath
|
loadPathQuery(input.directory, input.sdk, (x) => {
|
||||||
? Promise.resolve()
|
const next = projectID(x.data?.directory ?? input.directory, input.global.project)
|
||||||
: retry(() =>
|
if (next) input.setStore("project", next)
|
||||||
input.sdk.path.get().then((x) => {
|
}),
|
||||||
input.setStore("path", x.data!)
|
)),
|
||||||
const next = projectID(x.data?.directory ?? input.directory, input.global.project)
|
|
||||||
if (next) input.setStore("project", next)
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
() =>
|
() =>
|
||||||
retry(() =>
|
retry(() =>
|
||||||
input.sdk.vcs.get().then((x) => {
|
input.sdk.vcs.get().then((x) => {
|
||||||
@ -330,7 +346,28 @@ export async function bootstrapDirectory(input: {
|
|||||||
input.setStore("mcp_ready", true)
|
input.setStore("mcp_ready", true)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
]
|
() =>
|
||||||
|
input.queryClient.ensureQueryData({
|
||||||
|
...loadProvidersQuery(input.directory),
|
||||||
|
queryFn: () =>
|
||||||
|
retry(() => input.sdk.provider.list())
|
||||||
|
.then((x) => {
|
||||||
|
if (providerRev.get(input.directory) !== rev) return
|
||||||
|
input.setStore("provider", normalizeProviderList(x.data!))
|
||||||
|
input.setStore("provider_ready", true)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
|
||||||
|
const project = getFilename(input.directory)
|
||||||
|
showToast({
|
||||||
|
variant: "error",
|
||||||
|
title: input.translate("toast.project.reloadFailed.title", { project }),
|
||||||
|
description: formatServerError(err, input.translate),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(() => null),
|
||||||
|
}),
|
||||||
|
].filter(Boolean) as (() => Promise<any>)[]
|
||||||
|
|
||||||
await waitForPaint()
|
await waitForPaint()
|
||||||
const slowErrs = errors(await runAll(slow))
|
const slowErrs = errors(await runAll(slow))
|
||||||
@ -344,29 +381,6 @@ export async function bootstrapDirectory(input: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete")
|
if (loading && slowErrs.length === 0) input.setStore("status", "complete")
|
||||||
|
|
||||||
const rev = (providerRev.get(input.directory) ?? 0) + 1
|
|
||||||
providerRev.set(input.directory, rev)
|
|
||||||
void input.queryClient.ensureQueryData({
|
|
||||||
...loadSessionsQuery(input.directory),
|
|
||||||
queryFn: () =>
|
|
||||||
retry(() => input.sdk.provider.list())
|
|
||||||
.then((x) => {
|
|
||||||
if (providerRev.get(input.directory) !== rev) return
|
|
||||||
input.setStore("provider", normalizeProviderList(x.data!))
|
|
||||||
input.setStore("provider_ready", true)
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
|
|
||||||
const project = getFilename(input.directory)
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: input.translate("toast.project.reloadFailed.title", { project }),
|
|
||||||
description: formatServerError(err, input.translate),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(() => null),
|
|
||||||
})
|
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import {
|
|||||||
type VcsCache,
|
type VcsCache,
|
||||||
} from "./types"
|
} from "./types"
|
||||||
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
|
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
|
||||||
|
import { useQuery } from "@tanstack/solid-query"
|
||||||
|
import { loadPathQuery } from "./bootstrap"
|
||||||
|
|
||||||
export function createChildStoreManager(input: {
|
export function createChildStoreManager(input: {
|
||||||
owner: Owner
|
owner: Owner
|
||||||
@ -156,6 +158,8 @@ export function createChildStoreManager(input: {
|
|||||||
createRoot((dispose) => {
|
createRoot((dispose) => {
|
||||||
const initialMeta = meta[0].value
|
const initialMeta = meta[0].value
|
||||||
const initialIcon = icon[0].value
|
const initialIcon = icon[0].value
|
||||||
|
|
||||||
|
const pathQuery = useQuery(() => loadPathQuery(directory))
|
||||||
const child = createStore<State>({
|
const child = createStore<State>({
|
||||||
project: "",
|
project: "",
|
||||||
projectMeta: initialMeta,
|
projectMeta: initialMeta,
|
||||||
@ -163,7 +167,11 @@ export function createChildStoreManager(input: {
|
|||||||
provider_ready: false,
|
provider_ready: false,
|
||||||
provider: { all: [], connected: [], default: {} },
|
provider: { all: [], connected: [], default: {} },
|
||||||
config: {},
|
config: {},
|
||||||
path: { state: "", config: "", worktree: "", directory: "", home: "" },
|
get path() {
|
||||||
|
if (pathQuery.isLoading || !pathQuery.data)
|
||||||
|
return { state: "", config: "", worktree: "", directory: "", home: "" }
|
||||||
|
return pathQuery.data
|
||||||
|
},
|
||||||
status: "loading" as const,
|
status: "loading" as const,
|
||||||
agent: [],
|
agent: [],
|
||||||
command: [],
|
command: [],
|
||||||
|
|||||||
@ -185,9 +185,9 @@ function createPromptSession(dir: string, id: string | undefined) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
ready,
|
ready,
|
||||||
current: createMemo(() => store.prompt),
|
current: () => store.prompt,
|
||||||
cursor: createMemo(() => store.cursor),
|
cursor: createMemo(() => store.cursor),
|
||||||
dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)),
|
dirty: () => !isPromptEqual(store.prompt, DEFAULT_PROMPT),
|
||||||
context: {
|
context: {
|
||||||
items: createMemo(() => store.context.items),
|
items: createMemo(() => store.context.items),
|
||||||
add(item: ContextItem) {
|
add(item: ContextItem) {
|
||||||
@ -277,7 +277,7 @@ export const { use: usePrompt, provider: PromptProvider } = createSimpleContext(
|
|||||||
const pick = (scope?: Scope) => (scope ? load(scope.dir, scope.id) : session())
|
const pick = (scope?: Scope) => (scope ? load(scope.dir, scope.id) : session())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ready: () => session().ready(),
|
ready: () => session().ready,
|
||||||
current: () => session().current(),
|
current: () => session().current(),
|
||||||
cursor: () => session().cursor(),
|
cursor: () => session().cursor(),
|
||||||
dirty: () => session().dirty(),
|
dirty: () => session().dirty(),
|
||||||
|
|||||||
@ -73,4 +73,13 @@
|
|||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { DataProvider } from "@opencode-ai/ui/context"
|
|||||||
import { showToast } from "@opencode-ai/ui/toast"
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
import { base64Encode } from "@opencode-ai/shared/util/encode"
|
import { base64Encode } from "@opencode-ai/shared/util/encode"
|
||||||
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
import { useLocation, useNavigate, useParams } from "@solidjs/router"
|
||||||
import { createEffect, createMemo, type ParentProps, Show } from "solid-js"
|
import { createEffect, createMemo, createResource, type ParentProps, Show } from "solid-js"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { LocalProvider } from "@/context/local"
|
import { LocalProvider } from "@/context/local"
|
||||||
import { SDKProvider } from "@/context/sdk"
|
import { SDKProvider } from "@/context/sdk"
|
||||||
@ -23,11 +23,10 @@ function DirectoryDataProvider(props: ParentProps<{ directory: string }>) {
|
|||||||
navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true })
|
navigate(`/${base64Encode(next)}${path}${location.search}${location.hash}`, { replace: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createResource(
|
||||||
const id = params.id
|
() => params.id,
|
||||||
if (!id) return
|
(id) => sync.session.sync(id),
|
||||||
void sync.session.sync(id)
|
)
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataProvider
|
<DataProvider
|
||||||
|
|||||||
@ -31,7 +31,7 @@ function sortSessions(now: number) {
|
|||||||
const isRootVisibleSession = (session: Session, directory: string) =>
|
const isRootVisibleSession = (session: Session, directory: string) =>
|
||||||
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
|
workspaceKey(session.directory) === workspaceKey(directory) && !session.parentID && !session.time?.archived
|
||||||
|
|
||||||
const roots = (store: SessionStore) =>
|
export const roots = (store: SessionStore) =>
|
||||||
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
||||||
|
|
||||||
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
|
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
|
||||||
|
|||||||
@ -321,7 +321,7 @@ export const SortableWorkspace = (props: {
|
|||||||
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
const hasMore = createMemo(() => workspaceStore.sessionTotal > count())
|
||||||
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) }))
|
||||||
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
const busy = createMemo(() => props.ctx.isBusy(props.directory))
|
||||||
const loading = () => query.isLoading
|
const loading = () => query.isLoading && count() === 0
|
||||||
const touch = createMediaQuery("(hover: none)")
|
const touch = createMediaQuery("(hover: none)")
|
||||||
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user