fix(app): hide default session timestamps (#20892)

pull/20841/head^2
Shoubhit Dash 2026-04-03 19:21:54 +05:30 committed by GitHub
parent 9d57f21f9f
commit fbfa148e4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 42 deletions

View File

@ -16,6 +16,7 @@ import { getAvatarColors, type LocalProject, useLayout } from "@/context/layout"
import { useNotification } from "@/context/notification" import { useNotification } from "@/context/notification"
import { usePermission } from "@/context/permission" import { usePermission } from "@/context/permission"
import { messageAgentColor } from "@/utils/agent" import { messageAgentColor } from "@/utils/agent"
import { sessionTitle } from "@/utils/session-title"
import { sessionPermissionRequest } from "../session/composer/session-request-tree" import { sessionPermissionRequest } from "../session/composer/session-request-tree"
import { hasProjectPermissions } from "./helpers" import { hasProjectPermissions } from "./helpers"
@ -101,42 +102,46 @@ const SessionRow = (props: {
warmPress: () => void warmPress: () => void
warmFocus: () => void warmFocus: () => void
cancelHoverPrefetch: () => void cancelHoverPrefetch: () => void
}): JSX.Element => ( }) => {
<A const title = () => sessionTitle(props.session.title)
href={`/${props.slug}/session/${props.session.id}`}
class={`flex items-center gap-1 min-w-0 w-full text-left focus:outline-none ${props.dense ? "py-0.5" : "py-1"}`} return (
onPointerDown={props.warmPress} <A
onPointerEnter={props.warmHover} href={`/${props.slug}/session/${props.session.id}`}
onPointerLeave={props.cancelHoverPrefetch} class={`flex items-center gap-1 min-w-0 w-full text-left focus:outline-none ${props.dense ? "py-0.5" : "py-1"}`}
onFocus={props.warmFocus} onPointerDown={props.warmPress}
onClick={() => { onPointerEnter={props.warmHover}
props.setHoverSession(undefined) onPointerLeave={props.cancelHoverPrefetch}
if (props.sidebarOpened()) return onFocus={props.warmFocus}
props.clearHoverProjectSoon() onClick={() => {
}} props.setHoverSession(undefined)
> if (props.sidebarOpened()) return
<div props.clearHoverProjectSoon()
class="shrink-0 size-6 flex items-center justify-center" }}
style={{ color: props.tint() ?? "var(--icon-interactive-base)" }}
> >
<Switch fallback={<Icon name="dash" size="small" class="text-icon-weak" />}> <div
<Match when={props.isWorking()}> class="shrink-0 size-6 flex items-center justify-center"
<Spinner class="size-[15px]" /> style={{ color: props.tint() ?? "var(--icon-interactive-base)" }}
</Match> >
<Match when={props.hasPermissions()}> <Switch fallback={<Icon name="dash" size="small" class="text-icon-weak" />}>
<div class="size-1.5 rounded-full bg-surface-warning-strong" /> <Match when={props.isWorking()}>
</Match> <Spinner class="size-[15px]" />
<Match when={props.hasError()}> </Match>
<div class="size-1.5 rounded-full bg-text-diff-delete-base" /> <Match when={props.hasPermissions()}>
</Match> <div class="size-1.5 rounded-full bg-surface-warning-strong" />
<Match when={props.unseenCount() > 0}> </Match>
<div class="size-1.5 rounded-full bg-text-interactive-base" /> <Match when={props.hasError()}>
</Match> <div class="size-1.5 rounded-full bg-text-diff-delete-base" />
</Switch> </Match>
</div> <Match when={props.unseenCount() > 0}>
<span class="text-14-regular text-text-strong min-w-0 flex-1 truncate">{props.session.title}</span> <div class="size-1.5 rounded-full bg-text-interactive-base" />
</A> </Match>
) </Switch>
</div>
<span class="text-14-regular text-text-strong min-w-0 flex-1 truncate">{title()}</span>
</A>
)
}
const SessionHoverPreview = (props: { const SessionHoverPreview = (props: {
mobile?: boolean mobile?: boolean
@ -319,7 +324,7 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
fallback={ fallback={
<Tooltip <Tooltip
placement={props.mobile ? "bottom" : "right"} placement={props.mobile ? "bottom" : "right"}
value={props.session.title} value={sessionTitle(props.session.title)}
gutter={10} gutter={10}
class="min-w-0 w-full" class="min-w-0 w-full"
> >

View File

@ -29,6 +29,7 @@ import { useSettings } from "@/context/settings"
import { useSDK } from "@/context/sdk" import { useSDK } from "@/context/sdk"
import { useSync } from "@/context/sync" import { useSync } from "@/context/sync"
import { messageAgentColor } from "@/utils/agent" import { messageAgentColor } from "@/utils/agent"
import { sessionTitle } from "@/utils/session-title"
import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note" import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note"
import { makeTimer } from "@solid-primitives/timer" import { makeTimer } from "@solid-primitives/timer"
@ -43,7 +44,6 @@ type MessageComment = {
const emptyMessages: MessageType[] = [] const emptyMessages: MessageType[] = []
const idle = { type: "idle" as const } const idle = { type: "idle" as const }
type UserActions = { type UserActions = {
fork?: (input: { sessionID: string; messageID: string }) => Promise<void> | void fork?: (input: { sessionID: string; messageID: string }) => Promise<void> | void
revert?: (input: { sessionID: string; messageID: string }) => Promise<void> | void revert?: (input: { sessionID: string; messageID: string }) => Promise<void> | void
@ -291,6 +291,7 @@ export function MessageTimeline(props: {
return sync.session.get(id) return sync.session.get(id)
}) })
const titleValue = createMemo(() => info()?.title) const titleValue = createMemo(() => info()?.title)
const titleLabel = createMemo(() => sessionTitle(titleValue()))
const shareUrl = createMemo(() => info()?.share?.url) const shareUrl = createMemo(() => info()?.share?.url)
const shareEnabled = createMemo(() => sync.data.config.share !== "disabled") const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
const parentID = createMemo(() => info()?.parentID) const parentID = createMemo(() => info()?.parentID)
@ -399,7 +400,7 @@ export function MessageTimeline(props: {
const openTitleEditor = () => { const openTitleEditor = () => {
if (!sessionID()) return if (!sessionID()) return
setTitle({ editing: true, draft: titleValue() ?? "" }) setTitle({ editing: true, draft: titleLabel() ?? "" })
requestAnimationFrame(() => { requestAnimationFrame(() => {
titleRef?.focus() titleRef?.focus()
titleRef?.select() titleRef?.select()
@ -417,7 +418,7 @@ export function MessageTimeline(props: {
if (titleMutation.isPending) return if (titleMutation.isPending) return
const next = title.draft.trim() const next = title.draft.trim()
if (!next || next === (titleValue() ?? "")) { if (!next || next === (titleLabel() ?? "")) {
setTitle("editing", false) setTitle("editing", false)
return return
} }
@ -532,7 +533,9 @@ export function MessageTimeline(props: {
} }
function DialogDeleteSession(props: { sessionID: string }) { function DialogDeleteSession(props: { sessionID: string }) {
const name = createMemo(() => sync.session.get(props.sessionID)?.title ?? language.t("command.session.new")) const name = createMemo(
() => sessionTitle(sync.session.get(props.sessionID)?.title) ?? language.t("command.session.new"),
)
const handleDelete = async () => { const handleDelete = async () => {
await deleteSession(props.sessionID) await deleteSession(props.sessionID)
dialog.close() dialog.close()
@ -673,7 +676,7 @@ export function MessageTimeline(props: {
</div> </div>
</Show> </Show>
</div> </div>
<Show when={titleValue() || title.editing}> <Show when={titleLabel() || title.editing}>
<Show <Show
when={title.editing} when={title.editing}
fallback={ fallback={
@ -681,7 +684,7 @@ export function MessageTimeline(props: {
class="text-14-medium text-text-strong truncate grow-1 min-w-0" class="text-14-medium text-text-strong truncate grow-1 min-w-0"
onDblClick={openTitleEditor} onDblClick={openTitleEditor}
> >
{titleValue()} {titleLabel()}
</h1> </h1>
} }
> >

View File

@ -0,0 +1,7 @@
const pattern = /^(New session|Child session) - \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/
export function sessionTitle(title?: string) {
if (!title) return title
const match = title.match(pattern)
return match?.[1] ?? title
}