mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-13 05:07:40 +02:00
[eric] composer: attachment chips answer right-click, file chips gain Copy path and a reveal-only Finder IPC
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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',
|
||||
|
||||
Vendored
+1
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user