summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-15 13:33:21 -0600
committerAdam <[email protected]>2026-01-19 07:35:52 -0600
commit093a3e7876bfec4bdfc57f580e37875d6fe9e4cb (patch)
tree1eaa32bdc0aa2a71296c2ac68f07d4fc67cd02b7 /packages/app/src
parentf26de6c52f7442762973155c26743d3494fb5887 (diff)
downloadopencode-093a3e7876bfec4bdfc57f580e37875d6fe9e4cb.tar.gz
opencode-093a3e7876bfec4bdfc57f580e37875d6fe9e4cb.zip
feat(app): reset worktree
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/pages/layout.tsx90
1 files changed, 90 insertions, 0 deletions
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
index 8d61f0510..e7acd5f89 100644
--- a/packages/app/src/pages/layout.tsx
+++ b/packages/app/src/pages/layout.tsx
@@ -942,6 +942,30 @@ export default function Layout(props: ParentProps) {
}
}
+ const resetWorkspace = async (directory: string) => {
+ const current = currentProject()
+ if (!current) return
+ if (directory === current.worktree) return
+
+ const result = await globalSDK.client.worktree
+ .reset({ directory: current.worktree, worktreeResetInput: { directory } })
+ .then((x) => x.data)
+ .catch((err) => {
+ showToast({
+ title: "Failed to reset workspace",
+ description: errorMessage(err),
+ })
+ return false
+ })
+
+ if (!result) return
+
+ showToast({
+ title: "Workspace reset",
+ description: "Workspace now matches the default branch.",
+ })
+ }
+
function DialogDeleteWorkspace(props: { directory: string }) {
const name = createMemo(() => getFilename(props.directory))
const [data, setData] = createStore({
@@ -1000,6 +1024,66 @@ export default function Layout(props: ParentProps) {
)
}
+ function DialogResetWorkspace(props: { directory: string }) {
+ const name = createMemo(() => getFilename(props.directory))
+ const [data, setData] = createStore({
+ status: "loading" as "loading" | "ready" | "error",
+ dirty: false,
+ })
+
+ onMount(() => {
+ const current = currentProject()
+ if (!current) {
+ setData({ status: "error", dirty: false })
+ return
+ }
+
+ globalSDK.client.file
+ .status({ directory: props.directory })
+ .then((x) => {
+ const files = x.data ?? []
+ const dirty = files.length > 0
+ setData({ status: "ready", dirty })
+ })
+ .catch(() => {
+ setData({ status: "error", dirty: false })
+ })
+ })
+
+ const handleReset = async () => {
+ await resetWorkspace(props.directory)
+ dialog.close()
+ }
+
+ const description = () => {
+ if (data.status === "loading") return "Checking for unmerged changes..."
+ if (data.status === "error") return "Unable to verify git status."
+ if (!data.dirty) return "No unmerged changes detected."
+ return "Unmerged changes detected in this workspace."
+ }
+
+ return (
+ <Dialog title="Reset workspace">
+ <div class="flex flex-col gap-4 px-2.5 pb-3">
+ <div class="flex flex-col gap-1">
+ <span class="text-14-regular text-text-strong">Reset workspace "{name()}"?</span>
+ <span class="text-12-regular text-text-weak">
+ {description()} This will reset the workspace to match the default branch.
+ </span>
+ </div>
+ <div class="flex justify-end gap-2">
+ <Button variant="ghost" size="large" onClick={() => dialog.close()}>
+ Cancel
+ </Button>
+ <Button variant="primary" size="large" disabled={data.status === "loading"} onClick={handleReset}>
+ Reset workspace
+ </Button>
+ </div>
+ </div>
+ </Dialog>
+ )
+ }
+
createEffect(
on(
() => ({ ready: pageReady(), dir: params.dir, id: params.id }),
@@ -1393,6 +1477,12 @@ export default function Layout(props: ParentProps) {
</DropdownMenu.Item>
<DropdownMenu.Item
disabled={local()}
+ onSelect={() => dialog.show(() => <DialogResetWorkspace directory={props.directory} />)}
+ >
+ <DropdownMenu.ItemLabel>Reset workspace</DropdownMenu.ItemLabel>
+ </DropdownMenu.Item>
+ <DropdownMenu.Item
+ disabled={local()}
onSelect={() => dialog.show(() => <DialogDeleteWorkspace directory={props.directory} />)}
>
<DropdownMenu.ItemLabel>Delete workspace</DropdownMenu.ItemLabel>