Improve sidebar workspace readability and host identity (#2790)
* fix(app): align turn footer actions Keep running-turn actions in the same position as completed-turn actions and use the shared small icon size for both copy and fork controls. * feat(app): improve sidebar workspace identity Make dense sidebar workspace rows easier to scan and let each device control how connected hosts are identified. * fix(app): keep host badges readable Use a compact display menu and keep identity color on the host icon so translated controls fit and badge text retains standard contrast. * fix(app): announce selected sidebar badge mode * fix(app): retain icon-only host names for screen readers * fix(app): name hoisted workspace rows * fix(app): retain host identity in workspace labels * fix(app): retain workspace status in row labels * fix(app): defer host appearance until identity resolves * fix(app): serialize host appearance writes * fix(app): serialize host registry writes * fix(app): bound sidebar host badge labels * test(app): match workspace status labels * fix(app): consolidate sidebar identity behavior * test(app): assert status grouping behavior * fix(app): keep sidebar row actions accessible * fix(app): stabilize optimistic message layout
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
CircleX,
|
||||
Copy,
|
||||
ExternalLink,
|
||||
FileDiff,
|
||||
Folder,
|
||||
GitBranch,
|
||||
Server,
|
||||
@@ -94,12 +95,14 @@ interface WorkspaceHoverCardProps {
|
||||
workspace: SidebarWorkspaceEntry;
|
||||
prHint: PrHint | null;
|
||||
isDragging: boolean;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function WorkspaceHoverCard({
|
||||
workspace,
|
||||
prHint,
|
||||
isDragging,
|
||||
disabled = false,
|
||||
children,
|
||||
}: PropsWithChildren<WorkspaceHoverCardProps>): ReactNode {
|
||||
const isCompact = useIsCompactFormFactor();
|
||||
@@ -109,7 +112,12 @@ export function WorkspaceHoverCard({
|
||||
}
|
||||
|
||||
return (
|
||||
<WorkspaceHoverCardDesktop workspace={workspace} prHint={prHint} isDragging={isDragging}>
|
||||
<WorkspaceHoverCardDesktop
|
||||
workspace={workspace}
|
||||
prHint={prHint}
|
||||
isDragging={isDragging}
|
||||
disabled={disabled}
|
||||
>
|
||||
{children}
|
||||
</WorkspaceHoverCardDesktop>
|
||||
);
|
||||
@@ -119,6 +127,7 @@ function WorkspaceHoverCardDesktop({
|
||||
workspace,
|
||||
prHint,
|
||||
isDragging,
|
||||
disabled = false,
|
||||
children,
|
||||
}: PropsWithChildren<WorkspaceHoverCardProps>): ReactElement {
|
||||
const triggerRef = useRef<View>(null);
|
||||
@@ -145,10 +154,10 @@ function WorkspaceHoverCardDesktop({
|
||||
const handleTriggerEnter = useCallback(() => {
|
||||
triggerHoveredRef.current = true;
|
||||
clearGraceTimer();
|
||||
if (!isDragging) {
|
||||
if (!isDragging && !disabled) {
|
||||
setOpen(true);
|
||||
}
|
||||
}, [clearGraceTimer, isDragging]);
|
||||
}, [clearGraceTimer, disabled, isDragging]);
|
||||
|
||||
const handleTriggerLeave = useCallback(() => {
|
||||
triggerHoveredRef.current = false;
|
||||
@@ -166,13 +175,13 @@ function WorkspaceHoverCardDesktop({
|
||||
onLeaveSafeZone: scheduleClose,
|
||||
});
|
||||
|
||||
// Close when drag starts
|
||||
// Close while another row interaction owns attention.
|
||||
useEffect(() => {
|
||||
if (isDragging) {
|
||||
if (isDragging || disabled) {
|
||||
clearGraceTimer();
|
||||
setOpen(false);
|
||||
}
|
||||
}, [isDragging, clearGraceTimer]);
|
||||
}, [clearGraceTimer, disabled, isDragging]);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
@@ -285,6 +294,16 @@ function WorkspaceHoverCardContent({
|
||||
{workspace.name}
|
||||
</Text>
|
||||
</View>
|
||||
{prHint ? <PrBadge hint={prHint} style={styles.cardInfoRow} /> : null}
|
||||
{workspace.diffStat ? (
|
||||
<View style={styles.cardInfoRow}>
|
||||
<ThemedFileDiff size={12} uniProps={foregroundMutedColorMapping} />
|
||||
<DiffStat
|
||||
additions={workspace.diffStat.additions}
|
||||
deletions={workspace.diffStat.deletions}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
<HostRow serverId={workspace.serverId} />
|
||||
{workspace.currentBranch ? (
|
||||
<CopyableInfoRow
|
||||
@@ -304,17 +323,6 @@ function WorkspaceHoverCardContent({
|
||||
testID="hover-card-workspace-cwd"
|
||||
/>
|
||||
) : null}
|
||||
{prHint || workspace.diffStat ? (
|
||||
<View style={styles.cardMetaRow}>
|
||||
{workspace.diffStat ? (
|
||||
<DiffStat
|
||||
additions={workspace.diffStat.additions}
|
||||
deletions={workspace.diffStat.deletions}
|
||||
/>
|
||||
) : null}
|
||||
{prHint ? <PrBadge hint={prHint} /> : null}
|
||||
</View>
|
||||
) : null}
|
||||
{prHint?.checks && prHint.checks.length > 0 ? (
|
||||
<>
|
||||
<View style={styles.separator} />
|
||||
@@ -334,6 +342,7 @@ function WorkspaceHoverCardContent({
|
||||
const ThemedGitBranch = withUnistyles(GitBranch);
|
||||
const ThemedFolder = withUnistyles(Folder);
|
||||
const ThemedServer = withUnistyles(Server);
|
||||
const ThemedFileDiff = withUnistyles(FileDiff);
|
||||
|
||||
type CardInfoIcon = React.ComponentType<React.ComponentProps<typeof ThemedGitBranch>>;
|
||||
|
||||
@@ -596,13 +605,6 @@ const styles = StyleSheet.create((theme) => ({
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
cardMetaRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingBottom: theme.spacing[2],
|
||||
},
|
||||
cardInfoRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
|
||||
Reference in New Issue
Block a user