[eric] composer: attachment chips answer right-click, file chips gain Copy path and a reveal-only Finder IPC

This commit is contained in:
ciregenz
2026-08-06 13:34:37 -07:00
parent dd8bac0552
commit af69bd5017
5 changed files with 53 additions and 1 deletions
+13
View File
@@ -3168,6 +3168,19 @@ ipcMain.handle('get-webview-preload-path', () => {
return `file://${path.join(__dirname, 'webview-preload.js')}`;
});
// Reveal a user-attached composer file in Finder/Explorer. Reveal-only on an existing path:
// showItemInFolder never opens or executes the file, so the worst misuse is popping a Finder window.
ipcMain.handle('files:reveal', (event, filePath) => {
try {
const p = path.resolve(String(filePath || ''));
if (!fs.existsSync(p)) return { ok: false };
shell.showItemInFolder(p);
return { ok: true };
} catch (_) {
return { ok: false };
}
});
// Reveal a diagnostics bundle in the file manager so the user can drag it into a GitHub issue.
// Scoped HARD to the backend's diagnostics dir: this must never become an arbitrary-path opener.
ipcMain.handle('help:reveal-bundle', (event, folderPath) => {
+2
View File
@@ -90,6 +90,8 @@ contextBridge.exposeInMainWorld('openswarm', {
},
// Reveal a diagnostics folder in Finder/Explorer (path validated in main; diagnostics dir only).
revealBundle: (folderPath) => ipcRenderer.invoke('help:reveal-bundle', folderPath),
// Reveal a user-attached file in Finder/Explorer (reveal-only; main checks existence).
revealPath: (filePath) => ipcRenderer.invoke('files:reveal', filePath),
// Native OS notification for a finished workflow run, posted by the MAIN process
// so it survives a minimized/hidden/backgrounded renderer (the renderer's own
@@ -8,6 +8,8 @@ import FolderOpenIcon from '@mui/icons-material/FolderOpen';
import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';
import AdsClickIcon from '@mui/icons-material/AdsClick';
import { getToolGroupIcon } from '@/app/components/editor/CommandPicker';
import { openCardContextMenu } from '@/app/pages/Dashboard/desktop/openCardContextMenu';
import { IS_MAC } from '@/app/pages/Dashboard/desktop/chord';
import { SelectedElement } from '@/app/components/editor/ElementSelectionContext';
import { ContextPath } from '@/app/components/editor/DirectoryBrowser';
import { ClaudeTokens } from '@/shared/styles/claudeTokens';
@@ -74,6 +76,13 @@ export const AttachmentChips: React.FC<Props> = ({
'&:hover': { opacity: 0.85, transform: 'scale(1.04)' },
}}
onClick={() => setLightboxSrc(img.preview)}
onContextMenu={(e) => openCardContextMenu(e, {
items: [
{ label: 'View', onClick: () => setLightboxSrc(img.preview) },
{ kind: 'separator' },
{ label: 'Remove', danger: true, onClick: () => removeImage(idx) },
],
})}
>
<img
src={img.preview}
@@ -151,6 +160,21 @@ export const AttachmentChips: React.FC<Props> = ({
setTimeout(() => setCopiedPathIdx((cur) => cur === idx ? null : cur), 1200);
}}
onDelete={() => setContextPaths((prev) => prev.filter((_, i) => i !== idx))}
onContextMenu={(e) => openCardContextMenu(e, {
items: [
{
label: 'Copy path',
onClick: () => {
navigator.clipboard.writeText(cp.path);
setCopiedPathIdx(idx);
setTimeout(() => setCopiedPathIdx((cur) => cur === idx ? null : cur), 1200);
},
},
{ label: IS_MAC ? 'Reveal in Finder' : 'Show in Explorer', onClick: () => { void window.openswarm?.revealPath?.(cp.path); } },
{ kind: 'separator' },
{ label: 'Remove', danger: true, onClick: () => setContextPaths((prev) => prev.filter((_, i) => i !== idx)) },
],
})}
sx={{
bgcolor: `${chipColor}12`,
color: chipColor,
@@ -184,6 +208,11 @@ export const AttachmentChips: React.FC<Props> = ({
label={`@${ft.label.toLowerCase()}`}
size="small"
onDelete={() => setForcedTools((prev) => prev.filter((_, i) => i !== idx))}
onContextMenu={(e) => openCardContextMenu(e, {
items: [
{ label: 'Remove', danger: true, onClick: () => setForcedTools((prev) => prev.filter((_, i) => i !== idx)) },
],
})}
sx={{
bgcolor: `${c.status.info}15`,
color: c.status.info,
@@ -236,6 +265,13 @@ export const AttachmentChips: React.FC<Props> = ({
label={chipLabel}
size="small"
onDelete={() => elementSelection?.removeOwnerElement(ownerId, el.id)}
onContextMenu={(e) => openCardContextMenu(e, {
items: [
{ label: 'Copy selector', onClick: () => { navigator.clipboard.writeText(el.selectorPath); } },
{ kind: 'separator' },
{ label: 'Remove', danger: true, onClick: () => elementSelection?.removeOwnerElement(ownerId, el.id) },
],
})}
sx={{
bgcolor: 'rgba(59, 130, 246, 0.1)',
color: '#3b82f6',
@@ -1,5 +1,5 @@
// Renders a shortcut the way the platform writes it: mac glyphs run together, Windows spells them with +.
const IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/i.test(navigator.platform);
export const IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/i.test(navigator.platform);
const GLYPH: Record<string, string> = {
mod: IS_MAC ? '⌘' : 'Ctrl',
+1
View File
@@ -101,6 +101,7 @@ declare global {
onOauthClaim?: (cb: (url: string) => void) => () => void;
notify?: (payload: OpenSwarmNotifyRequest) => Promise<boolean>;
onNotificationAction?: (cb: (payload: OpenSwarmNotifyAction) => void) => () => void;
revealPath?: (filePath: string) => Promise<{ ok: boolean }>;
}
interface Window {