@@ -273,6 +297,7 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
isLoading={searchResultsQuery.isLoading}
fileManagerName={fileManagerName}
onCopyPath={copyWorkspacePath}
+ onDeleteEntry={deleteEntry}
onOpenDirectoryInFileManager={openDirectoryInFileManager}
onOpenFileInEditor={openFileInNativeEditor}
onOpenFile={openFile}
@@ -288,6 +313,7 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
expandedDirectories={expandedDirectories}
fileManagerName={fileManagerName}
onCopyPath={copyWorkspacePath}
+ onDeleteEntry={deleteEntry}
onOpenDirectoryInFileManager={openDirectoryInFileManager}
onOpenFileInEditor={openFileInNativeEditor}
onOpenFile={openFile}
@@ -310,6 +336,7 @@ const WorkspaceSearchResults = memo(function WorkspaceSearchResults(props: {
truncated: boolean;
resolvedTheme: "light" | "dark";
onCopyPath: (pathValue: string) => void;
+ onDeleteEntry: (pathValue: string) => void;
onOpenDirectoryInFileManager: (pathValue: string) => void;
onOpenFileInEditor: (pathValue: string) => void;
onOpenFile: (pathValue: string, event?: { metaKey?: boolean; ctrlKey?: boolean }) => void;
@@ -344,6 +371,7 @@ const WorkspaceSearchResults = memo(function WorkspaceSearchResults(props: {
entry={entry}
fileManagerName={props.fileManagerName}
onCopyPath={props.onCopyPath}
+ onDeleteEntry={props.onDeleteEntry}
onOpenDirectoryInFileManager={props.onOpenDirectoryInFileManager}
onOpenFileInEditor={props.onOpenFileInEditor}
onOpenFile={props.onOpenFile}
@@ -367,6 +395,7 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
fileManagerName: string;
resolvedTheme: "light" | "dark";
onCopyPath: (pathValue: string) => void;
+ onDeleteEntry: (pathValue: string) => void;
onOpenDirectoryInFileManager: (pathValue: string) => void;
onOpenFileInEditor: (pathValue: string) => void;
onOpenFile: (pathValue: string, event?: { metaKey?: boolean; ctrlKey?: boolean }) => void;
@@ -387,6 +416,7 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
{ id: "reveal-in-tree", label: "Reveal in tree" },
{ id: "open-in-finder", label: `Open in ${props.fileManagerName}` },
{ id: "copy-path", label: "Copy path" },
+ { id: "delete", label: "Delete", destructive: true },
],
{ x: event.clientX, y: event.clientY },
);
@@ -396,6 +426,8 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
props.onOpenDirectoryInFileManager(props.entry.path);
} else if (clicked === "copy-path") {
props.onCopyPath(props.entry.path);
+ } else if (clicked === "delete") {
+ props.onDeleteEntry(props.entry.path);
}
return;
}
@@ -406,6 +438,7 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
{ id: "open-in-editor", label: "Open in editor" },
{ id: "reveal-in-finder", label: `Reveal in ${props.fileManagerName}` },
{ id: "copy-path", label: "Copy path" },
+ { id: "delete", label: "Delete", destructive: true },
],
{ x: event.clientX, y: event.clientY },
);
@@ -418,6 +451,8 @@ const WorkspaceSearchResultRow = memo(function WorkspaceSearchResultRow(props: {
props.onRevealFileInFileManager(props.entry.path);
} else if (clicked === "copy-path") {
props.onCopyPath(props.entry.path);
+ } else if (clicked === "delete") {
+ props.onDeleteEntry(props.entry.path);
}
},
[isDirectory, props],
@@ -468,6 +503,7 @@ const WorkspaceFileTreeDirectory = memo(function WorkspaceFileTreeDirectory(prop
fileManagerName: string;
resolvedTheme: "light" | "dark";
onCopyPath: (pathValue: string) => void;
+ onDeleteEntry: (pathValue: string) => void;
onOpenDirectoryInFileManager: (pathValue: string) => void;
onOpenFileInEditor: (pathValue: string) => void;
onToggleDirectory: (pathValue: string) => void;
@@ -521,6 +557,7 @@ const WorkspaceFileTreeDirectory = memo(function WorkspaceFileTreeDirectory(prop
fileManagerName={props.fileManagerName}
isExpanded={isExpanded}
onCopyPath={props.onCopyPath}
+ onDeleteEntry={props.onDeleteEntry}
onOpenDirectoryInFileManager={props.onOpenDirectoryInFileManager}
onToggleDirectory={props.onToggleDirectory}
/>
@@ -532,6 +569,7 @@ const WorkspaceFileTreeDirectory = memo(function WorkspaceFileTreeDirectory(prop
expandedDirectories={props.expandedDirectories}
fileManagerName={props.fileManagerName}
onCopyPath={props.onCopyPath}
+ onDeleteEntry={props.onDeleteEntry}
onOpenDirectoryInFileManager={props.onOpenDirectoryInFileManager}
onOpenFileInEditor={props.onOpenFileInEditor}
onOpenFile={props.onOpenFile}
@@ -551,6 +589,7 @@ const WorkspaceFileTreeDirectory = memo(function WorkspaceFileTreeDirectory(prop
entry={entry}
fileManagerName={props.fileManagerName}
onCopyPath={props.onCopyPath}
+ onDeleteEntry={props.onDeleteEntry}
onOpenFileInEditor={props.onOpenFileInEditor}
onOpenFile={props.onOpenFile}
onRevealFileInFileManager={props.onRevealFileInFileManager}
@@ -573,6 +612,7 @@ const WorkspaceDirectoryRow = memo(function WorkspaceDirectoryRow(props: {
fileManagerName: string;
isExpanded: boolean;
onCopyPath: (pathValue: string) => void;
+ onDeleteEntry: (pathValue: string) => void;
onOpenDirectoryInFileManager: (pathValue: string) => void;
onToggleDirectory: (pathValue: string) => void;
}) {
@@ -590,6 +630,7 @@ const WorkspaceDirectoryRow = memo(function WorkspaceDirectoryRow(props: {
},
{ id: "open-in-finder", label: `Open in ${props.fileManagerName}` },
{ id: "copy-path", label: "Copy path" },
+ { id: "delete", label: "Delete", destructive: true },
],
{ x: event.clientX, y: event.clientY },
);
@@ -599,6 +640,8 @@ const WorkspaceDirectoryRow = memo(function WorkspaceDirectoryRow(props: {
props.onOpenDirectoryInFileManager(props.entry.path);
} else if (clicked === "copy-path") {
props.onCopyPath(props.entry.path);
+ } else if (clicked === "delete") {
+ props.onDeleteEntry(props.entry.path);
}
},
[props],
@@ -649,6 +692,7 @@ const WorkspaceFileRow = memo(function WorkspaceFileRow(props: {
fileManagerName: string;
resolvedTheme: "light" | "dark";
onCopyPath: (pathValue: string) => void;
+ onDeleteEntry: (pathValue: string) => void;
onOpenFileInEditor: (pathValue: string) => void;
onOpenFile: (pathValue: string, event?: { metaKey?: boolean; ctrlKey?: boolean }) => void;
onRevealFileInFileManager: (pathValue: string) => void;
@@ -665,6 +709,7 @@ const WorkspaceFileRow = memo(function WorkspaceFileRow(props: {
{ id: "open-in-editor", label: "Open in editor" },
{ id: "reveal-in-finder", label: `Reveal in ${props.fileManagerName}` },
{ id: "copy-path", label: "Copy path" },
+ { id: "delete", label: "Delete", destructive: true },
],
{ x: event.clientX, y: event.clientY },
);
@@ -676,6 +721,8 @@ const WorkspaceFileRow = memo(function WorkspaceFileRow(props: {
props.onRevealFileInFileManager(props.entry.path);
} else if (clicked === "copy-path") {
props.onCopyPath(props.entry.path);
+ } else if (clicked === "delete") {
+ props.onDeleteEntry(props.entry.path);
}
},
[props],
diff --git a/apps/web/src/wsNativeApi.ts b/apps/web/src/wsNativeApi.ts
index c8aa17f32..9015e40b2 100644
--- a/apps/web/src/wsNativeApi.ts
+++ b/apps/web/src/wsNativeApi.ts
@@ -193,6 +193,7 @@ export function createWsNativeApi(): NativeApi {
listDirectory: (input) => transport.request(WS_METHODS.projectsListDirectory, input),
writeFile: (input) => transport.request(WS_METHODS.projectsWriteFile, input),
readFile: (input) => transport.request(WS_METHODS.projectsReadFile, input),
+ deleteEntry: (input) => transport.request(WS_METHODS.projectsDeleteEntry, input),
},
shell: {
openInEditor: (cwd, editor) =>
diff --git a/packages/contracts/src/ipc.ts b/packages/contracts/src/ipc.ts
index f0436fb10..93f3fcff1 100644
--- a/packages/contracts/src/ipc.ts
+++ b/packages/contracts/src/ipc.ts
@@ -24,6 +24,7 @@ import type {
GitStatusResult,
} from "./git";
import type {
+ ProjectDeleteEntryInput,
ProjectListDirectoryInput,
ProjectListDirectoryResult,
ProjectReadFileInput,
@@ -313,6 +314,7 @@ export interface NativeApi {
listDirectory: (input: ProjectListDirectoryInput) => Promise
;
writeFile: (input: ProjectWriteFileInput) => Promise;
readFile: (input: ProjectReadFileInput) => Promise;
+ deleteEntry: (input: ProjectDeleteEntryInput) => Promise;
};
shell: {
openInEditor: (cwd: string, editor: EditorId) => Promise;
diff --git a/packages/contracts/src/project.ts b/packages/contracts/src/project.ts
index c76991790..99f7c0f07 100644
--- a/packages/contracts/src/project.ts
+++ b/packages/contracts/src/project.ts
@@ -83,3 +83,9 @@ export const ProjectReadFileResult = Schema.Struct({
imageDataUrl: Schema.optional(Schema.String),
});
export type ProjectReadFileResult = typeof ProjectReadFileResult.Type;
+
+export const ProjectDeleteEntryInput = Schema.Struct({
+ cwd: TrimmedNonEmptyString,
+ relativePath: TrimmedNonEmptyString.check(Schema.isMaxLength(PROJECT_DIRECTORY_PATH_MAX_LENGTH)),
+});
+export type ProjectDeleteEntryInput = typeof ProjectDeleteEntryInput.Type;
diff --git a/packages/contracts/src/ws.ts b/packages/contracts/src/ws.ts
index aa28f2bbe..3017f1c8c 100644
--- a/packages/contracts/src/ws.ts
+++ b/packages/contracts/src/ws.ts
@@ -58,6 +58,7 @@ import {
SaveProjectEnvironmentVariablesInput,
} from "./environment";
import {
+ ProjectDeleteEntryInput,
ProjectListDirectoryInput,
ProjectReadFileInput,
ProjectSearchEntriesInput,
@@ -93,6 +94,7 @@ export const WS_METHODS = {
projectsListDirectory: "projects.listDirectory",
projectsWriteFile: "projects.writeFile",
projectsReadFile: "projects.readFile",
+ projectsDeleteEntry: "projects.deleteEntry",
// Shell methods
shellOpenInEditor: "shell.openInEditor",
@@ -204,6 +206,7 @@ const WebSocketRequestBody = Schema.Union([
tagRequestBody(WS_METHODS.projectsListDirectory, ProjectListDirectoryInput),
tagRequestBody(WS_METHODS.projectsWriteFile, ProjectWriteFileInput),
tagRequestBody(WS_METHODS.projectsReadFile, ProjectReadFileInput),
+ tagRequestBody(WS_METHODS.projectsDeleteEntry, ProjectDeleteEntryInput),
// Shell methods
tagRequestBody(WS_METHODS.shellOpenInEditor, OpenInEditorInput),