Add shared workspace settings note and prevent filter modal expansion (#25300)

* fix(mobile): say that workspace sort, grouping, and filters are shared

The Manual sort option was subtitled 'Server order', but it orders by the
desktop's drag ranks. Sort, grouping, and filters on the phone all write the
host's shared view settings, so changing them also changes every other
device on that host, which the screen never said. Relabel Manual as 'Desktop
drag order' and add 'Shared with other devices on this host' under the Sort
By, Group By, and Filter titles. The note avoids naming a desktop sidebar
because headless hosts have none.

* fix(mobile): prevent filter modal heading expansion

Add flexShrink: 1 to allow the heading container to shrink when
space is constrained. Update comment to clarify why workspace view
is shared across devices.

* update wording
This commit is contained in:
Jinjing
2026-10-04 14:35:16 -07:00
committed by GitHub
parent e42768fb23
commit 0971479866
5 changed files with 29 additions and 4 deletions
+8
View File
@@ -15,6 +15,7 @@ export type PickerOption<T extends string = string> = {
type Props<T extends string = string> = {
visible: boolean
title: string
subtitle?: string
options: PickerOption<T>[]
selected: T
onSelect: (value: T) => void
@@ -32,6 +33,7 @@ type PickerModalContentProps<T extends string = string> = Pick<
export function PickerModal<T extends string = string>({
visible,
title,
subtitle,
options,
selected,
onSelect,
@@ -44,6 +46,7 @@ export function PickerModal<T extends string = string>({
<BottomDrawer visible={visible} onClose={onClose} onAfterClose={onAfterClose} zIndex={zIndex}>
<View style={styles.header}>
<Text style={styles.title}>{title}</Text>
{subtitle ? <Text style={styles.subtitle}>{subtitle}</Text> : null}
</View>
<PickerModalContent
@@ -130,6 +133,11 @@ const styles = StyleSheet.create({
fontWeight: '500',
color: colors.textMuted
},
subtitle: {
fontSize: 11,
color: colors.textMuted,
marginTop: 2
},
group: {
backgroundColor: colors.bgPanel,
borderRadius: 12,
@@ -12,7 +12,8 @@ import { hostNewWorktreeSessionRoute } from '../host-route-action-state'
import { getWorktreeRowIdentity } from '../worktree/worktree-host-row-identity'
import {
WORKSPACE_GROUP_OPTIONS as GROUP_OPTIONS,
WORKSPACE_SORT_OPTIONS as SORT_OPTIONS
WORKSPACE_SORT_OPTIONS as SORT_OPTIONS,
WORKSPACE_VIEW_SHARED_NOTE
} from '../worktree/workspace-list-picker-options'
import { isWorktreePinned } from '../worktree/workspace-list-sections'
import { hostScreenStyles as styles } from './host-screen-styles'
@@ -37,6 +38,7 @@ export function HostScreenOverlays({ controller }: { controller: HostScreenContr
<PickerModal
visible={state.showSortPicker}
title="Sort By"
subtitle={WORKSPACE_VIEW_SHARED_NOTE}
options={SORT_OPTIONS}
selected={state.sortMode}
onSelect={settings.handleSortChange}
@@ -46,6 +48,7 @@ export function HostScreenOverlays({ controller }: { controller: HostScreenContr
<PickerModal
visible={state.showGroupPicker}
title="Group By"
subtitle={WORKSPACE_VIEW_SHARED_NOTE}
options={GROUP_OPTIONS}
selected={state.groupMode}
onSelect={settings.handleGroupChange}
@@ -54,7 +57,10 @@ export function HostScreenOverlays({ controller }: { controller: HostScreenContr
<BottomDrawer visible={state.showFilterModal} onClose={() => state.setShowFilterModal(false)}>
<View style={styles.filterModalHeader}>
<Text style={styles.filterModalTitle}>Filter</Text>
<View style={styles.filterModalHeading}>
<Text style={styles.filterModalTitle}>Filter</Text>
<Text style={styles.filterModalSubtitle}>{WORKSPACE_VIEW_SHARED_NOTE}</Text>
</View>
{settings.activeFilterCount > 0 && (
<Pressable onPress={settings.clearFilters}>
<Text style={styles.clearFiltersText}>Clear filters</Text>
@@ -47,11 +47,19 @@ export const hostScreenSecondaryStyles = StyleSheet.create({
paddingHorizontal: spacing.xs,
marginBottom: spacing.md
},
filterModalHeading: {
flexShrink: 1
},
filterModalTitle: {
fontSize: 15,
fontWeight: '600',
color: colors.textPrimary
},
filterModalSubtitle: {
fontSize: 11,
color: colors.textMuted,
marginTop: 2
},
clearFiltersText: {
fontSize: 13,
color: colors.textSecondary
@@ -1,6 +1,9 @@
import type { PickerOption } from '../components/PickerModal'
import type { MobileGroupMode, MobileSortMode } from './workspace-view-settings'
// Why: the host may be headless, so the note can't promise a desktop sidebar.
export const WORKSPACE_VIEW_SHARED_NOTE = 'Synced across your devices'
export const WORKSPACE_SORT_OPTIONS: PickerOption<MobileSortMode>[] = [
// Why: desktop and persisted state keep the `smart` key, while mobile shows the product label.
{
@@ -11,7 +14,7 @@ export const WORKSPACE_SORT_OPTIONS: PickerOption<MobileSortMode>[] = [
{ value: 'name', label: 'Name', subtitle: 'Alphabetical by name' },
{ value: 'recent', label: 'Recent', subtitle: 'Most recent output first' },
{ value: 'repo', label: 'Repo', subtitle: 'Repository, then workspace name' },
{ value: 'manual', label: 'Manual', subtitle: 'Server order' }
{ value: 'manual', label: 'Manual', subtitle: 'Desktop drag order' }
]
export const WORKSPACE_GROUP_OPTIONS: PickerOption<MobileGroupMode>[] = [
@@ -7,7 +7,7 @@ import type { WorkspaceStatusDefinition } from '../../../src/shared/worktree/typ
import { coerceMobileWorkspaceStatuses } from './mobile-workspace-statuses'
export type MobileGroupMode = 'none' | 'workspaceStatus' | 'repo' | 'prStatus'
// Desktop sort adds 'manual'; mobile renders it but sorts by server order.
// Desktop sort adds 'manual'; mobile orders it by the desktop's drag ranks.
export type MobileSortMode = 'smart' | 'name' | 'recent' | 'repo' | 'manual'
// Desktop PersistedUIState fields this screen syncs (a structural subset).