@cerbur/clutch-dsh-worktree 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -6
- package/lib/client/WorktreeModeAction.d.ts +4 -3
- package/lib/client/WorktreeModeAction.d.ts.map +1 -1
- package/lib/client/WorktreeModeAction.js +3 -3
- package/lib/client/WorktreeModeAction.js.map +1 -1
- package/lib/client/WorktreeSurface.d.ts +4 -3
- package/lib/client/WorktreeSurface.d.ts.map +1 -1
- package/lib/client/WorktreeSurface.js +142 -63
- package/lib/client/WorktreeSurface.js.map +1 -1
- package/lib/client/entry.d.ts +6 -0
- package/lib/client/entry.d.ts.map +1 -1
- package/lib/client/entry.js +5 -1
- package/lib/client/entry.js.map +1 -1
- package/lib/client/locales.d.ts +149 -0
- package/lib/client/locales.d.ts.map +1 -0
- package/lib/client/locales.js +148 -0
- package/lib/client/locales.js.map +1 -0
- package/lib/client/sidebar-overlay-geometry.js +1 -1
- package/lib/client/sidebar-overlay-geometry.js.map +1 -1
- package/lib/client/worktree-connection.d.ts.map +1 -1
- package/lib/client/worktree-connection.js +6 -5
- package/lib/client/worktree-connection.js.map +1 -1
- package/lib/client/worktree-error-copy.d.ts +7 -0
- package/lib/client/worktree-error-copy.d.ts.map +1 -0
- package/lib/client/worktree-error-copy.js +44 -0
- package/lib/client/worktree-error-copy.js.map +1 -0
- package/lib/client/worktree-view.d.ts +1 -0
- package/lib/client/worktree-view.d.ts.map +1 -1
- package/lib/client/worktree-view.js +15 -5
- package/lib/client/worktree-view.js.map +1 -1
- package/lib/client.js +413 -97
- package/lib/client.js.map +1 -1
- package/package.json +4 -1
|
@@ -4,8 +4,15 @@ import { Button, IconArchiveOutline20, IconBranchOutline16, IconChevronDownOutli
|
|
|
4
4
|
import { openWorktreeSession } from './navigation.js';
|
|
5
5
|
import { useSidebarOverlayGeometry } from './sidebar-overlay-geometry.js';
|
|
6
6
|
import { effectiveViewMode, unboundSessionIds, workspaceSessionIds } from './view-mode.js';
|
|
7
|
+
import { formatWorktreeViewError } from './worktree-error-copy.js';
|
|
7
8
|
import { executeWorktreeAction, createDefaultWorktreeName, filterArchivedSessionIds, loadWorktreeViews, selectDefaultBaseBranch, stableWorkspaceIds, toWorktreeViewError, WorktreeSessionBindingError, } from './worktree-view.js';
|
|
8
9
|
import styles from './worktree.css';
|
|
10
|
+
function toNativeWorktreeViewError(error) {
|
|
11
|
+
const viewError = toWorktreeViewError(error);
|
|
12
|
+
if (typeof error === 'object' && error !== null)
|
|
13
|
+
return viewError;
|
|
14
|
+
return { ...viewError, message: String(error) };
|
|
15
|
+
}
|
|
9
16
|
const EMPTY_READ_STATE = { status: 'idle', views: [] };
|
|
10
17
|
function useStableWorkspaceIds(workspaces) {
|
|
11
18
|
const next = workspaces.map((workspace) => workspace.workspaceId);
|
|
@@ -46,17 +53,17 @@ function workspaceMatches(workspace, view, sessions, query) {
|
|
|
46
53
|
return view.bindings.some((binding) => includesText(sessionLabel(binding.sessionId, sessions), query));
|
|
47
54
|
}
|
|
48
55
|
/** Workspace row using the native DSH menu, fixed action column, and drag contract. */
|
|
49
|
-
function WorktreeWorkspaceRow({ workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange, }) {
|
|
56
|
+
function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange, }) {
|
|
50
57
|
const workspaceMenuItems = [
|
|
51
58
|
{
|
|
52
59
|
id: 'rename',
|
|
53
|
-
label: '
|
|
60
|
+
label: t('workspace.rename'),
|
|
54
61
|
icon: _jsx(IconEditOutline16, {}),
|
|
55
62
|
disabled: actionPending,
|
|
56
63
|
},
|
|
57
64
|
{
|
|
58
65
|
id: 'delete',
|
|
59
|
-
label: '
|
|
66
|
+
label: t('workspace.delete'),
|
|
60
67
|
icon: _jsx(IconTrashOutline16, {}),
|
|
61
68
|
danger: true,
|
|
62
69
|
disabled: actionPending,
|
|
@@ -84,7 +91,9 @@ function WorktreeWorkspaceRow({ workspace, expanded, actionPending, menuOpen, dr
|
|
|
84
91
|
return;
|
|
85
92
|
event.preventDefault();
|
|
86
93
|
drag.drop(rowHalf(event));
|
|
87
|
-
}, children: [_jsx("button", { type: "button", className: `${styles.disclosureButton} ${styles.workspaceDisclosure}`, "aria-label":
|
|
94
|
+
}, children: [_jsx("button", { type: "button", className: `${styles.disclosureButton} ${styles.workspaceDisclosure}`, "aria-label": t(expanded ? 'workspace.collapse' : 'workspace.expand', {
|
|
95
|
+
name: workspace.title,
|
|
96
|
+
}), "aria-expanded": expanded, onClick: (event) => {
|
|
88
97
|
event.stopPropagation();
|
|
89
98
|
onToggle();
|
|
90
99
|
}, children: expanded ? (_jsx(IconChevronDownOutline14, { size: 18 })) : (_jsx(IconChevronRightOutline14, { size: 18 })) }), _jsx("span", { className: styles.workspaceIcon, "aria-hidden": "true", children: expanded ? _jsx(IconFolderOpen16, {}) : _jsx(IconFolderClose16, {}) }), _jsx("span", { className: styles.workspaceTitle, children: workspace.title }), _jsxs("span", { className: `${styles.treeActionSlot} ${styles.workspaceActions}`, children: [_jsx("span", { className: styles.menuAction, children: _jsx(Menu, { open: menuOpen, onClose: () => {
|
|
@@ -95,27 +104,44 @@ function WorktreeWorkspaceRow({ workspace, expanded, actionPending, menuOpen, dr
|
|
|
95
104
|
onRename();
|
|
96
105
|
if (id === 'delete')
|
|
97
106
|
onDelete();
|
|
98
|
-
}, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: styles.iconButton, "data-workspace-menu": true, "aria-label":
|
|
107
|
+
}, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: styles.iconButton, "data-workspace-menu": true, "aria-label": t('workspace.options', { name: workspace.title }), onClick: (event) => {
|
|
99
108
|
event.stopPropagation();
|
|
100
109
|
onMenuOpenChange(!menuOpen);
|
|
101
|
-
}, children: _jsx(IconEllipsisOutline16, {}) })) }) }), _jsx("button", { type: "button", className: styles.iconButton, "data-add-worktree": true, "aria-label":
|
|
110
|
+
}, children: _jsx(IconEllipsisOutline16, {}) })) }) }), _jsx("button", { type: "button", className: styles.iconButton, "data-add-worktree": true, "aria-label": t('workspace.addWorktree', { name: workspace.title }), onClick: (event) => {
|
|
102
111
|
event.stopPropagation();
|
|
103
112
|
onCreateWorktree();
|
|
104
113
|
}, children: _jsx(IconPlusOutline16, {}) })] })] }));
|
|
105
114
|
}
|
|
106
115
|
/** Shared Main/Worktree group row with parameterized icon, state, and actions. */
|
|
107
|
-
function WorktreeGroupRow({ kind, label, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, }) {
|
|
116
|
+
function WorktreeGroupRow({ t, kind, label, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, }) {
|
|
108
117
|
const main = kind === 'main';
|
|
109
|
-
return (_jsxs("div", { className: styles.worktreeRow, "data-main-group": main ? 'true' : undefined, "data-main-expanded": main ? String(expanded) : undefined, onClick: onToggle, children: [_jsx("button", { type: "button", className: `${styles.disclosureButton} ${styles.worktreeDisclosure}`, "aria-label":
|
|
118
|
+
return (_jsxs("div", { className: styles.worktreeRow, "data-main-group": main ? 'true' : undefined, "data-main-expanded": main ? String(expanded) : undefined, "data-menu-open": menu?.open ? 'true' : undefined, onClick: onToggle, children: [_jsx("button", { type: "button", className: `${styles.disclosureButton} ${styles.worktreeDisclosure}`, "aria-label": t(expanded ? 'worktree.collapse' : 'worktree.expand', { name: label }), "aria-expanded": expanded, onClick: (event) => {
|
|
110
119
|
event.stopPropagation();
|
|
111
120
|
onToggle();
|
|
112
|
-
}, children: expanded ? (_jsx(IconChevronDownOutline14, { size: 18 })) : (_jsx(IconChevronRightOutline14, { size: 18 })) }), _jsx("span", { className: styles.worktreeIcon, "aria-hidden": "true", children: icon }), state !== undefined && stateLabel !== undefined && (_jsx("span", { className: styles.worktreeState, role: "img", "aria-label": stateLabel, title: stateLabel, children: _jsx(StateDot, { state: state }) })), _jsx("span", { className: styles.worktreeLabel, children: label }),
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
121
|
+
}, children: expanded ? (_jsx(IconChevronDownOutline14, { size: 18 })) : (_jsx(IconChevronRightOutline14, { size: 18 })) }), _jsx("span", { className: styles.worktreeIcon, "aria-hidden": "true", children: icon }), state !== undefined && stateLabel !== undefined && (_jsx("span", { className: styles.worktreeState, role: "img", "aria-label": stateLabel, title: stateLabel, children: _jsx(StateDot, { state: state }) })), _jsx("span", { className: styles.worktreeLabel, children: label }), _jsxs("span", { className: styles.treeActionSlot, children: [menu !== undefined && (_jsx("span", { className: styles.menuAction, children: _jsx(Menu, { open: menu.open, onClose: () => {
|
|
122
|
+
menu.onOpenChange(false);
|
|
123
|
+
}, items: [
|
|
124
|
+
{
|
|
125
|
+
id: 'remove',
|
|
126
|
+
label: t('worktree.remove'),
|
|
127
|
+
icon: _jsx(IconTrashOutline16, {}),
|
|
128
|
+
danger: true,
|
|
129
|
+
disabled: menu.disabled,
|
|
130
|
+
},
|
|
131
|
+
], onSelect: (id) => {
|
|
132
|
+
menu.onOpenChange(false);
|
|
133
|
+
if (id === 'remove')
|
|
134
|
+
menu.onRemove();
|
|
135
|
+
}, portal: true, closeOnPointerLeave: true, anchor: _jsx("button", { type: "button", className: styles.iconButton, "data-worktree-menu": true, "aria-label": t('worktree.options', { name: menu.label }), onClick: (event) => {
|
|
136
|
+
event.stopPropagation();
|
|
137
|
+
menu.onOpenChange(!menu.open);
|
|
138
|
+
}, children: _jsx(IconEllipsisOutline16, {}) }) }) })), onCreateSession !== undefined && (_jsx("button", { type: "button", className: styles.iconButton, "data-add-main-session": main ? 'true' : undefined, "data-add-session": main ? undefined : 'true', "aria-label": t('worktree.addSession', { name: workspaceTitle }), onClick: (event) => {
|
|
139
|
+
event.stopPropagation();
|
|
140
|
+
onCreateSession();
|
|
141
|
+
}, children: _jsx(IconPlusOutline16, {}) }))] })] }));
|
|
116
142
|
}
|
|
117
143
|
/** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
|
|
118
|
-
function WorktreeSessionRow({ sessionId, label, drag, actionPending, onOpen, onRename, onFork, onArchive, }) {
|
|
144
|
+
function WorktreeSessionRow({ t, sessionId, label, drag, actionPending, onOpen, onRename, onFork, onArchive, }) {
|
|
119
145
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
120
146
|
const markerClass = drag.marker === 'before'
|
|
121
147
|
? styles.dropBefore
|
|
@@ -125,19 +151,19 @@ function WorktreeSessionRow({ sessionId, label, drag, actionPending, onOpen, onR
|
|
|
125
151
|
const sessionMenuItems = [
|
|
126
152
|
{
|
|
127
153
|
id: 'rename',
|
|
128
|
-
label: '
|
|
154
|
+
label: t('session.rename'),
|
|
129
155
|
icon: _jsx(IconEditOutline16, {}),
|
|
130
156
|
disabled: onRename === undefined || actionPending,
|
|
131
157
|
},
|
|
132
158
|
{
|
|
133
159
|
id: 'fork',
|
|
134
|
-
label: '
|
|
160
|
+
label: t('session.fork'),
|
|
135
161
|
icon: _jsx(IconBranchOutline16, {}),
|
|
136
162
|
disabled: onFork === undefined || actionPending,
|
|
137
163
|
},
|
|
138
164
|
{
|
|
139
165
|
id: 'archive',
|
|
140
|
-
label: '
|
|
166
|
+
label: t('session.archive'),
|
|
141
167
|
icon: _jsx(IconArchiveOutline20, { size: 16 }),
|
|
142
168
|
disabled: onArchive === undefined || actionPending,
|
|
143
169
|
},
|
|
@@ -167,15 +193,15 @@ function WorktreeSessionRow({ sessionId, label, drag, actionPending, onOpen, onR
|
|
|
167
193
|
onFork?.(sessionId);
|
|
168
194
|
if (id === 'archive')
|
|
169
195
|
onArchive?.(sessionId);
|
|
170
|
-
}, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: styles.iconButton, "data-session-menu": true, "aria-label":
|
|
196
|
+
}, portal: true, closeOnPointerLeave: true, anchor: (_jsx("button", { type: "button", className: styles.iconButton, "data-session-menu": true, "aria-label": t('session.options', { name: label }), onClick: (event) => {
|
|
171
197
|
event.stopPropagation();
|
|
172
198
|
setMenuOpen((current) => !current);
|
|
173
199
|
}, children: _jsx(IconEllipsisOutline16, {}) })) }) })] }));
|
|
174
200
|
}
|
|
175
|
-
function WorktreeSessionGroup({ groupKey, sessionIds, workspaceId, expanded, actionPending, sessions, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive, }) {
|
|
201
|
+
function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, expanded, actionPending, sessions, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive, }) {
|
|
176
202
|
const visibleSessionIds = expanded ? sessionIds : sessionIds.slice(0, 5);
|
|
177
203
|
const sameGroupDrag = dragState?.groupKey === groupKey;
|
|
178
|
-
return (_jsxs(_Fragment, { children: [visibleSessionIds.map((sessionId) => (_jsx(WorktreeSessionRow, { sessionId: sessionId, label: sessionLabel(sessionId, sessions), drag: {
|
|
204
|
+
return (_jsxs(_Fragment, { children: [visibleSessionIds.map((sessionId) => (_jsx(WorktreeSessionRow, { t: t, sessionId: sessionId, label: sessionLabel(sessionId, sessions), drag: {
|
|
179
205
|
active: sameGroupDrag,
|
|
180
206
|
marker: sameGroupDrag && dragState.over?.sessionId === sessionId
|
|
181
207
|
? dragState.over.half
|
|
@@ -202,13 +228,15 @@ function WorktreeSessionGroup({ groupKey, sessionIds, workspaceId, expanded, act
|
|
|
202
228
|
},
|
|
203
229
|
}, actionPending: actionPending, onOpen: () => {
|
|
204
230
|
onOpen(sessionId);
|
|
205
|
-
}, onRename: onRename, onFork: onFork, onArchive: onArchive }, `${groupKey}:${sessionId}`))), sessionIds.length > 5 && (_jsx("button", { type: "button", className: styles.sessionOverflowButton, "aria-expanded": expanded, onClick: onToggleExpanded, children: expanded
|
|
231
|
+
}, onRename: onRename, onFork: onFork, onArchive: onArchive }, `${groupKey}:${sessionId}`))), sessionIds.length > 5 && (_jsx("button", { type: "button", className: styles.sessionOverflowButton, "aria-expanded": expanded, onClick: onToggleExpanded, children: expanded
|
|
232
|
+
? t('session.collapse')
|
|
233
|
+
: t('session.expandMore', { count: sessionIds.length - 5 }) }))] }));
|
|
206
234
|
}
|
|
207
235
|
/**
|
|
208
236
|
* Peer Worktree navigation surface. It keeps the original DSH Workspace mode
|
|
209
237
|
* intact and renders a browser-local Workspace → Worktree → Session projection.
|
|
210
238
|
*/
|
|
211
|
-
export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, available, manager, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession, }) {
|
|
239
|
+
export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession, }) {
|
|
212
240
|
const preferredMode = useStore((state) => state.viewMode);
|
|
213
241
|
const mode = effectiveViewMode(preferredMode, available && manager !== undefined);
|
|
214
242
|
const sessions = useSessions((state) => state);
|
|
@@ -221,6 +249,8 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
221
249
|
const [expandedWorktrees, setExpandedWorktrees] = useState({});
|
|
222
250
|
const [worktreeModalWorkspaceId, setWorktreeModalWorkspaceId] = useState();
|
|
223
251
|
const [openWorkspaceMenuId, setOpenWorkspaceMenuId] = useState();
|
|
252
|
+
const [openWorktreeMenuId, setOpenWorktreeMenuId] = useState();
|
|
253
|
+
const [worktreeRemoval, setWorktreeRemoval] = useState();
|
|
224
254
|
const [selectedBranch, setSelectedBranch] = useState('');
|
|
225
255
|
const [newBranch, setNewBranch] = useState('');
|
|
226
256
|
const [pendingSessionBinding, setPendingSessionBinding] = useState();
|
|
@@ -328,7 +358,11 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
328
358
|
if (workspaceRenameBlocked || target === undefined)
|
|
329
359
|
return;
|
|
330
360
|
if (renameWorkspace === undefined) {
|
|
331
|
-
setWorkspaceRenameError(
|
|
361
|
+
setWorkspaceRenameError({
|
|
362
|
+
code: 'WORKSPACE_RENAME_UNAVAILABLE',
|
|
363
|
+
message: '',
|
|
364
|
+
retryable: true,
|
|
365
|
+
});
|
|
332
366
|
return;
|
|
333
367
|
}
|
|
334
368
|
setWorkspaceRenamePending(true);
|
|
@@ -338,7 +372,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
338
372
|
setWorkspaceRenameTarget(undefined);
|
|
339
373
|
}
|
|
340
374
|
catch (error) {
|
|
341
|
-
setWorkspaceRenameError(
|
|
375
|
+
setWorkspaceRenameError(toNativeWorktreeViewError(error));
|
|
342
376
|
}
|
|
343
377
|
finally {
|
|
344
378
|
setWorkspaceRenamePending(false);
|
|
@@ -359,7 +393,11 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
359
393
|
if (target === undefined || workspaceDeletePending)
|
|
360
394
|
return;
|
|
361
395
|
if (deleteWorkspace === undefined) {
|
|
362
|
-
setWorkspaceDeleteError(
|
|
396
|
+
setWorkspaceDeleteError({
|
|
397
|
+
code: 'WORKSPACE_DELETE_UNAVAILABLE',
|
|
398
|
+
message: '',
|
|
399
|
+
retryable: true,
|
|
400
|
+
});
|
|
363
401
|
return;
|
|
364
402
|
}
|
|
365
403
|
setWorkspaceDeletePending(true);
|
|
@@ -369,7 +407,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
369
407
|
setWorkspaceDeleteTarget(undefined);
|
|
370
408
|
}
|
|
371
409
|
catch (error) {
|
|
372
|
-
setWorkspaceDeleteError(
|
|
410
|
+
setWorkspaceDeleteError(toNativeWorktreeViewError(error));
|
|
373
411
|
}
|
|
374
412
|
finally {
|
|
375
413
|
setWorkspaceDeletePending(false);
|
|
@@ -399,7 +437,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
399
437
|
if (insertWorkspaceBefore === undefined) {
|
|
400
438
|
setActionError({
|
|
401
439
|
code: 'WORKSPACE_ORDER_UNAVAILABLE',
|
|
402
|
-
message: '
|
|
440
|
+
message: '',
|
|
403
441
|
retryable: true,
|
|
404
442
|
});
|
|
405
443
|
return;
|
|
@@ -432,7 +470,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
432
470
|
if (insertSessionBefore === undefined) {
|
|
433
471
|
setActionError({
|
|
434
472
|
code: 'SESSION_ORDER_UNAVAILABLE',
|
|
435
|
-
message: '
|
|
473
|
+
message: '',
|
|
436
474
|
retryable: true,
|
|
437
475
|
});
|
|
438
476
|
return;
|
|
@@ -459,7 +497,11 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
459
497
|
if (target === undefined || title.length === 0 || sessionRenamePending)
|
|
460
498
|
return;
|
|
461
499
|
if (renameSession === undefined) {
|
|
462
|
-
setSessionRenameError(
|
|
500
|
+
setSessionRenameError({
|
|
501
|
+
code: 'SESSION_RENAME_UNAVAILABLE',
|
|
502
|
+
message: '',
|
|
503
|
+
retryable: true,
|
|
504
|
+
});
|
|
463
505
|
return;
|
|
464
506
|
}
|
|
465
507
|
setSessionRenamePending(true);
|
|
@@ -469,7 +511,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
469
511
|
setSessionRenameTarget(undefined);
|
|
470
512
|
}
|
|
471
513
|
catch (error) {
|
|
472
|
-
setSessionRenameError(
|
|
514
|
+
setSessionRenameError(toNativeWorktreeViewError(error));
|
|
473
515
|
}
|
|
474
516
|
finally {
|
|
475
517
|
setSessionRenamePending(false);
|
|
@@ -532,14 +574,18 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
532
574
|
input,
|
|
533
575
|
});
|
|
534
576
|
if (createdWorktree === undefined) {
|
|
535
|
-
throw
|
|
577
|
+
throw {
|
|
578
|
+
code: 'WORKTREE_RECORD_MISSING',
|
|
579
|
+
message: '',
|
|
580
|
+
retryable: true,
|
|
581
|
+
};
|
|
536
582
|
}
|
|
537
583
|
setWorktreeModalWorkspaceId(undefined);
|
|
538
584
|
if (createSessionCallback === undefined) {
|
|
539
585
|
await refresh();
|
|
540
586
|
setActionError({
|
|
541
|
-
code: '
|
|
542
|
-
message: '
|
|
587
|
+
code: 'WORKTREE_CREATED_SESSION_UNAVAILABLE',
|
|
588
|
+
message: '',
|
|
543
589
|
retryable: true,
|
|
544
590
|
});
|
|
545
591
|
return;
|
|
@@ -571,7 +617,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
571
617
|
if (createSessionCallback === undefined) {
|
|
572
618
|
setActionError({
|
|
573
619
|
code: 'SESSION_CREATE_UNAVAILABLE',
|
|
574
|
-
message: '
|
|
620
|
+
message: '',
|
|
575
621
|
retryable: true,
|
|
576
622
|
});
|
|
577
623
|
return;
|
|
@@ -624,31 +670,31 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
624
670
|
if (mode !== 'worktree')
|
|
625
671
|
return null;
|
|
626
672
|
const visibleWorkspaces = workspaces.items.filter((workspace) => workspaceMatches(workspace, viewByWorkspace.get(workspace.workspaceId), sessions, query));
|
|
627
|
-
return (_jsxs("aside", { ref: ref, className: styles.surface, "data-worktree-surface": true, "data-collapsed": collapsed || undefined, "aria-label":
|
|
673
|
+
return (_jsxs("aside", { ref: ref, className: styles.surface, "data-worktree-surface": true, "data-collapsed": collapsed || undefined, "aria-label": t('mode.navigation'), style: {
|
|
628
674
|
width: `${width}px`,
|
|
629
675
|
...(bounds.ready
|
|
630
676
|
? { top: `${bounds.top}px`, height: `${bounds.height}px` }
|
|
631
677
|
: { height: '0px', visibility: 'hidden' }),
|
|
632
|
-
}, children: [_jsxs("div", { className: styles.wideContent, children: [_jsxs("header", { className: styles.header, children: [_jsx("span", { className: styles.title, children:
|
|
678
|
+
}, children: [_jsxs("div", { className: styles.wideContent, children: [_jsxs("header", { className: styles.header, children: [_jsx("span", { className: styles.title, children: t('worktree.title') }), _jsx("button", { type: "button", className: styles.closeButton, "aria-label": t('mode.exit'), onClick: () => {
|
|
633
679
|
actions.setViewMode('workspace-session');
|
|
634
|
-
}, children: _jsx(IconCloseOutline16, {}) })] }), _jsxs("div", { className: styles.searchRow, children: [_jsx("span", { className: styles.searchIcon, "aria-hidden": "true", children: _jsx(IconSearchOutline16, {}) }), _jsx("input", { className: styles.searchInput, "aria-label":
|
|
680
|
+
}, children: _jsx(IconCloseOutline16, {}) })] }), _jsxs("div", { className: styles.searchRow, children: [_jsx("span", { className: styles.searchIcon, "aria-hidden": "true", children: _jsx(IconSearchOutline16, {}) }), _jsx("input", { className: styles.searchInput, "aria-label": t('workspace.search'), placeholder: t('workspace.search'), value: searchQuery, onChange: (event) => {
|
|
635
681
|
setSearchQuery(event.currentTarget.value);
|
|
636
|
-
} }), _jsx("button", { type: "button", className: styles.iconButton, "aria-label":
|
|
682
|
+
} }), _jsx("button", { type: "button", className: styles.iconButton, "aria-label": t('workspace.add'), onClick: () => {
|
|
637
683
|
if (createWorkspace !== undefined)
|
|
638
684
|
void runMutation(createWorkspace);
|
|
639
|
-
}, children: _jsx(IconPlusOutline16, {}) })] }), _jsxs("div", { className: styles.content, tabIndex: 0, children: [actionError !== undefined && (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: actionError
|
|
685
|
+
}, children: _jsx(IconPlusOutline16, {}) })] }), _jsxs("div", { className: styles.content, tabIndex: 0, children: [actionError !== undefined && (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(actionError, t) }), pendingSessionBinding !== undefined && (_jsxs("div", { className: styles.recoveryActions, children: [_jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending, onClick: () => {
|
|
640
686
|
void retrySessionBinding();
|
|
641
|
-
}, children:
|
|
687
|
+
}, children: t('action.retryBinding') }), _jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending, onClick: () => {
|
|
642
688
|
const sessionId = pendingSessionBinding.sessionId;
|
|
643
689
|
setPendingSessionBinding(undefined);
|
|
644
690
|
setActionError(undefined);
|
|
645
691
|
openSession(sessionId);
|
|
646
|
-
}, children:
|
|
692
|
+
}, children: t('action.openCreatedSession') })] })), actionError.retryable && (_jsx("button", { type: "button", className: styles.retryButton, onClick: () => {
|
|
647
693
|
setActionError(undefined);
|
|
648
694
|
void refresh();
|
|
649
|
-
}, children:
|
|
695
|
+
}, children: t('action.retry') }))] })), readState.status === 'loading' && (_jsx("p", { className: styles.message, children: t('status.loading') })), readState.status === 'error' && readState.error !== undefined ? (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(readState.error, t) }), _jsx("button", { type: "button", className: styles.retryButton, onClick: () => {
|
|
650
696
|
void refresh();
|
|
651
|
-
}, children:
|
|
697
|
+
}, children: t('action.retry') })] })) : readState.status === 'ready' ? (_jsx("div", { className: styles.workspaceList, children: visibleWorkspaces.length === 0 ? (_jsx("p", { className: styles.empty, children: t('workspace.noMatches') })) : (visibleWorkspaces.map((workspace) => {
|
|
652
698
|
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
653
699
|
const expanded = expandedWorkspaces[workspace.workspaceId] !== false;
|
|
654
700
|
const workspaceMatchesQuery = includesText(workspace.title, query);
|
|
@@ -663,7 +709,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
663
709
|
const mainExpanded = expandedMains[workspace.workspaceId] !== false;
|
|
664
710
|
const mainGroupKey = `main:${workspace.workspaceId}`;
|
|
665
711
|
const worktrees = view?.worktrees ?? [];
|
|
666
|
-
return (_jsxs("section", { className: styles.workspaceGroup, "data-workspace-id": workspace.workspaceId, children: [_jsx(WorktreeWorkspaceRow, { workspace: workspace, expanded: expanded, actionPending: actionPending, menuOpen: openWorkspaceMenuId === workspace.workspaceId, drag: {
|
|
712
|
+
return (_jsxs("section", { className: styles.workspaceGroup, "data-workspace-id": workspace.workspaceId, children: [_jsx(WorktreeWorkspaceRow, { t: t, workspace: workspace, expanded: expanded, actionPending: actionPending, menuOpen: openWorkspaceMenuId === workspace.workspaceId, drag: {
|
|
667
713
|
active: workspaceDrag !== undefined,
|
|
668
714
|
marker: workspaceDrag?.over?.workspaceId === workspace.workspaceId
|
|
669
715
|
? workspaceDrag.over.half
|
|
@@ -707,13 +753,13 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
707
753
|
openWorkspaceDelete(workspace);
|
|
708
754
|
}, onMenuOpenChange: (open) => {
|
|
709
755
|
setOpenWorkspaceMenuId(open ? workspace.workspaceId : undefined);
|
|
710
|
-
} }), expanded && (_jsxs("div", { className: styles.treeChildren, children: [_jsx(WorktreeGroupRow, { kind: "main", label:
|
|
756
|
+
} }), expanded && (_jsxs("div", { className: styles.treeChildren, children: [_jsx(WorktreeGroupRow, { t: t, kind: "main", label: t('worktree.main'), expanded: mainExpanded, icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, onToggle: () => {
|
|
711
757
|
toggleMain(workspace.workspaceId);
|
|
712
758
|
}, onCreateSession: createMainSession === undefined
|
|
713
759
|
? undefined
|
|
714
760
|
: () => {
|
|
715
761
|
createMainSession(workspace.workspaceId);
|
|
716
|
-
} }), mainExpanded && (_jsx(WorktreeSessionGroup, { groupKey: mainGroupKey, sessionIds: visibleMainSessionIds, workspaceId: workspace.workspaceId, expanded: expandedSessionGroups[mainGroupKey] === true, actionPending: actionPending, sessions: sessions, dragState: sessionDrag, onToggleExpanded: () => {
|
|
762
|
+
} }), mainExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: mainGroupKey, sessionIds: visibleMainSessionIds, workspaceId: workspace.workspaceId, expanded: expandedSessionGroups[mainGroupKey] === true, actionPending: actionPending, sessions: sessions, dragState: sessionDrag, onToggleExpanded: () => {
|
|
717
763
|
setExpandedSessionGroups((current) => ({
|
|
718
764
|
...current,
|
|
719
765
|
[mainGroupKey]: current[mainGroupKey] !== true,
|
|
@@ -731,7 +777,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
731
777
|
sessionDropCommitted.current = false;
|
|
732
778
|
}, onCommitDrag: commitSessionDrag, onOpen: (sessionId) => {
|
|
733
779
|
openWorktreeSession({ open: openSession }, sessionId);
|
|
734
|
-
}, onRename: renameSession === undefined ? undefined : openSessionRename, onFork: forkSession, onArchive: archiveSession === undefined ? undefined : archiveWorktreeSession })), worktrees.length === 0 && (_jsx("p", { className: styles.emptyNested, children:
|
|
780
|
+
}, onRename: renameSession === undefined ? undefined : openSessionRename, onFork: forkSession, onArchive: archiveSession === undefined ? undefined : archiveWorktreeSession })), worktrees.length === 0 && (_jsx("p", { className: styles.emptyNested, children: t('worktree.noWorktrees') })), worktrees.map((record) => {
|
|
735
781
|
const worktreeSessionIds = filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds);
|
|
736
782
|
const worktreeMatchesQuery = workspaceMatchesQuery ||
|
|
737
783
|
includesText(record.branch, query) ||
|
|
@@ -750,12 +796,12 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
750
796
|
? 'error'
|
|
751
797
|
: 'done';
|
|
752
798
|
const stateLabel = record.status === 'removed'
|
|
753
|
-
? '
|
|
799
|
+
? t('worktree.detached')
|
|
754
800
|
: record.health === 'repair'
|
|
755
|
-
? '
|
|
756
|
-
: '
|
|
801
|
+
? t('worktree.repair')
|
|
802
|
+
: t('worktree.ready');
|
|
757
803
|
const worktreeExpanded = expandedWorktrees[record.worktreeId] !== false;
|
|
758
|
-
return (_jsxs("div", { className: styles.worktreeGroup, "data-worktree-id": record.worktreeId, children: [_jsx(WorktreeGroupRow, { kind: "worktree", label: record.branch, expanded: worktreeExpanded, icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, state: state, stateLabel: stateLabel, onToggle: () => {
|
|
804
|
+
return (_jsxs("div", { className: styles.worktreeGroup, "data-worktree-id": record.worktreeId, children: [_jsx(WorktreeGroupRow, { t: t, kind: "worktree", label: record.branch, expanded: worktreeExpanded, icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, state: state, stateLabel: stateLabel, onToggle: () => {
|
|
759
805
|
toggleWorktree(record.worktreeId);
|
|
760
806
|
}, onCreateSession: record.status === 'active'
|
|
761
807
|
? () => {
|
|
@@ -765,7 +811,20 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
765
811
|
cwd: record.absolutePath,
|
|
766
812
|
});
|
|
767
813
|
}
|
|
768
|
-
: undefined
|
|
814
|
+
: undefined, menu: record.status === 'active'
|
|
815
|
+
? {
|
|
816
|
+
open: openWorktreeMenuId === record.worktreeId,
|
|
817
|
+
label: record.branch,
|
|
818
|
+
disabled: actionPending,
|
|
819
|
+
onOpenChange: (open) => {
|
|
820
|
+
setOpenWorktreeMenuId(open ? record.worktreeId : undefined);
|
|
821
|
+
},
|
|
822
|
+
onRemove: () => {
|
|
823
|
+
setWorktreeRemoval(record);
|
|
824
|
+
setActionError(undefined);
|
|
825
|
+
},
|
|
826
|
+
}
|
|
827
|
+
: undefined }), worktreeExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: worktreeGroupKey, sessionIds: visibleWorktreeSessionIds, workspaceId: workspace.workspaceId, expanded: expandedSessionGroups[worktreeGroupKey] === true, actionPending: actionPending, sessions: sessions, dragState: sessionDrag, onToggleExpanded: () => {
|
|
769
828
|
setExpandedSessionGroups((current) => ({
|
|
770
829
|
...current,
|
|
771
830
|
[worktreeGroupKey]: current[worktreeGroupKey] !== true,
|
|
@@ -787,11 +846,11 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
787
846
|
? undefined
|
|
788
847
|
: archiveWorktreeSession }))] }, record.worktreeId));
|
|
789
848
|
})] }))] }, workspace.workspaceId));
|
|
790
|
-
})) })) : null] })] }), _jsx("div", { className: styles.railContent, children: _jsx("button", { type: "button", className: styles.railButton, "aria-label":
|
|
849
|
+
})) })) : null] })] }), _jsx("div", { className: styles.railContent, children: _jsx("button", { type: "button", className: styles.railButton, "aria-label": t('mode.exit'), onClick: () => {
|
|
791
850
|
actions.setViewMode('workspace-session');
|
|
792
|
-
}, children: "WT" }) }), _jsxs(Modal, { open: sessionRenameTarget !== undefined, onClose: closeSessionRename, closeLabel:
|
|
851
|
+
}, children: "WT" }) }), _jsxs(Modal, { open: sessionRenameTarget !== undefined, onClose: closeSessionRename, closeLabel: t('dialog.close'), title: t('session.rename'), footer: (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: sessionRenamePending, onClick: closeSessionRename, children: t('dialog.cancel') }), _jsx(Button, { variant: "primary", disabled: sessionRenamePending || sessionRenameDraft.trim().length === 0, onClick: () => {
|
|
793
852
|
void confirmSessionRename();
|
|
794
|
-
}, children:
|
|
853
|
+
}, children: t('dialog.rename') })] })), children: [_jsx(Input, { className: styles.renameInput, value: sessionRenameDraft, "aria-label": t('session.name'), autoFocus: true, disabled: sessionRenamePending, onFocus: (event) => {
|
|
795
854
|
event.currentTarget.select();
|
|
796
855
|
}, onChange: (event) => {
|
|
797
856
|
setSessionRenameDraft(event.currentTarget.value);
|
|
@@ -801,9 +860,9 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
801
860
|
event.preventDefault();
|
|
802
861
|
void confirmSessionRename();
|
|
803
862
|
}
|
|
804
|
-
} }), sessionRenameError !== undefined && (_jsx("p", { className: styles.renameError, role: "alert", children: sessionRenameError }))] }), workspaceRenameTarget !== undefined && (_jsxs(Modal, { open: workspaceRenameTarget !== undefined, onClose: closeWorkspaceRename, closeLabel:
|
|
863
|
+
} }), sessionRenameError !== undefined && (_jsx("p", { className: styles.renameError, role: "alert", children: formatWorktreeViewError(sessionRenameError, t) }))] }), workspaceRenameTarget !== undefined && (_jsxs(Modal, { open: workspaceRenameTarget !== undefined, onClose: closeWorkspaceRename, closeLabel: t('dialog.closeWorkspaceRename'), title: t('workspace.renameTitle'), footer: (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: workspaceRenamePending, onClick: closeWorkspaceRename, children: t('dialog.cancel') }), _jsx(Button, { variant: "primary", disabled: workspaceRenameBlocked, onClick: () => {
|
|
805
864
|
void confirmWorkspaceRename();
|
|
806
|
-
}, children:
|
|
865
|
+
}, children: t('dialog.rename') })] })), children: [_jsx(Input, { className: styles.renameInput, value: workspaceRenameDraft, "aria-label": t('workspace.name'), autoFocus: true, disabled: workspaceRenamePending, onFocus: (event) => {
|
|
807
866
|
event.currentTarget.select();
|
|
808
867
|
}, onChange: (event) => {
|
|
809
868
|
setWorkspaceRenameDraft(event.currentTarget.value);
|
|
@@ -813,22 +872,42 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
|
|
|
813
872
|
event.preventDefault();
|
|
814
873
|
void confirmWorkspaceRename();
|
|
815
874
|
}
|
|
816
|
-
} }), workspaceRenameDuplicate && (_jsx("p", { className: styles.renameError, role: "alert", children:
|
|
875
|
+
} }), workspaceRenameDuplicate && (_jsx("p", { className: styles.renameError, role: "alert", children: t('workspace.duplicate') })), workspaceRenameError !== undefined && (_jsx("p", { className: styles.renameError, role: "alert", children: formatWorktreeViewError(workspaceRenameError, t) }))] })), workspaceDeleteTarget !== undefined && (_jsx(Modal, { open: workspaceDeleteTarget !== undefined, onClose: closeWorkspaceDelete, closeLabel: t('dialog.closeWorkspaceDelete'), title: t('workspace.deleteTitle'), description: t('workspace.deleteDescription', { name: workspaceDeleteTarget.title }), footer: (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: workspaceDeletePending, onClick: closeWorkspaceDelete, children: t('dialog.cancel') }), _jsx(Button, { variant: "outline", disabled: workspaceDeletePending, onClick: () => {
|
|
817
876
|
void confirmWorkspaceDelete();
|
|
818
|
-
}, children:
|
|
877
|
+
}, children: t('dialog.delete') })] })), children: workspaceDeleteError !== undefined && (_jsx("p", { className: styles.renameError, role: "alert", children: formatWorktreeViewError(workspaceDeleteError, t) })) })), worktreeModalWorkspaceId !== undefined && modalWorkspace !== undefined && (_jsxs(Modal, { open: worktreeModalWorkspaceId !== undefined, onClose: () => {
|
|
819
878
|
if (actionPending)
|
|
820
879
|
return;
|
|
821
880
|
setWorktreeModalWorkspaceId(undefined);
|
|
822
|
-
}, closeLabel:
|
|
881
|
+
}, closeLabel: t('dialog.closeWorktreeCreate'), title: t('worktree.createTitle'), description: t('worktree.createDescription', { name: modalWorkspace.title }), footer: (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: actionPending, onClick: () => {
|
|
823
882
|
setWorktreeModalWorkspaceId(undefined);
|
|
824
|
-
}, children:
|
|
883
|
+
}, children: t('dialog.cancel') }), _jsx(Button, { variant: "primary", disabled: actionPending ||
|
|
825
884
|
selectedBranch.length === 0 ||
|
|
826
885
|
newBranch.trim().length === 0, onClick: () => {
|
|
827
886
|
void submitWorktree();
|
|
828
|
-
}, children:
|
|
887
|
+
}, children: t('worktree.create') })] })), children: [_jsxs("label", { className: styles.modalField, children: [t('worktree.baseBranch'), _jsxs("select", { className: styles.actionSelect, "aria-label": t('worktree.baseBranch'), value: selectedBranch, disabled: actionPending, onChange: (event) => {
|
|
829
888
|
setSelectedBranch(event.currentTarget.value);
|
|
830
|
-
}, children: [_jsx("option", { value: "", children:
|
|
889
|
+
}, children: [_jsx("option", { value: "", children: t('worktree.noLocalBranch') }), (modalView?.branches ?? []).map((branch) => (_jsxs("option", { value: branch.name, children: [branch.name, branch.isCurrent ? t('branch.current') : '', branch.checkedOut ? t('branch.checkedOut') : ''] }, branch.name)))] })] }), _jsxs("label", { className: styles.modalField, children: [t('worktree.name'), _jsx(Input, { className: styles.renameInput, "aria-label": t('worktree.name'), value: newBranch, placeholder: "dsh/12345678", disabled: actionPending, onChange: (event) => {
|
|
831
890
|
setNewBranch(event.currentTarget.value);
|
|
832
|
-
} })] }), modalView?.branches.length === 0 && (_jsx("p", { className: styles.empty, children:
|
|
891
|
+
} })] }), modalView?.branches.length === 0 && (_jsx("p", { className: styles.empty, children: t('worktree.noBranches') }))] })), worktreeRemoval !== undefined && (_jsx(Modal, { open: worktreeRemoval !== undefined, onClose: () => {
|
|
892
|
+
if (actionPending)
|
|
893
|
+
return;
|
|
894
|
+
setWorktreeRemoval(undefined);
|
|
895
|
+
}, closeLabel: t('dialog.closeWorktreeRemove'), title: t('worktree.remove'), description: t('worktree.removeDescription', { name: worktreeRemoval.branch }), footer: (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", disabled: actionPending, onClick: () => {
|
|
896
|
+
setWorktreeRemoval(undefined);
|
|
897
|
+
}, children: t('dialog.cancel') }), _jsx(Button, { variant: "primary", disabled: actionPending, onClick: () => {
|
|
898
|
+
if (manager === undefined)
|
|
899
|
+
return;
|
|
900
|
+
const target = worktreeRemoval;
|
|
901
|
+
void runMutation(async () => {
|
|
902
|
+
await executeWorktreeAction(manager, {
|
|
903
|
+
type: 'removeWorktree',
|
|
904
|
+
input: {
|
|
905
|
+
workspaceId: target.workspaceId,
|
|
906
|
+
worktreeId: target.worktreeId,
|
|
907
|
+
},
|
|
908
|
+
});
|
|
909
|
+
setWorktreeRemoval(undefined);
|
|
910
|
+
});
|
|
911
|
+
}, children: t('worktree.remove') })] })) }))] }));
|
|
833
912
|
}
|
|
834
913
|
//# sourceMappingURL=WorktreeSurface.js.map
|