Merge pull request #7558 from Kilo-Org/kirillk/main-screen

feat(vscode): improve cloud session history UX
This commit is contained in:
Mark IJbema
2026-03-25 08:17:15 +01:00
committed by GitHub
10 changed files with 95 additions and 32 deletions
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d23a2e49a796acc94f387f7d4cddf783de1c630a3cd3902f3cf558083839b043
size 17817
oid sha256:63c6e23a31f570031361db39105d4283e05da923bb50757e7583c9430f805c53
size 16379
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5236457b1993d510ffd683a6ca3c8e538defe5ab607cbb92185bf9169764e8bf
size 28744
oid sha256:31bf6a6c046503a150ec6e49eae627411af10da26c17c7c5c455bb3c74198bc5
size 27697
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:65686e2d0978adcf09ae504d9414e2d81f304eb18ff2275be7a33a9c3579a5e5
size 18209
oid sha256:8b971f7a2234c16abbeeda98d9ee4f024a4ff46e63f7a6e5cc900a1e893bde6e
size 18934
+2 -1
View File
@@ -237,10 +237,11 @@ const AppContent: Component = () => {
<MarketplaceView />
</Match>
<Match when={currentView() === "history"}>
<SessionList onSelectSession={handleSelectSession} />
<SessionList onSelectSession={handleSelectSession} onBack={() => setCurrentView("newTask")} />
</Match>
<Match when={currentView() === "cloudHistory"}>
<CloudSessionList
onBack={() => setCurrentView("newTask")}
onSelectSession={(cloudSessionId) => {
session.selectCloudSession(cloudSessionId)
setCurrentView("newTask")
@@ -56,7 +56,7 @@ export const CloudImportDialog: Component<CloudImportDialogProps> = (props) => {
error={error()}
/>
<div class="dialog-confirm-actions">
<Button variant="ghost" size="large" onClick={() => dialog.close()}>
<Button variant="secondary" size="large" onClick={() => dialog.close()}>
{language.t("common.cancel")}
</Button>
<Button variant="primary" size="large" onClick={submit}>
@@ -10,14 +10,12 @@
import { Component, For, Show, createEffect, createMemo, onCleanup, JSX } from "solid-js"
import { Icon } from "@kilocode/kilo-ui/icon"
import { Spinner } from "@kilocode/kilo-ui/spinner"
import { Button } from "@kilocode/kilo-ui/button"
import { useDialog } from "@kilocode/kilo-ui/context/dialog"
import { createAutoScroll } from "@kilocode/kilo-ui/hooks"
import { useSession } from "../../context/session"
import { useServer } from "../../context/server"
import { useLanguage } from "../../context/language"
import { formatRelativeDate } from "../../utils/date"
import { CloudImportDialog } from "./CloudImportDialog"
import { FeedbackDialog } from "./FeedbackDialog"
import { VscodeSessionTurn } from "./VscodeSessionTurn"
import { RevertBanner } from "./RevertBanner"
@@ -129,21 +127,6 @@ export const MessageList: Component<MessageListProps> = (props) => {
</For>
</div>
</Show>
<Button
variant="ghost"
size="small"
onClick={() =>
dialog.show(() => (
<CloudImportDialog
onImport={(id) => {
session.selectCloudSession(id)
}}
/>
))
}
>
{language.t("session.cloud.import")}
</Button>
<button class="feedback-button" onClick={() => dialog.show(() => <FeedbackDialog />)}>
<Icon name="bubble-5" size="small" />
{language.t("feedback.button")}
@@ -8,8 +8,10 @@ import { Component, createSignal, createEffect, onMount, onCleanup, Show } from
import { List } from "@kilocode/kilo-ui/list"
import { Button } from "@kilocode/kilo-ui/button"
import { Checkbox } from "@kilocode/kilo-ui/checkbox"
import { useDialog } from "@kilocode/kilo-ui/context/dialog"
import { useVSCode } from "../../context/vscode"
import { useLanguage } from "../../context/language"
import { CloudImportDialog } from "../chat/CloudImportDialog"
import { formatRelativeDate } from "../../utils/date"
import type { CloudSessionInfo, ExtensionMessage } from "../../types/messages"
@@ -51,11 +53,13 @@ function toDisplay(s: CloudSessionInfo): DisplaySession {
interface CloudSessionListProps {
onSelectSession?: (id: string) => void
onBack?: () => void
}
const CloudSessionList: Component<CloudSessionListProps> = (props) => {
const vscode = useVSCode()
const language = useLanguage()
const dialog = useDialog()
const [sessions, setSessions] = createSignal<DisplaySession[]>([])
const [loading, setLoading] = createSignal(false)
@@ -127,9 +131,31 @@ const CloudSessionList: Component<CloudSessionListProps> = (props) => {
return (
<div class="session-list cloud-session-list">
<div class="cloud-session-filters">
<Checkbox checked={repoOnly()} onChange={setRepoOnly}>
{language.t("session.cloud.repoOnly") ?? "Only this repository"}
</Checkbox>
<Button variant="ghost" size="small" icon="arrow-left" onClick={() => props.onBack?.()}>
{language.t("common.goBack")}
</Button>
<div class="cloud-session-filters-right">
<Show when={gitUrl() !== null}>
<Checkbox checked={repoOnly()} onChange={setRepoOnly}>
{language.t("session.cloud.repoOnly") ?? "Only this repository"}
</Checkbox>
</Show>
<Button
variant="secondary"
size="small"
onClick={() =>
dialog.show(() => (
<CloudImportDialog
onImport={(id) => {
props.onSelectSession?.(id)
}}
/>
))
}
>
{language.t("session.cloud.import")}
</Button>
</div>
</div>
<List<DisplaySession>
items={sessions()}
@@ -37,6 +37,7 @@ function dateGroupKey(iso: string): (typeof DATE_GROUP_KEYS)[number] {
interface SessionListProps {
onSelectSession: (id: string) => void
onBack?: () => void
}
const SessionList: Component<SessionListProps> = (props) => {
@@ -130,6 +131,11 @@ const SessionList: Component<SessionListProps> = (props) => {
return (
<div class="session-list">
<div class="session-list-header">
<Button variant="ghost" size="small" icon="arrow-left" onClick={() => props.onBack?.()}>
{language.t("common.goBack")}
</Button>
</div>
<List<SessionInfo>
items={session.sessions()}
key={(s) => s.id}
@@ -827,13 +827,13 @@ export const dict = {
"session.search.placeholder": "Search sessions...",
"session.empty": "No sessions yet. Click + to start a new conversation.",
"session.cloud.repoOnly": "Only this repository",
"session.cloud.import": "Import from cloud",
"session.cloud.import": "Import session",
"feedback.button": "Feedback & Support",
"feedback.dialog.message": "We'd love to hear your feedback or help with any issues you're experiencing.",
"feedback.dialog.github": "Report an issue on GitHub",
"feedback.dialog.discord": "Join our Discord community",
"feedback.dialog.support": "Customer Support",
"session.cloud.import.title": "Import from cloud",
"session.cloud.import.title": "Import session",
"session.cloud.import.placeholder": "Session ID, URL, or kilo import command",
"session.cloud.import.button": "Import",
"session.cloud.import.invalid": "Invalid session ID format",
@@ -2089,6 +2089,24 @@
white-space: nowrap;
}
body.vscode-light .session-list [data-slot="list-item"][data-active="true"] [data-slot="list-item-description"],
body.vscode-light .session-list [data-slot="list-item"][data-selected="true"] [data-slot="list-item-description"] {
color: var(--text-on-interactive-base, white);
}
body.vscode-light
.session-list
[data-slot="list-item"][data-active="true"]
[data-slot="session-delete-button"]
[data-slot="icon-svg"],
body.vscode-light
.session-list
[data-slot="list-item"][data-selected="true"]
[data-slot="session-delete-button"]
[data-slot="icon-svg"] {
color: var(--text-on-interactive-base, white);
}
.session-list [data-slot="session-delete-button"] {
flex-shrink: 0;
margin-left: 4px;
@@ -2109,10 +2127,39 @@
min-height: 0;
}
.session-list-header,
.cloud-session-filters {
flex-shrink: 0;
padding: 8px 12px;
border-bottom: 1px solid var(--vscode-panel-border);
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
min-height: 40px;
}
.cloud-session-filters {
[data-component="checkbox"] {
gap: 8px;
[data-slot="checkbox-checkbox-label"] {
padding-inline-start: 0;
margin-inline-end: 0;
}
}
}
.cloud-session-filters-right {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
}
[data-component="input"][data-variant="normal"] [data-slot="input-wrapper"]:focus-within:not(:has([data-readonly])) {
border-color: transparent;
box-shadow: none;
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
.cloud-session-load-more {