Fix sidebar shortcut hints shifting rows
This commit is contained in:
@@ -101,7 +101,10 @@ import { SidebarStatusWorkspaceList } from "@/components/sidebar/sidebar-status-
|
|||||||
import {
|
import {
|
||||||
SidebarWorkspaceRowFrame,
|
SidebarWorkspaceRowFrame,
|
||||||
SidebarWorkspaceRowContent,
|
SidebarWorkspaceRowContent,
|
||||||
sidebarWorkspaceRowStyles,
|
SidebarWorkspaceShortcutBadge,
|
||||||
|
SidebarWorkspaceTrailingActionBase,
|
||||||
|
SidebarWorkspaceTrailingActionOverlay,
|
||||||
|
SidebarWorkspaceTrailingActionSlot,
|
||||||
} from "@/components/sidebar/sidebar-workspace-row-content";
|
} from "@/components/sidebar/sidebar-workspace-row-content";
|
||||||
import {
|
import {
|
||||||
useHydratedWorkspaceEntries,
|
useHydratedWorkspaceEntries,
|
||||||
@@ -652,7 +655,10 @@ function WorkspaceRowRightGroup({
|
|||||||
onCopyPath?: () => void;
|
onCopyPath?: () => void;
|
||||||
onRename?: () => void;
|
onRename?: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
||||||
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
||||||
|
const showKebabInSlot = showKebab && !showShortcut;
|
||||||
|
const shouldRenderActionSlot = Boolean(onArchive || workspace.diffStat);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showScriptsIcon ? (
|
{showScriptsIcon ? (
|
||||||
@@ -665,30 +671,35 @@ function WorkspaceRowRightGroup({
|
|||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
{isCreating ? <Text style={styles.workspaceCreatingText}>Creating...</Text> : null}
|
{isCreating ? <Text style={styles.workspaceCreatingText}>Creating...</Text> : null}
|
||||||
{showKebab && onArchive ? (
|
{shouldRenderActionSlot ? (
|
||||||
<WorkspaceKebabMenu
|
<SidebarWorkspaceTrailingActionSlot>
|
||||||
workspaceKey={workspace.workspaceKey}
|
<SidebarWorkspaceTrailingActionBase
|
||||||
onCopyPath={onCopyPath}
|
visible={Boolean(workspace.diffStat && !showKebabInSlot && !showShortcut)}
|
||||||
onCopyBranchName={onCopyBranchName}
|
>
|
||||||
onRename={onRename}
|
{workspace.diffStat ? (
|
||||||
onMarkAsRead={onMarkAsRead}
|
<DiffStat
|
||||||
onArchive={onArchive}
|
additions={workspace.diffStat.additions}
|
||||||
archiveLabel={archiveLabel}
|
deletions={workspace.diffStat.deletions}
|
||||||
archiveStatus={archiveStatus}
|
/>
|
||||||
archivePendingLabel={archivePendingLabel}
|
) : null}
|
||||||
archiveShortcutKeys={archiveShortcutKeys}
|
</SidebarWorkspaceTrailingActionBase>
|
||||||
/>
|
<SidebarWorkspaceTrailingActionOverlay visible={showKebabInSlot}>
|
||||||
) : null}
|
{onArchive ? (
|
||||||
{!showKebab && workspace.diffStat ? (
|
<WorkspaceKebabMenu
|
||||||
<DiffStat
|
workspaceKey={workspace.workspaceKey}
|
||||||
additions={workspace.diffStat.additions}
|
onCopyPath={onCopyPath}
|
||||||
deletions={workspace.diffStat.deletions}
|
onCopyBranchName={onCopyBranchName}
|
||||||
/>
|
onRename={onRename}
|
||||||
) : null}
|
onMarkAsRead={onMarkAsRead}
|
||||||
{showShortcutBadge && shortcutNumber !== null ? (
|
onArchive={onArchive}
|
||||||
<View style={sidebarWorkspaceRowStyles.shortcutBadge}>
|
archiveLabel={archiveLabel}
|
||||||
<Text style={sidebarWorkspaceRowStyles.shortcutBadgeText}>{shortcutNumber}</Text>
|
archiveStatus={archiveStatus}
|
||||||
</View>
|
archivePendingLabel={archivePendingLabel}
|
||||||
|
archiveShortcutKeys={archiveShortcutKeys}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</SidebarWorkspaceTrailingActionOverlay>
|
||||||
|
</SidebarWorkspaceTrailingActionSlot>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -1275,8 +1286,8 @@ function ProjectHeaderRow({
|
|||||||
removeProjectStatus={removeProjectStatus}
|
removeProjectStatus={removeProjectStatus}
|
||||||
/>
|
/>
|
||||||
{showShortcutBadge && shortcutNumber !== null ? (
|
{showShortcutBadge && shortcutNumber !== null ? (
|
||||||
<View style={styles.shortcutBadge}>
|
<View style={styles.projectShortcutBadgeOverlay} pointerEvents="none">
|
||||||
<Text style={styles.shortcutBadgeText}>{shortcutNumber}</Text>
|
<SidebarWorkspaceShortcutBadge number={shortcutNumber} />
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
@@ -1412,6 +1423,8 @@ function WorkspaceRowInner({
|
|||||||
isHovered={isHovered}
|
isHovered={isHovered}
|
||||||
isLoading={isArchiving || isCreating}
|
isLoading={isArchiving || isCreating}
|
||||||
isCreating={isCreating}
|
isCreating={isCreating}
|
||||||
|
shortcutNumber={shortcutNumber}
|
||||||
|
showShortcutBadge={showShortcutBadge}
|
||||||
>
|
>
|
||||||
<WorkspaceRowRightGroup
|
<WorkspaceRowRightGroup
|
||||||
workspace={workspace}
|
workspace={workspace}
|
||||||
@@ -2789,6 +2802,7 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
},
|
},
|
||||||
projectRow: {
|
projectRow: {
|
||||||
|
position: "relative",
|
||||||
minHeight: 36,
|
minHeight: 36,
|
||||||
paddingVertical: theme.spacing[2],
|
paddingVertical: theme.spacing[2],
|
||||||
paddingHorizontal: theme.spacing[2],
|
paddingHorizontal: theme.spacing[2],
|
||||||
@@ -2925,6 +2939,11 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
fontSize: theme.fontSize.sm,
|
fontSize: theme.fontSize.sm,
|
||||||
},
|
},
|
||||||
projectActionTooltipShortcut: {},
|
projectActionTooltipShortcut: {},
|
||||||
|
projectShortcutBadgeOverlay: {
|
||||||
|
position: "absolute",
|
||||||
|
top: theme.spacing[2] + 1,
|
||||||
|
right: theme.spacing[2],
|
||||||
|
},
|
||||||
workspaceRow: {
|
workspaceRow: {
|
||||||
minHeight: 36,
|
minHeight: 36,
|
||||||
marginBottom: theme.spacing[1],
|
marginBottom: theme.spacing[1],
|
||||||
@@ -3045,24 +3064,6 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
kebabButtonHovered: {
|
kebabButtonHovered: {
|
||||||
backgroundColor: theme.colors.surface2,
|
backgroundColor: theme.colors.surface2,
|
||||||
},
|
},
|
||||||
shortcutBadge: {
|
|
||||||
minWidth: 18,
|
|
||||||
height: 18,
|
|
||||||
paddingHorizontal: theme.spacing[1],
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
borderRadius: theme.borderRadius.sm,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.surface2,
|
|
||||||
backgroundColor: theme.colors.surface0,
|
|
||||||
flexShrink: 0,
|
|
||||||
},
|
|
||||||
shortcutBadgeText: {
|
|
||||||
color: theme.colors.foregroundMuted,
|
|
||||||
fontSize: theme.fontSize.xs,
|
|
||||||
fontWeight: theme.fontWeight.medium,
|
|
||||||
lineHeight: 14,
|
|
||||||
},
|
|
||||||
statusDotNeedsInput: {
|
statusDotNeedsInput: {
|
||||||
backgroundColor: theme.colors.palette.amber[500],
|
backgroundColor: theme.colors.palette.amber[500],
|
||||||
borderColor: theme.colors.surface0,
|
borderColor: theme.colors.surface0,
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ import { useClearWorkspaceAttention } from "@/hooks/use-clear-workspace-attentio
|
|||||||
import {
|
import {
|
||||||
SidebarWorkspaceRowFrame,
|
SidebarWorkspaceRowFrame,
|
||||||
SidebarWorkspaceRowContent,
|
SidebarWorkspaceRowContent,
|
||||||
sidebarWorkspaceRowStyles,
|
SidebarWorkspaceTrailingActionBase,
|
||||||
|
SidebarWorkspaceTrailingActionOverlay,
|
||||||
|
SidebarWorkspaceTrailingActionSlot,
|
||||||
} from "@/components/sidebar/sidebar-workspace-row-content";
|
} from "@/components/sidebar/sidebar-workspace-row-content";
|
||||||
import { useSidebarCollapsedSectionsStore } from "@/stores/sidebar-collapsed-sections-store";
|
import { useSidebarCollapsedSectionsStore } from "@/stores/sidebar-collapsed-sections-store";
|
||||||
|
|
||||||
@@ -611,7 +613,10 @@ function StatusWorkspaceRowInner({
|
|||||||
return (
|
return (
|
||||||
<SidebarWorkspaceRowFrame workspace={workspace}>
|
<SidebarWorkspaceRowFrame workspace={workspace}>
|
||||||
{({ isHovered, hoverHandlers }) => {
|
{({ isHovered, hoverHandlers }) => {
|
||||||
|
const showShortcut = showShortcutBadge && shortcutNumber !== null;
|
||||||
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
|
||||||
|
const showKebabInSlot = showKebab && !showShortcut;
|
||||||
|
const shouldRenderActionSlot = Boolean(onArchive || workspace.diffStat);
|
||||||
const workspaceRowStyle = getStatusWorkspaceRowStyle({ selected, isHovered });
|
const workspaceRowStyle = getStatusWorkspaceRowStyle({ selected, isHovered });
|
||||||
return (
|
return (
|
||||||
<View style={styles.workspaceRowContainer} {...hoverHandlers}>
|
<View style={styles.workspaceRowContainer} {...hoverHandlers}>
|
||||||
@@ -628,6 +633,8 @@ function StatusWorkspaceRowInner({
|
|||||||
subtitle={projectName}
|
subtitle={projectName}
|
||||||
isHovered={isHovered}
|
isHovered={isHovered}
|
||||||
isLoading={isArchiving}
|
isLoading={isArchiving}
|
||||||
|
shortcutNumber={shortcutNumber}
|
||||||
|
showShortcutBadge={showShortcutBadge}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
{showScriptsIcon ? (
|
{showScriptsIcon ? (
|
||||||
@@ -639,9 +646,11 @@ function StatusWorkspaceRowInner({
|
|||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
{showKebab && onArchive ? (
|
{shouldRenderActionSlot ? (
|
||||||
<StatusKebabMenu
|
<StatusWorkspaceActionSlot
|
||||||
workspaceKey={workspace.workspaceKey}
|
workspace={workspace}
|
||||||
|
showBase={Boolean(workspace.diffStat && !showKebabInSlot && !showShortcut)}
|
||||||
|
showOverlay={showKebabInSlot}
|
||||||
onCopyPath={onCopyPath}
|
onCopyPath={onCopyPath}
|
||||||
onCopyBranchName={onCopyBranchName}
|
onCopyBranchName={onCopyBranchName}
|
||||||
onRename={onRename}
|
onRename={onRename}
|
||||||
@@ -653,19 +662,6 @@ function StatusWorkspaceRowInner({
|
|||||||
archiveShortcutKeys={archiveShortcutKeys}
|
archiveShortcutKeys={archiveShortcutKeys}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{!showKebab && workspace.diffStat ? (
|
|
||||||
<DiffStat
|
|
||||||
additions={workspace.diffStat.additions}
|
|
||||||
deletions={workspace.diffStat.deletions}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{showShortcutBadge && shortcutNumber !== null ? (
|
|
||||||
<View style={sidebarWorkspaceRowStyles.shortcutBadge}>
|
|
||||||
<Text style={sidebarWorkspaceRowStyles.shortcutBadgeText}>
|
|
||||||
{shortcutNumber}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
</SidebarWorkspaceRowContent>
|
</SidebarWorkspaceRowContent>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@@ -676,6 +672,63 @@ function StatusWorkspaceRowInner({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function StatusWorkspaceActionSlot({
|
||||||
|
workspace,
|
||||||
|
showBase,
|
||||||
|
showOverlay,
|
||||||
|
onCopyPath,
|
||||||
|
onCopyBranchName,
|
||||||
|
onRename,
|
||||||
|
onMarkAsRead,
|
||||||
|
onArchive,
|
||||||
|
archiveLabel,
|
||||||
|
archiveStatus,
|
||||||
|
archivePendingLabel,
|
||||||
|
archiveShortcutKeys,
|
||||||
|
}: {
|
||||||
|
workspace: SidebarWorkspaceEntry;
|
||||||
|
showBase: boolean;
|
||||||
|
showOverlay: boolean;
|
||||||
|
onCopyPath?: () => void;
|
||||||
|
onCopyBranchName?: () => void;
|
||||||
|
onRename?: () => void;
|
||||||
|
onMarkAsRead?: () => void;
|
||||||
|
onArchive?: () => void;
|
||||||
|
archiveLabel?: string;
|
||||||
|
archiveStatus?: "idle" | "pending" | "success";
|
||||||
|
archivePendingLabel?: string;
|
||||||
|
archiveShortcutKeys?: ShortcutKey[][] | null;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<SidebarWorkspaceTrailingActionSlot>
|
||||||
|
<SidebarWorkspaceTrailingActionBase visible={showBase}>
|
||||||
|
{workspace.diffStat ? (
|
||||||
|
<DiffStat
|
||||||
|
additions={workspace.diffStat.additions}
|
||||||
|
deletions={workspace.diffStat.deletions}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</SidebarWorkspaceTrailingActionBase>
|
||||||
|
<SidebarWorkspaceTrailingActionOverlay visible={showOverlay}>
|
||||||
|
{onArchive ? (
|
||||||
|
<StatusKebabMenu
|
||||||
|
workspaceKey={workspace.workspaceKey}
|
||||||
|
onCopyPath={onCopyPath}
|
||||||
|
onCopyBranchName={onCopyBranchName}
|
||||||
|
onRename={onRename}
|
||||||
|
onMarkAsRead={onMarkAsRead}
|
||||||
|
onArchive={onArchive}
|
||||||
|
archiveLabel={archiveLabel}
|
||||||
|
archiveStatus={archiveStatus}
|
||||||
|
archivePendingLabel={archivePendingLabel}
|
||||||
|
archiveShortcutKeys={archiveShortcutKeys}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</SidebarWorkspaceTrailingActionOverlay>
|
||||||
|
</SidebarWorkspaceTrailingActionSlot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function StatusKebabMenu({
|
function StatusKebabMenu({
|
||||||
workspaceKey,
|
workspaceKey,
|
||||||
onCopyPath,
|
onCopyPath,
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ export const SidebarWorkspaceRowContent = memo(function SidebarWorkspaceRowConte
|
|||||||
isHovered,
|
isHovered,
|
||||||
isLoading,
|
isLoading,
|
||||||
isCreating = false,
|
isCreating = false,
|
||||||
|
shortcutNumber = null,
|
||||||
|
showShortcutBadge = false,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
workspace: SidebarWorkspaceEntry;
|
workspace: SidebarWorkspaceEntry;
|
||||||
@@ -96,6 +98,8 @@ export const SidebarWorkspaceRowContent = memo(function SidebarWorkspaceRowConte
|
|||||||
isHovered: boolean;
|
isHovered: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isCreating?: boolean;
|
isCreating?: boolean;
|
||||||
|
shortcutNumber?: number | null;
|
||||||
|
showShortcutBadge?: boolean;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const workspaceBranchTextStyle = useMemo(
|
const workspaceBranchTextStyle = useMemo(
|
||||||
@@ -108,7 +112,7 @@ export const SidebarWorkspaceRowContent = memo(function SidebarWorkspaceRowConte
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<View style={styles.workspaceRowContent}>
|
||||||
<View style={styles.workspaceRowMain}>
|
<View style={styles.workspaceRowMain}>
|
||||||
<View style={styles.workspaceRowLeft}>
|
<View style={styles.workspaceRowLeft}>
|
||||||
<WorkspaceStatusIndicator
|
<WorkspaceStatusIndicator
|
||||||
@@ -122,6 +126,11 @@ export const SidebarWorkspaceRowContent = memo(function SidebarWorkspaceRowConte
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.workspaceRowRight}>{children}</View>
|
<View style={styles.workspaceRowRight}>{children}</View>
|
||||||
</View>
|
</View>
|
||||||
|
{showShortcutBadge && shortcutNumber !== null ? (
|
||||||
|
<View style={styles.shortcutBadgeOverlay} pointerEvents="none">
|
||||||
|
<SidebarWorkspaceShortcutBadge number={shortcutNumber} />
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
{subtitle ? (
|
{subtitle ? (
|
||||||
<Text style={styles.workspaceSubtitle} numberOfLines={1}>
|
<Text style={styles.workspaceSubtitle} numberOfLines={1}>
|
||||||
{subtitle}
|
{subtitle}
|
||||||
@@ -133,7 +142,7 @@ export const SidebarWorkspaceRowContent = memo(function SidebarWorkspaceRowConte
|
|||||||
<ChecksBadge checks={workspace.prHint.checks} />
|
<ChecksBadge checks={workspace.prHint.checks} />
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</View>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -346,7 +355,7 @@ const checksBadgeStyles = StyleSheet.create((theme) => ({
|
|||||||
export const sidebarWorkspaceRowStyles = StyleSheet.create((theme) => ({
|
export const sidebarWorkspaceRowStyles = StyleSheet.create((theme) => ({
|
||||||
rowRight: {
|
rowRight: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "flex-start",
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
},
|
},
|
||||||
@@ -368,12 +377,63 @@ export const sidebarWorkspaceRowStyles = StyleSheet.create((theme) => ({
|
|||||||
fontWeight: theme.fontWeight.medium,
|
fontWeight: theme.fontWeight.medium,
|
||||||
lineHeight: 14,
|
lineHeight: 14,
|
||||||
},
|
},
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
trailingActionSlot: {
|
||||||
|
position: "relative",
|
||||||
|
minWidth: 18,
|
||||||
|
minHeight: 20,
|
||||||
|
flexShrink: 0,
|
||||||
|
alignItems: "flex-end",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
},
|
||||||
|
trailingActionOverlay: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export function SidebarWorkspaceShortcutBadge({ number }: { number: number }) {
|
||||||
|
return (
|
||||||
|
<View style={sidebarWorkspaceRowStyles.shortcutBadge}>
|
||||||
|
<Text style={sidebarWorkspaceRowStyles.shortcutBadgeText}>{number}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SidebarWorkspaceTrailingActionSlot({ children }: { children: ReactNode }) {
|
||||||
|
return <View style={sidebarWorkspaceRowStyles.trailingActionSlot}>{children}</View>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SidebarWorkspaceTrailingActionBase({
|
||||||
|
visible,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
visible: boolean;
|
||||||
|
children: ReactNode;
|
||||||
|
}) {
|
||||||
|
if (!children) return null;
|
||||||
|
return <View style={visible ? undefined : sidebarWorkspaceRowStyles.hidden}>{children}</View>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SidebarWorkspaceTrailingActionOverlay({
|
||||||
|
visible,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
visible: boolean;
|
||||||
|
children: ReactNode;
|
||||||
|
}) {
|
||||||
|
if (!visible || !children) return null;
|
||||||
|
return <View style={sidebarWorkspaceRowStyles.trailingActionOverlay}>{children}</View>;
|
||||||
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create((theme) => ({
|
const styles = StyleSheet.create((theme) => ({
|
||||||
|
workspaceRowContent: {
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
workspaceRowMain: {
|
workspaceRowMain: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "flex-start",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
gap: theme.spacing[2],
|
gap: theme.spacing[2],
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -386,6 +446,11 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
},
|
},
|
||||||
workspaceRowRight: sidebarWorkspaceRowStyles.rowRight,
|
workspaceRowRight: sidebarWorkspaceRowStyles.rowRight,
|
||||||
|
shortcutBadgeOverlay: {
|
||||||
|
position: "absolute",
|
||||||
|
top: 1,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
workspaceStatusDot: {
|
workspaceStatusDot: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: WORKSPACE_STATUS_DOT_WIDTH,
|
width: WORKSPACE_STATUS_DOT_WIDTH,
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export function WorkspaceShortcutTargetsSubscriber({
|
|||||||
const collapsedProjectKeys = useSidebarCollapsedSectionsStore(
|
const collapsedProjectKeys = useSidebarCollapsedSectionsStore(
|
||||||
(state) => state.collapsedProjectKeys,
|
(state) => state.collapsedProjectKeys,
|
||||||
);
|
);
|
||||||
|
const collapsedStatusGroupKeys = useSidebarCollapsedSectionsStore(
|
||||||
|
(state) => state.collapsedStatusGroupKeys,
|
||||||
|
);
|
||||||
const setSidebarShortcutWorkspaceTargets = useKeyboardShortcutsStore(
|
const setSidebarShortcutWorkspaceTargets = useKeyboardShortcutsStore(
|
||||||
(state) => state.setSidebarShortcutWorkspaceTargets,
|
(state) => state.setSidebarShortcutWorkspaceTargets,
|
||||||
);
|
);
|
||||||
@@ -37,6 +40,7 @@ export function WorkspaceShortcutTargetsSubscriber({
|
|||||||
return buildStatusSidebarShortcutModel({
|
return buildStatusSidebarShortcutModel({
|
||||||
workspaces: statusWorkspaces,
|
workspaces: statusWorkspaces,
|
||||||
projectNamesByKey,
|
projectNamesByKey,
|
||||||
|
collapsedStatusGroupKeys,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +48,14 @@ export function WorkspaceShortcutTargetsSubscriber({
|
|||||||
projects,
|
projects,
|
||||||
collapsedProjectKeys,
|
collapsedProjectKeys,
|
||||||
});
|
});
|
||||||
}, [collapsedProjectKeys, groupMode, projectNamesByKey, projects, statusWorkspaces]);
|
}, [
|
||||||
|
collapsedProjectKeys,
|
||||||
|
collapsedStatusGroupKeys,
|
||||||
|
groupMode,
|
||||||
|
projectNamesByKey,
|
||||||
|
projects,
|
||||||
|
statusWorkspaces,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled || !serverId) {
|
if (!enabled || !serverId) {
|
||||||
|
|||||||
@@ -199,6 +199,37 @@ describe("buildStatusSidebarShortcutModel", () => {
|
|||||||
expect(model.shortcutIndexByWorkspaceKey.get("s1:running-old")).toBe(3);
|
expect(model.shortcutIndexByWorkspaceKey.get("s1:running-old")).toBe(3);
|
||||||
expect(model.shortcutIndexByWorkspaceKey.get("s1:done-old")).toBe(4);
|
expect(model.shortcutIndexByWorkspaceKey.get("s1:done-old")).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("excludes collapsed status groups from shortcut targets", () => {
|
||||||
|
const workspaces = [
|
||||||
|
workspace({
|
||||||
|
serverId: "s1",
|
||||||
|
workspaceId: "needs-input",
|
||||||
|
workspaceDirectory: "/repo/needs-input",
|
||||||
|
name: "needs input",
|
||||||
|
projectKey: "p1",
|
||||||
|
statusBucket: "needs_input",
|
||||||
|
}),
|
||||||
|
workspace({
|
||||||
|
serverId: "s1",
|
||||||
|
workspaceId: "running",
|
||||||
|
workspaceDirectory: "/repo/running",
|
||||||
|
name: "running",
|
||||||
|
projectKey: "p1",
|
||||||
|
statusBucket: "running",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const model = buildStatusSidebarShortcutModel({
|
||||||
|
workspaces,
|
||||||
|
projectNamesByKey: new Map([["p1", "Project 1"]]),
|
||||||
|
collapsedStatusGroupKeys: new Set(["needs_input"]),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(model.shortcutTargets).toEqual([{ serverId: "s1", workspaceId: "running" }]);
|
||||||
|
expect(model.shortcutIndexByWorkspaceKey.get("s1:needs-input")).toBeUndefined();
|
||||||
|
expect(model.shortcutIndexByWorkspaceKey.get("s1:running")).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getRelativeSidebarShortcutTarget", () => {
|
describe("getRelativeSidebarShortcutTarget", () => {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export function buildSidebarShortcutModel(input: {
|
|||||||
export function buildStatusSidebarShortcutModel(input: {
|
export function buildStatusSidebarShortcutModel(input: {
|
||||||
workspaces: SidebarWorkspaceEntry[];
|
workspaces: SidebarWorkspaceEntry[];
|
||||||
projectNamesByKey: Map<string, string>;
|
projectNamesByKey: Map<string, string>;
|
||||||
|
collapsedStatusGroupKeys?: ReadonlySet<string>;
|
||||||
shortcutLimit?: number;
|
shortcutLimit?: number;
|
||||||
}): SidebarShortcutModel {
|
}): SidebarShortcutModel {
|
||||||
const maxShortcuts = Math.max(0, Math.floor(input.shortcutLimit ?? 9));
|
const maxShortcuts = Math.max(0, Math.floor(input.shortcutLimit ?? 9));
|
||||||
@@ -61,6 +62,10 @@ export function buildStatusSidebarShortcutModel(input: {
|
|||||||
const shortcutIndexByWorkspaceKey = new Map<string, number>();
|
const shortcutIndexByWorkspaceKey = new Map<string, number>();
|
||||||
|
|
||||||
for (const group of groups) {
|
for (const group of groups) {
|
||||||
|
if (input.collapsedStatusGroupKeys?.has(group.bucket)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const workspace of group.rows) {
|
for (const workspace of group.rows) {
|
||||||
if (shortcutTargets.length >= maxShortcuts) {
|
if (shortcutTargets.length >= maxShortcuts) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user