Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/screenshots/01-palette-archived.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/screenshots/02-unarchive-dropdown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/screenshots/03-restored.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/app/src/components/dialog-select-file.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,9 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
>
{item.title}
</span>
<Show when={item.archived}>
<span class="text-12-regular text-text-weak">(archived)</span>
</Show>
<Show when={item.description}>
<span
class="text-14-regular text-text-weak truncate"
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/context/global-sync/event-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export function applyDirectoryEvent(input: {
const trimmed = trimSessions(next, { limit: input.store.limit, permission: input.store.permission })
input.setStore("session", reconcile(trimmed, { key: "id" }))
cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo)
if (!info.parentID) input.setStore("sessionTotal", (value) => value + 1)
break
}
case "session.deleted": {
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const dict = {
"command.session.previous.unseen": "Previous unread session",
"command.session.next.unseen": "Next unread session",
"command.session.archive": "Archive session",
"command.session.unarchive": "Unarchive session",

"command.palette": "Command palette",

Expand Down Expand Up @@ -643,6 +644,7 @@ export const dict = {
"common.rename": "Rename",
"common.reset": "Reset",
"common.archive": "Archive",
"common.unarchive": "Unarchive",
"common.delete": "Delete",
"common.close": "Close",
"common.edit": "Edit",
Expand Down
18 changes: 18 additions & 0 deletions packages/app/src/pages/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,15 @@ export default function Layout(props: ParentProps) {
}
}

async function unarchiveSession(sessionID: string, directory: string) {
await globalSDK.client.session.update({
directory,
sessionID,
time: { archived: null },
})
navigate(`/${params.dir}/session/${sessionID}`)
}

command.register("layout", () => {
const commands: CommandOption[] = [
{
Expand Down Expand Up @@ -1099,6 +1108,15 @@ export default function Layout(props: ParentProps) {
if (session) void archiveSession(session)
},
},
{
id: "session.unarchive",
title: language.t("command.session.unarchive"),
category: language.t("command.category.session"),
disabled: !params.dir || !params.id,
onSelect: () => {
if (params.id && params.dir) void unarchiveSession(params.id, params.dir)
},
},
{
id: "workspace.new",
title: language.t("workspace.new"),
Expand Down
24 changes: 21 additions & 3 deletions packages/app/src/pages/session/message-timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,15 @@ export function MessageTimeline(props: {
})
}

const unarchiveSession = async (sessionID: string) => {
await sdk.client.session.update({ sessionID, time: { archived: null } }).catch((err) => {
showToast({
title: language.t("common.requestFailed"),
description: errorMessage(err),
})
})
}

const deleteSession = async (sessionID: string) => {
const session = sync.session.get(sessionID)
if (!session) return false
Expand Down Expand Up @@ -878,9 +887,18 @@ export function MessageTimeline(props: {
</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
</Show>
<DropdownMenu.Item onSelect={() => void archiveSession(id)}>
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
<Show
when={info()?.time?.archived}
fallback={
<DropdownMenu.Item onSelect={() => void archiveSession(id)}>
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
}
>
<DropdownMenu.Item onSelect={() => void unarchiveSession(id)}>
<DropdownMenu.ItemLabel>{language.t("common.unarchive")}</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
</Show>
<DropdownMenu.Separator />
<DropdownMenu.Item
onSelect={() => dialog.show(() => <DialogDeleteSession sessionID={id} />)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,15 @@ export function DialogSessionList() {
category = "Today"
}
const isDeleting = toDelete() === x.id
const isArchived = !!x.time?.archived
const status = sync.data.session_status?.[x.id]
const isWorking = status?.type === "busy"
return {
title: isDeleting ? `Press ${keybind.print("session_delete")} again to confirm` : x.title,
title: isDeleting
? `Press ${keybind.print("session_delete")} again to confirm`
: isArchived
? `[archived] ${x.title}`
: x.title,
bg: isDeleting ? theme.error : undefined,
value: x.id,
category,
Expand Down Expand Up @@ -247,6 +252,29 @@ export function DialogSessionList() {
dialog.replace(() => <DialogSessionRename session={option.value} />)
},
},
{
keybind: Keybind.parse("ctrl+a")[0],
title: "archive",
onTrigger: async (option) => {
const session = sessions().find((item) => item.id === option.value)
if (!session) return
const archived = session.time?.archived
await sdk.client.session
.update({
sessionID: option.value,
time: { archived: archived ? null : Date.now() },
})
.catch((err) => {
toast.show({
variant: "error",
title: archived ? "Failed to unarchive session" : "Failed to archive session",
message: errorMessage(err),
})
})
await sync.session.refresh()
if (search()) await refetch()
},
},
{
keybind: Keybind.parse("ctrl+w")[0],
title: "new workspace",
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/server/routes/instance/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export const SessionRoutes = lazy(() =>
permission: Permission.Ruleset.zod.optional(),
time: z
.object({
archived: z.number().optional(),
archived: z.number().nullable().optional(),
})
.optional(),
}),
Expand All @@ -310,7 +310,7 @@ export const SessionRoutes = lazy(() =>
})
}
if (updates.time?.archived !== undefined) {
yield* session.setArchived({ sessionID, time: updates.time.archived })
yield* session.setArchived({ sessionID, time: updates.time.archived ?? undefined })
}

return yield* session.get(sessionID)
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/session/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
})

const setArchived = Effect.fn("Session.setArchived")(function* (input: { sessionID: SessionID; time?: number }) {
yield* patch(input.sessionID, { time: { archived: input.time } })
yield* patch(input.sessionID, { time: { archived: input.time ?? null } })
})

const setPermission = Effect.fn("Session.setPermission")(function* (input: {
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/js/src/v2/gen/sdk.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1795,7 +1795,7 @@ export class Session2 extends HeyApiClient {
title?: string
permission?: PermissionRuleset
time?: {
archived?: number
archived?: number | null
}
},
options?: Options<never, ThrowOnError>,
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3420,7 +3420,7 @@ export type SessionUpdateData = {
title?: string
permission?: PermissionRuleset
time?: {
archived?: number
archived?: number | null
}
}
path: {
Expand Down
9 changes: 8 additions & 1 deletion packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2652,7 +2652,14 @@
"type": "object",
"properties": {
"archived": {
"type": "number"
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
]
}
}
}
Expand Down
Loading