mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-11 08:42:45 +00:00
Co-authored-by: netcatty-bot <308658023+netcatty-bot@users.noreply.github.com>
This commit is contained in:
1 parent
04a63c653a
commit
50ca182e1e
7 files changed
+57
No files matched your search
@@ -53,6 +53,19 @@ test("scripts side panel offers run-on-all-tabs for every snippet, not only auto
|
||||
assert.match(source, /openPackageDialog/);
|
||||
});
|
||||
|
||||
test("scripts side panel snippet context menu offers copy command without running", () => {
|
||||
// Copy must sit between the run actions and Edit, write snippet.command to
|
||||
// the clipboard, and confirm with a toast — it never executes the command.
|
||||
assert.match(source, /onCopyCommand=\{\(\) => handleCopySnippetCommand\(item\.snippet\)\}/);
|
||||
assert.match(source, /onCopyCommand=\{\(\) => handleCopySnippetCommand\(item\.row\.snippet\)\}/);
|
||||
assert.match(source, /scripts\.actions\.copyCommand'/);
|
||||
const menu = source.match(/\{onRunParallel \? \([\s\S]*?<\/ContextMenu>/);
|
||||
assert.ok(menu, "snippet row context menu should exist");
|
||||
assert.match(menu[0], /onCopyCommand[\s\S]*?onClick=\{onEdit\}/);
|
||||
assert.match(menu[0], /<Copy className="[\s\S]*?\{copyCommandLabel\}/);
|
||||
assert.match(source, /handleCopySnippetCommand[\s\S]*?snippet\.command[\s\S]*?toast\.success/);
|
||||
});
|
||||
|
||||
test("scripts side panel exposes create actions as inline toolbar icons", () => {
|
||||
assert.match(source, /snippets\.action\.newSnippet/);
|
||||
assert.match(source, /snippets\.action\.newPackage/);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import {
|
||||
CheckSquare,
|
||||
ChevronRight,
|
||||
Copy,
|
||||
Edit2,
|
||||
Expand,
|
||||
FolderPlus,
|
||||
@@ -54,6 +55,7 @@ import { SnippetCommandTooltipContent } from './snippets/SnippetCommandTooltipCo
|
||||
import { TERMINAL_SIDE_PANEL_INNER_HEADER_CLASS } from './terminalLayer/terminalSidePanelChrome';
|
||||
import { isNonPrimaryPointer, primaryOnlyDragHandlers } from './ui/primaryOnlyDrag';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip';
|
||||
import { toast } from './ui/toast';
|
||||
|
||||
const toolbarIconButtonClass =
|
||||
'h-7 w-7 shrink-0 flex items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-muted/60 transition-colors disabled:opacity-40 disabled:pointer-events-none';
|
||||
@@ -889,6 +891,20 @@ const ScriptsSidePanelInner: React.FC<ScriptsSidePanelProps> = ({
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleCopySnippetCommand = useCallback((snippet: Snippet) => {
|
||||
if (!snippet.command) return;
|
||||
navigator.clipboard.writeText(snippet.command).then(
|
||||
() => {
|
||||
toast.success(t('scripts.actions.copyCommand.copied'), {
|
||||
title: snippet.label,
|
||||
});
|
||||
},
|
||||
() => {
|
||||
toast.error(t('scripts.actions.copyCommand.failed'));
|
||||
},
|
||||
);
|
||||
}, [t]);
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
const hasAnyContent = snippets.length > 0 || packages.length > 0;
|
||||
@@ -1129,6 +1145,8 @@ const ScriptsSidePanelInner: React.FC<ScriptsSidePanelProps> = ({
|
||||
onClick={() => handleSnippetClick(item.snippet)}
|
||||
onEdit={() => handleEditSnippet(item.snippet)}
|
||||
onDelete={() => handleDeleteSnippet(item.snippet.id)}
|
||||
onCopyCommand={() => handleCopySnippetCommand(item.snippet)}
|
||||
copyCommandLabel={t('scripts.actions.copyCommand')}
|
||||
onRunParallel={onRunScriptOnWorkspace
|
||||
? () => onRunScriptOnWorkspace(item.snippet, 'parallel')
|
||||
: undefined}
|
||||
@@ -1182,6 +1200,8 @@ const ScriptsSidePanelInner: React.FC<ScriptsSidePanelProps> = ({
|
||||
onClick={() => handleSnippetClick(item.row.snippet)}
|
||||
onEdit={() => handleEditSnippet(item.row.snippet)}
|
||||
onDelete={() => handleDeleteSnippet(item.row.snippet.id)}
|
||||
onCopyCommand={() => handleCopySnippetCommand(item.row.snippet)}
|
||||
copyCommandLabel={t('scripts.actions.copyCommand')}
|
||||
onRunParallel={onRunScriptOnWorkspace
|
||||
? () => onRunScriptOnWorkspace(item.row.snippet, 'parallel')
|
||||
: undefined}
|
||||
@@ -1505,6 +1525,8 @@ interface SnippetRowProps {
|
||||
onDelete: () => void;
|
||||
onRunParallel?: () => void;
|
||||
onRunSequential?: () => void;
|
||||
onCopyCommand?: () => void;
|
||||
copyCommandLabel?: string;
|
||||
runParallelLabel?: string;
|
||||
runSequentialLabel?: string;
|
||||
editLabel: string;
|
||||
@@ -1527,6 +1549,8 @@ const SnippetRow = memo<SnippetRowProps>(({
|
||||
onDelete,
|
||||
onRunParallel,
|
||||
onRunSequential,
|
||||
onCopyCommand,
|
||||
copyCommandLabel,
|
||||
runParallelLabel,
|
||||
runSequentialLabel,
|
||||
editLabel,
|
||||
@@ -1604,6 +1628,11 @@ const SnippetRow = memo<SnippetRowProps>(({
|
||||
<Layers className="mr-2 h-4 w-4" /> {runSequentialLabel}
|
||||
</ContextMenuItem>
|
||||
) : null}
|
||||
{onCopyCommand ? (
|
||||
<ContextMenuItem onClick={onCopyCommand}>
|
||||
<Copy className="mr-2 h-4 w-4" /> {copyCommandLabel}
|
||||
</ContextMenuItem>
|
||||
) : null}
|
||||
<ContextMenuItem onClick={onEdit}>
|
||||
<Edit2 className="mr-2 h-4 w-4" /> {editLabel}
|
||||
</ContextMenuItem>
|
||||
|
||||
Reference in new issue
Block a user