Give attachment preview tabs file actions from the shared action list
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- tauri, typescript
- Domain
- desktop, developer-experience, frontend
Research direction
Start with PreviewWorkspace.tsx, especially TabContextMenu, HeaderFileActions, PreviewAttachmentView, and the file and attachment tab components; read previewResource.ts to understand the shared actions. Then inspect DocumentTabView.tsx, its tests, and the English and Chinese i18n files. Done means the attachment actions, copy labels, document downloads, Markdown relative paths, failed-read behavior, remote host checks, translations, and docs match the listed acceptance criteria; the issue also depends on #27 and #28 and requires desktop checks and reviewed screenshots.
Written by the indexing model from the issue text.
Description
What feature would you like to see?
A file the agent sent with SendMessage opens in a preview tab whose context menu offers only "close tab / close others / close all", and whose header offers only "rendered / source" and a download arrow. PDF, Word, Excel, PowerPoint and CSV attachments do not even get a download: their header shows page controls only. Markdown attachments resolve relative images and links against the session directory instead of the file's own directory, so their images show "无法读取该文件" ("Could not load this file"). Opening the same notes.md from the receipt and from a link gives two tabs with the same name and no word saying which is the sent copy.
Decided
- Attachment tabs get the actions the shared action list (preview resource model issue) allows: with a trusted original they offer copy path, show on this computer, open original file, and "@" add to chat; without one they offer none of these.
- A live file and its sent copy are two tabs. The copy is labelled "副本" and offers "打开现在的文件" (open the current file).
- Every place in this file that decides "is this connection remote" uses the one
isKikiComputerfunction, which fails closed. - When a read fails, header actions that need the bytes (download, add to chat) are not rendered.
- Merging file and attachment tabs into one kind is a later phase; this issue keeps the two tab kinds.
Design
- Tab context menu (
TabContextMenu): keep close tab, close others, close all. For file tabs and attachment tabs, append the items ofresourceActions(...)fromapps/kiki-gui/src/state/previewResource.tsfor that tab's resource instead of the hand-writtentab.kind === 'file'branch. The file-tab items that exist today (copy relative path, copy absolute path, show in folder, open with default app) stay available where the action list allows them. - Attachment header: render the same action list. The most used action stays inline (download where the bytes are readable); the rest go into a header "more" menu. For a copy with a trusted original, the open-with-default-app action reads "打开原文件" / "Open original file", because it opens what is on disk now, not the sent bytes.
- Copy marking: an attachment tab whose resource is a copy shows the short mark "副本" / "Sent copy" on the tab and the line "发送时的副本" / "Copy as it was sent" in its header. When the trusted original is readable, the header offers "打开现在的文件" / "Open current file", which opens (or activates) the live file tab for the original path.
- Document attachments:
DocumentTabViewgets a download action in its own header, so PDF, Office and CSV attachments can be downloaded in every state, not only in the "unsupported" fallback. - Markdown attachments: pass the original's directory as
documentDirectory(and the original path asdocumentPath) when a trusted origin exists, so relative images and links resolve where the file came from. Without an origin, keep today's behaviour. - One remote check for host actions: replace the two SSH-only checks that gate reveal and open in this file (
scopeId.startsWith('ssh:')inTabContextMenuanduseFileOpeners) withisKikiComputer. Today the tab menu and header offer "show in folder" and "open with default app" in a remote space that is not SSH; afterwards they do not. TheconnectionSource === 'remote'check in the text tab answers a different question (whether the HTML preview goes through the remote-space broker and may ask for a resource root); leave its behaviour unchanged, but give the variable a name that says so. - Docs: in the preview paragraph of
docs/en/guides/interface.md, say that a sent attachment whose original is known offers copy path, show and open original, and is marked as the copy as it was sent; mirror it indocs/zh/guides/interface.md. - Failed reads: when the tab's read failed, the header does not render download or add-to-chat, and the tab's "@" is not rendered.
- Hard-coded English: the agent tab fallback label and tooltip use a hard-coded
Agent:; replace both with an i18n key inen.tsandzh.ts.
Repository rules: every new string gets a key in both packages/session-core/src/i18n/en.ts and zh.ts. The i18n files are shared with other issues; add keys, do not reorder.
Where
apps/kiki-gui/src/components/PreviewWorkspace.tsx:1061-1125(TabContextMenu; the file-only branch at 1088-1100; SSH-only check at 1080; both host openers required at 1082).:1162-1176(useFileOpeners, SSH-only check at 1166),:1198-1242(HeaderFileActions).:1959(remoteScope = connection?.connectionSource === 'remote'in the text tab, used at2003and2166for the remote HTML resource root).- Docs:
docs/en/guides/interface.md:87-97anddocs/zh/guides/interface.md:87-97. :2429-2774(PreviewAttachmentView: path stripped before the byte read at 2472-2475; document attachments hand the whole header toDocumentTabViewat 2584-2596; header download at 2630-2639; markdown rendered withoutdocumentDirectoryat 2738, compare the file tab at 2119-2120 and 2375).:456and:1003(hard-codedAgent:).:625-735(PreviewFileTabwith the "@" at 700-712),:811-893(PreviewAttachmentTab).apps/kiki-gui/src/components/preview/DocumentTabView.tsx:147-157(header without download),:309-313(download only in the fallback body).- Existing strings to reuse:
file.copyRelativePath,file.copyAbsolutePath,file.showInFolder,file.openDefaultApp,media.download,preview.addToChatinpackages/session-core/src/i18n/en.ts:883-887, 1901, 1929andzh.ts:872-876, 1881, 1909.
Done when
- With a SendMessage attachment that has
source_id, on a local desktop host: the tab menu and header offer copy path, show on this computer, open original file and "@"; in a remote space: only copy path; withoutsource_id: none of the three. Covered by tests inPreviewWorkspace.test.tsxusing a mocked host. - PDF, Office and CSV attachment tabs have a download action in the header in the ready state.
- A relative image in a Markdown attachment with a trusted origin resolves against the original's directory.
- Opening the same file from a receipt and from a link gives two tabs; the copy carries "副本" and "发送时的副本", and "打开现在的文件" activates the live tab.
- After a failed read, the header shows no download and no "@".
- No
scopeId.startsWith('ssh:')check remains inPreviewWorkspace.tsx; reveal and open are gated only byisKikiComputerand the host capabilities. - en and zh docs updated together.
- Screenshots from
apps/kiki-gui/scripts/visual-proof.mjs(--theme light,dark --locale en,zh --viewport wide,narrow,message-channelsscenario withsource_id, plus a mocked local desktop host built the wayapps/kiki-gui/scripts/broker-desktop-mock.mjsstubswindow.__TAURI_INTERNALS__) show the attachment tab header and menu at desktop and phone width; they are looked at, not only produced. -
pnpm --filter @kiki/gui typecheckandpnpm --filter @kiki/gui test:fastpass. - Phone-width screenshots are taken in a touch context (
isMobile: true, hasTouch: true, asapps/kiki-gui/scripts/visual-proof-mobile-reading.mjs:294-300does). Phone mode is(pointer: coarse) and (max-width: 639px)(apps/kiki-gui/src/lib/layoutHooks.ts:57), so a width-only--viewport narrowrun ofvisual-proof.mjsshows the desktop layout squeezed, not the phone layout.
Additional information
Start only after the pending GUI interaction and mobile pass has merged: it also edits PreviewWorkspace.tsx and mediaParts.tsx, and the line numbers above are from the tree that includes it. The later issue that splits PreviewWorkspace.tsx into renderer files must start after this one. The desktop shell's reveal, open and write commands only run in the desktop app, so the "show" and "open" items must be checked there by hand as well; the browser harness has no revealPath or openPath. Paired devices and remote spaces cannot read files by path yet; that is handled in its own issue.
Order and scope. Paths and line numbers refer to the code after the pending GUI interaction and mobile pull request is merged into kiki.
Depends on: #27, #28.
Main files: apps/kiki-gui/src/components/PreviewWorkspace.tsx, apps/kiki-gui/src/components/PreviewWorkspace.test.tsx, apps/kiki-gui/src/components/preview/DocumentTabView.tsx, packages/session-core/src/i18n/en.ts, packages/session-core/src/i18n/zh.ts, docs/en/guides/interface.md, docs/zh/guides/interface.md.
- Dominant language
- TypeScript
- Stars
- 54
- Forks
- 5
- Avg merge
- 2h 54m
- Merged PRs (30d)
- 2
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from X-T-E-R/kiki
-
Document PowerShell shell semantics and read-only Bash deduplication in Built-in Tools referenceOpendocumentation
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug documentation
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 54/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 1/100
-
documentation
Difficulty 5/5 Over a week Newbie friendliness 25/100
Similar issues
-
🐛 The Rulekeeper - An index run that gives up on the lock ends SucceededPossibly taken @github-actions claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SSWConsulting/SSW.Rules#2809 · 1 comment ·
Maintainers usually reply within 1 day
-
automated-triage type/bug type/ci
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
📦 expo-router Android contributor: external needs review sdk-58 severity: medium
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Translate the READMEOpendocumentation good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
asasemahmed/openboard#68 ·
Maintainers usually reply within 1 day