|
|
@@ -1,11 +1,9 @@
|
|
|
-import { type ComponentProps, createMemo, For, Match, Show, Switch } from "solid-js"
|
|
|
+import { type ComponentProps, createMemo, For, Show } from "solid-js"
|
|
|
import { DragDropProvider, PointerSensor } from "@dnd-kit/solid"
|
|
|
import { isSortable, useSortable } from "@dnd-kit/solid/sortable"
|
|
|
import { AutoScroller, Feedback, PointerActivationConstraints } from "@dnd-kit/dom"
|
|
|
import { RestrictToVerticalAxis } from "@dnd-kit/abstract/modifiers"
|
|
|
import { RestrictToElement } from "@dnd-kit/dom/modifiers"
|
|
|
-import { Button } from "@opencode-ai/ui/button"
|
|
|
-import { Logo } from "@opencode-ai/ui/logo"
|
|
|
import { Spinner } from "@opencode-ai/ui/spinner"
|
|
|
import { ScrollView } from "@opencode-ai/ui/scroll-view"
|
|
|
import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2"
|
|
|
@@ -15,20 +13,11 @@ import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
|
|
|
import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2"
|
|
|
import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
|
|
|
import { getProjectAvatarVariant, type LocalProject } from "@/context/layout"
|
|
|
-import { useNavigate } from "@solidjs/router"
|
|
|
-import { base64Encode } from "@opencode-ai/core/util/encode"
|
|
|
-import { Icon } from "@opencode-ai/ui/icon"
|
|
|
-import { DateTime } from "luxon"
|
|
|
-import { useDialog } from "@opencode-ai/ui/context/dialog"
|
|
|
-import { useDirectoryPicker } from "@/components/directory-picker"
|
|
|
-import { DialogSelectServer } from "@/components/dialog-select-server"
|
|
|
-import { ServerConnection, useServer } from "@/context/server"
|
|
|
-import { useServerSync } from "@/context/server-sync"
|
|
|
+import { ServerConnection } from "@/context/server"
|
|
|
import { useLanguage } from "@/context/language"
|
|
|
import { displayName, getProjectAvatarSource } from "@/pages/layout/helpers"
|
|
|
import { SessionTabAvatarView } from "@/pages/layout/session-tab-avatar"
|
|
|
import { sessionTitle } from "@/utils/session-title"
|
|
|
-import { useGlobal } from "@/context/global"
|
|
|
import { ServerRowMenuView, serverMenuLabels } from "@/components/server/server-row-menu"
|
|
|
import { ServerHealthIndicator } from "@/components/server/server-row"
|
|
|
import { type ServerHealth } from "@/utils/server-health"
|
|
|
@@ -1015,133 +1004,3 @@ function HomeSessionSkeleton(props: { label: string }) {
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
-
|
|
|
-export function LegacyHome() {
|
|
|
- const sync = useServerSync()
|
|
|
- const pickDirectory = useDirectoryPicker()
|
|
|
- const dialog = useDialog()
|
|
|
- const navigate = useNavigate()
|
|
|
- const global = useGlobal()
|
|
|
- const server = useServer()
|
|
|
- const language = useLanguage()
|
|
|
- const homedir = createMemo(() => sync().data.path.home)
|
|
|
- const serverUnreachable = createMemo(() => global.servers.health[server.key]?.healthy === false)
|
|
|
- const recent = createMemo(() => {
|
|
|
- return sync()
|
|
|
- .data.project.slice()
|
|
|
- .sort((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created))
|
|
|
- .slice(0, 5)
|
|
|
- })
|
|
|
-
|
|
|
- const serverDotClass = createMemo(() => {
|
|
|
- const healthy = global.servers.health[server.key]?.healthy
|
|
|
- if (healthy === true) return "bg-icon-success-base"
|
|
|
- if (healthy === false) return "bg-icon-critical-base"
|
|
|
- return "bg-border-weak-base"
|
|
|
- })
|
|
|
-
|
|
|
- function openProject(server: ServerConnection.Any, directory: string) {
|
|
|
- const serverCtx = global.ensureServerCtx(server)
|
|
|
- serverCtx.projects.open(directory)
|
|
|
- serverCtx.projects.touch(directory)
|
|
|
- navigate(`/${base64Encode(directory)}`)
|
|
|
- }
|
|
|
-
|
|
|
- function chooseProject() {
|
|
|
- if (serverUnreachable()) return
|
|
|
- const s = server.current
|
|
|
- if (!s) return
|
|
|
-
|
|
|
- const resolve = (result: string | string[] | null) => {
|
|
|
- if (Array.isArray(result)) {
|
|
|
- for (const directory of result) {
|
|
|
- openProject(s, directory)
|
|
|
- }
|
|
|
- } else if (result) {
|
|
|
- openProject(s, result)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pickDirectory({
|
|
|
- server: s,
|
|
|
- title: language.t("command.project.open"),
|
|
|
- multiple: true,
|
|
|
- onSelect: resolve,
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- return (
|
|
|
- <div class="mx-auto mt-55 w-full md:w-auto px-4">
|
|
|
- <Logo class="md:w-xl opacity-12" />
|
|
|
- <Button
|
|
|
- size="large"
|
|
|
- variant="ghost"
|
|
|
- class="mt-4 mx-auto text-14-regular text-text-weak"
|
|
|
- onClick={() => dialog.show(() => <DialogSelectServer />)}
|
|
|
- >
|
|
|
- <div
|
|
|
- classList={{
|
|
|
- "size-2 rounded-full": true,
|
|
|
- [serverDotClass()]: true,
|
|
|
- }}
|
|
|
- />
|
|
|
- {server.name}
|
|
|
- </Button>
|
|
|
- <Switch>
|
|
|
- <Match when={sync().data.project.length > 0}>
|
|
|
- <div class="mt-20 w-full flex flex-col gap-4">
|
|
|
- <div class="flex gap-2 items-center justify-between pl-3">
|
|
|
- <div class="text-14-medium text-text-strong">{language.t("home.recentProjects")}</div>
|
|
|
- <Button
|
|
|
- icon="folder-add-left"
|
|
|
- size="normal"
|
|
|
- class="pl-2 pr-3"
|
|
|
- disabled={serverUnreachable()}
|
|
|
- onClick={chooseProject}
|
|
|
- >
|
|
|
- {language.t("command.project.open")}
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- <ul class="flex flex-col gap-2">
|
|
|
- <For each={recent()}>
|
|
|
- {(project) => (
|
|
|
- <Button
|
|
|
- size="large"
|
|
|
- variant="ghost"
|
|
|
- class="text-14-mono text-left justify-between px-3"
|
|
|
- onClick={() => openProject(server.current!, project.worktree)}
|
|
|
- >
|
|
|
- {project.worktree.replace(homedir(), "~")}
|
|
|
- <div class="text-14-regular text-text-weak">
|
|
|
- {DateTime.fromMillis(project.time.updated ?? project.time.created).toRelative()}
|
|
|
- </div>
|
|
|
- </Button>
|
|
|
- )}
|
|
|
- </For>
|
|
|
- </ul>
|
|
|
- </div>
|
|
|
- </Match>
|
|
|
- <Match when={!sync().ready}>
|
|
|
- <div class="mt-30 mx-auto flex flex-col items-center gap-3">
|
|
|
- <div class="text-12-regular text-text-weak">{language.t("common.loading")}</div>
|
|
|
- <Button class="px-3" disabled={serverUnreachable()} onClick={chooseProject}>
|
|
|
- {language.t("command.project.open")}
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- </Match>
|
|
|
- <Match when={true}>
|
|
|
- <div class="mt-30 mx-auto flex flex-col items-center gap-3">
|
|
|
- <Icon name="folder-add-left" size="large" />
|
|
|
- <div class="flex flex-col gap-1 items-center justify-center">
|
|
|
- <div class="text-14-medium text-text-strong">{language.t("home.empty.title")}</div>
|
|
|
- <div class="text-12-regular text-text-weak">{language.t("home.empty.description")}</div>
|
|
|
- </div>
|
|
|
- <Button class="px-3 mt-1" disabled={serverUnreachable()} onClick={chooseProject}>
|
|
|
- {language.t("command.project.open")}
|
|
|
- </Button>
|
|
|
- </div>
|
|
|
- </Match>
|
|
|
- </Switch>
|
|
|
- </div>
|
|
|
- )
|
|
|
-}
|