Skip to content

Commit cf2bc76

Browse files
committed
fix: tighten session filters
1 parent 477b549 commit cf2bc76

1 file changed

Lines changed: 74 additions & 24 deletions

File tree

apps/workbench/src/features/sessions/SessionsScreen.tsx

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type SessionsScreenProps = {
2020

2121
type AvailabilityFilter = "all" | "online" | "offline";
2222
type StatusFilter = "all" | NonNullable<SessionRecord["status"]>;
23+
type FilterId = "agent" | "availability" | "host" | "status" | "workspace";
2324

2425
export function SessionsScreen({ hosts, language, sessions }: SessionsScreenProps) {
2526
const { width } = useWindowDimensions();
@@ -30,6 +31,7 @@ export function SessionsScreen({ hosts, language, sessions }: SessionsScreenProp
3031
const [workspaceRoot, setWorkspaceRoot] = useState("all");
3132
const [availability, setAvailability] = useState<AvailabilityFilter>("all");
3233
const [status, setStatus] = useState<StatusFilter>("all");
34+
const [openFilter, setOpenFilter] = useState<FilterId | undefined>();
3335
const [copiedKey, setCopiedKey] = useState<string | undefined>();
3436

3537
const hostLabels = useMemo(() => {
@@ -136,7 +138,10 @@ export function SessionsScreen({ hosts, language, sessions }: SessionsScreenProp
136138
<TextInput
137139
accessibilityLabel={t(language, "搜索 Session", "Search sessions")}
138140
autoCapitalize="none"
139-
onChangeText={setQuery}
141+
onChangeText={(value) => {
142+
setOpenFilter(undefined);
143+
setQuery(value);
144+
}}
140145
placeholder={t(language, "搜索 Session、主机、Agent、目录、ID", "Search session, host, agent, workspace, ID")}
141146
placeholderTextColor={colors.muted}
142147
style={[inputStyle, { flex: compact ? undefined : 1, width: compact ? "100%" : undefined }]}
@@ -150,46 +155,76 @@ export function SessionsScreen({ hosts, language, sessions }: SessionsScreenProp
150155
<View style={filterRailStyle}>
151156
<SelectFilter
152157
allLabel={t(language, "全部状态", "All states")}
158+
filterId="status"
153159
label={t(language, "状态", "State")}
160+
openFilter={openFilter}
154161
options={[
155162
["active", t(language, "运行中", "Active")],
156163
["starting", t(language, "启动中", "Starting")],
157164
["waiting_authorization", t(language, "等待授权", "Waiting")],
158165
["failed", t(language, "失败", "Failed")],
159166
]}
160167
value={status}
161-
onChange={(value) => setStatus(value as StatusFilter)}
168+
onChange={(value) => {
169+
setStatus(value as StatusFilter);
170+
setOpenFilter(undefined);
171+
}}
172+
onToggle={setOpenFilter}
162173
/>
163174
<SelectFilter
164175
allLabel={t(language, "全部在线状态", "All availability")}
176+
filterId="availability"
165177
label={t(language, "在线状态", "Availability")}
178+
openFilter={openFilter}
166179
options={[
167180
["online", t(language, "在线", "Online")],
168181
["offline", t(language, "离线", "Offline")],
169182
]}
170183
value={availability}
171-
onChange={(value) => setAvailability(value as AvailabilityFilter)}
184+
onChange={(value) => {
185+
setAvailability(value as AvailabilityFilter);
186+
setOpenFilter(undefined);
187+
}}
188+
onToggle={setOpenFilter}
172189
/>
173190
<SelectFilter
174191
allLabel={t(language, "全部主机", "All hosts")}
192+
filterId="host"
175193
label={t(language, "主机", "Host")}
194+
openFilter={openFilter}
176195
options={filterOptions.hosts.map((id) => [id, hostLabels.get(id) ?? shortId(id)] as const)}
177196
value={hostId}
178-
onChange={setHostId}
197+
onChange={(value) => {
198+
setHostId(value);
199+
setOpenFilter(undefined);
200+
}}
201+
onToggle={setOpenFilter}
179202
/>
180203
<SelectFilter
181204
allLabel={t(language, "全部 Agent", "All agents")}
205+
filterId="agent"
182206
label={t(language, "Agent", "Agent")}
207+
openFilter={openFilter}
183208
options={filterOptions.agents}
184209
value={agentKey}
185-
onChange={setAgentKey}
210+
onChange={(value) => {
211+
setAgentKey(value);
212+
setOpenFilter(undefined);
213+
}}
214+
onToggle={setOpenFilter}
186215
/>
187216
<SelectFilter
188217
allLabel={t(language, "全部目录", "All workspaces")}
218+
filterId="workspace"
189219
label={t(language, "目录", "Workspace")}
220+
openFilter={openFilter}
190221
options={filterOptions.workspaces}
191222
value={workspaceRoot}
192-
onChange={setWorkspaceRoot}
223+
onChange={(value) => {
224+
setWorkspaceRoot(value);
225+
setOpenFilter(undefined);
226+
}}
227+
onToggle={setOpenFilter}
193228
/>
194229
</View>
195230

@@ -229,45 +264,51 @@ export function SessionsScreen({ hosts, language, sessions }: SessionsScreenProp
229264

230265
function SelectFilter({
231266
allLabel,
267+
filterId,
232268
label,
233269
onChange,
270+
onToggle,
271+
openFilter,
234272
options,
235273
value,
236274
}: {
237275
allLabel: string;
276+
filterId: FilterId;
238277
label: string;
239278
onChange: (value: string) => void;
279+
onToggle: (filter: FilterId | undefined) => void;
280+
openFilter: FilterId | undefined;
240281
options: readonly (readonly [string, string])[];
241282
value: string;
242283
}) {
243-
const [open, setOpen] = useState(false);
284+
const open = openFilter === filterId;
244285
const items = [["all", allLabel] as const, ...options];
245286
const selectedLabel = items.find(([optionValue]) => optionValue === value)?.[1] ?? allLabel;
287+
const active = value !== "all";
246288
return (
247-
<View style={{ minWidth: 156, position: "relative", zIndex: open ? 30 : 1 }}>
289+
<View style={{ minWidth: 150, position: "relative", zIndex: open ? 50 : 1 }}>
248290
<Text style={[common.eyebrow, { marginBottom: 4 }]}>{label}</Text>
249291
<Pressable
250292
accessibilityLabel={label}
251293
accessibilityRole="button"
252-
onPress={() => setOpen((current) => !current)}
253-
style={selectButtonStyle}
294+
onPress={() => onToggle(open ? undefined : filterId)}
295+
style={[selectButtonStyle, active ? selectButtonActiveStyle : null]}
254296
>
255297
<Text numberOfLines={1} style={selectButtonTextStyle}>{selectedLabel}</Text>
256-
<Text style={selectCaretStyle}>{open ? "" : ""}</Text>
298+
<Text style={selectCaretStyle}>{open ? "" : ""}</Text>
257299
</Pressable>
258300
{open ? (
259301
<View style={selectMenuStyle}>
260-
<ScrollView keyboardShouldPersistTaps="handled" style={{ maxHeight: 220 }}>
302+
<ScrollView keyboardShouldPersistTaps="handled" style={{ maxHeight: 168 }}>
261303
{items.map(([optionValue, optionLabel]) => (
262304
<Pressable
263305
key={optionValue}
264306
onPress={() => {
265307
onChange(optionValue);
266-
setOpen(false);
267308
}}
268309
style={[
269310
selectOptionStyle,
270-
optionValue === value ? { backgroundColor: colors.lime } : null,
311+
optionValue === value ? selectOptionActiveStyle : null,
271312
]}
272313
>
273314
<Text numberOfLines={1} style={selectOptionTextStyle}>
@@ -554,33 +595,38 @@ const filterRailStyle = {
554595
alignItems: "flex-start" as const,
555596
flexDirection: "row" as const,
556597
flexWrap: "wrap" as const,
557-
gap: 10,
598+
gap: 8,
558599
paddingBottom: 2,
559600
};
560601

561602
const selectButtonStyle = {
562603
alignItems: "center" as const,
563604
backgroundColor: "#FFFFFF",
564605
borderColor: colors.ink,
565-
borderRadius: 8,
606+
borderRadius: 7,
566607
borderWidth: 1,
567608
flexDirection: "row" as const,
568-
gap: 8,
569-
minHeight: 34,
609+
gap: 6,
610+
minHeight: 32,
570611
paddingHorizontal: 10,
571612
};
572613

614+
const selectButtonActiveStyle = {
615+
backgroundColor: "#F8FFE3",
616+
borderColor: colors.graphite,
617+
};
618+
573619
const selectButtonTextStyle = {
574620
color: colors.ink,
575621
flex: 1,
576622
fontFamily: typography.sansSemi,
577-
fontSize: 13,
623+
fontSize: 12,
578624
};
579625

580626
const selectCaretStyle = {
581627
color: colors.muted,
582628
fontFamily: typography.sansSemi,
583-
fontSize: 13,
629+
fontSize: 9,
584630
};
585631

586632
const selectMenuStyle = {
@@ -594,24 +640,28 @@ const selectMenuStyle = {
594640
position: "absolute" as const,
595641
right: 0,
596642
shadowColor: colors.ink,
597-
shadowOffset: { width: 3, height: 3 },
643+
shadowOffset: { width: 2, height: 2 },
598644
shadowOpacity: 1,
599645
shadowRadius: 0,
600-
top: 56,
646+
top: 52,
601647
};
602648

603649
const selectOptionStyle = {
604650
borderBottomColor: colors.line,
605651
borderBottomWidth: 1,
606-
minHeight: 34,
652+
minHeight: 30,
607653
justifyContent: "center" as const,
608654
paddingHorizontal: 10,
609655
};
610656

657+
const selectOptionActiveStyle = {
658+
backgroundColor: "#F5F1E8",
659+
};
660+
611661
const selectOptionTextStyle = {
612662
color: colors.ink,
613663
fontFamily: typography.sans,
614-
fontSize: 13,
664+
fontSize: 12,
615665
};
616666

617667
const rowStyle = {

0 commit comments

Comments
 (0)