Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@
Page Down are included by default instead of separate fixed scroll buttons.
Up to four optional right-side buttons can also be configured for the original
Up/Down position.
- Pin individual workspaces or linked worktrees to the top of the Workspace
tree with browser persistence. Pinned linked worktrees are lifted out of their
repository group into the top-level pinned section.
- Collapse and expand linked worktrees beneath their repository workspace, with
the collapsed groups saved in the current browser.
- Mark linked-worktree workspace items with a compact branch icon, expanded to
a `WT` badge when pinned or otherwise top-level, and hide a redundant branch
badge when its branch matches the workspace name.

### Changed

Expand Down
8 changes: 8 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,14 @@ launchctl bootout "gui/$(id -u)/dev.herdr.herdr-gui"

在 workspace 上右键可以打开菜单:

- `Pin workspace` / `Pin worktree`:把 workspace 或 linked worktree 置顶;
置顶的 linked worktree 会脱离原仓库分组,作为独立项目显示在列表顶部。再次打开
菜单取消置顶后,它会回到原 parent workspace 下。配置保存在当前浏览器中。
- linked worktree 会显示紧凑的分支图标;置顶并脱离原分组后会展开为 `WT`
标记。如果 workspace 名称与 Git branch 完全相同,则不再重复显示 branch
标签。
- 有 linked worktree 的主 workspace 左侧会显示箭头;点击可以折叠或展开同组
worktree,折叠状态也保存在当前浏览器中。
- `New worktree...`:从主 checkout 创建新 worktree。
- `Rename workspace...`:重命名 workspace。
- `Remove worktree`:移除 linked worktree。
Expand Down
18 changes: 16 additions & 2 deletions web/src/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { WorktreeOpenDialog } from "./WorktreeOpenDialog";
import { WorkspaceAutoSyncDialog } from "./WorkspaceAutoSyncDialog";
import { worktreeCreationSource } from "../worktree";
import { WorktreeLifecycleDialog } from "./WorktreeLifecycleDialog";
import { isWorkspacePinned } from "../workspacePins";

export interface ContextMenuState {
x: number;
Expand Down Expand Up @@ -45,9 +46,13 @@ type DialogState =

export function ContextMenu({
state,
pinnedWorkspaceKeys,
onPinnedChange,
onClose,
}: {
state: ContextMenuState | null;
pinnedWorkspaceKeys: ReadonlySet<string>;
onPinnedChange: (workspace: Workspace, pinned: boolean) => void;
onClose: () => void;
}) {
const workspaces = useStore().workspaces;
Expand Down Expand Up @@ -199,11 +204,20 @@ export function ContextMenu({
</>
);
}
const w = state.workspace;
const w =
workspaces.find(
(workspace) => workspace.workspace_id === state.workspace.workspace_id,
) ?? state.workspace;
const isLinked = !!w.worktree?.is_linked_worktree;
const pinned = isWorkspacePinned(pinnedWorkspaceKeys, w);
const creationSource = worktreeCreationSource(workspaces, w);

const items: Item[] = [];
const items: Item[] = [
{
label: `${pinned ? "Unpin" : "Pin"} ${isLinked ? "worktree" : "workspace"}`,
action: () => onPinnedChange(w, !pinned),
},
];
if (w.worktree) {
items.push({
label: "Worktree lifecycle…",
Expand Down
Loading