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
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function SubagentDelegationSection({
onChange={v => onSave({ model: v || null, effort: effort || null })}
disabled={saving}
label={t("dash.injectionLabel")}
align="right"
/>
{model && efforts.length > 0 && (
<Select
Expand All @@ -62,6 +63,7 @@ export default function SubagentDelegationSection({
onChange={v => onSave({ model: model || null, effort: v || null })}
disabled={saving}
label={t("dash.injectionEffortLabel")}
align="right"
/>
)}
</div>
Expand Down
6 changes: 6 additions & 0 deletions gui/src/pages/dashboard-overview-sections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export function DashboardEffortCapPanel({ apiBase, d }: { apiBase: string; d: Da
}}
disabled={effortCapSaving}
label={t("dash.effortCapLabel")}
align="right"
/>
<Select
value={subagentEffortCap}
Expand All @@ -85,6 +86,7 @@ export function DashboardEffortCapPanel({ apiBase, d }: { apiBase: string; d: Da
}}
disabled={effortCapSaving}
label={t("dash.subagentEffortCapLabel")}
align="right"
/>
</div>
</div>
Expand Down Expand Up @@ -118,6 +120,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) {
onChange={(v) => { void saveInjection({ model: v || null, effort: injectionEffort || null }); }}
disabled={injectionSaving}
label={t("dash.injectionLabel")}
align="right"
/>
{injectionModel && injectionEfforts.length > 0 && (
<Select
Expand All @@ -129,6 +132,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) {
onChange={(v) => { void saveInjection({ model: injectionModel || null, effort: v || null }); }}
disabled={injectionSaving}
label={t("dash.injectionEffortLabel")}
align="right"
/>
)}
<button
Expand Down Expand Up @@ -309,6 +313,7 @@ export function DashboardSidecarPanels({ d }: { d: Dash }) {
onChange={model => { void saveSidecar({ webSearch: { model, backend: sidecarBackendForModel(models, model) } }); }}
disabled={!sidecar || sidecarSaving}
label={t("dash.sidecarModel")}
align="right"
/>
</div>
<div className="muted setting-hint">{t("dash.webSearchSidecarHint")}</div>
Expand All @@ -323,6 +328,7 @@ export function DashboardSidecarPanels({ d }: { d: Dash }) {
onChange={model => { void saveSidecar({ vision: { model, backend: sidecarBackendForModel(models, model) } }); }}
disabled={!sidecar || sidecarSaving}
label={t("dash.sidecarModel")}
align="right"
/>
</div>
<div className="muted setting-hint">{t("dash.visionSidecarHint")}</div>
Expand Down
11 changes: 6 additions & 5 deletions gui/src/select-position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function viewportWidth() {

export function computeSelectMenuStyle(
trigger: SelectMenuTriggerRect,
{ align = "left", placement = "below", menuHeight = MAX_MENU_HEIGHT_PX }: SelectMenuStyleOptions = {},
{ align, placement = "below", menuHeight = MAX_MENU_HEIGHT_PX }: SelectMenuStyleOptions = {},
): CSSProperties {
const measuredHeight = Math.min(Math.max(menuHeight, MIN_MENU_HEIGHT_PX), MAX_MENU_HEIGHT_PX);
const vh = viewportHeight();
Expand Down Expand Up @@ -65,6 +65,7 @@ export function computeSelectMenuStyle(
};
}

const effectiveAlign = align ?? (trigger.right > vw / 2 ? "right" : "left");
const width = Math.max(trigger.width, 0);
const spaceBelow = vh - trigger.bottom - VIEWPORT_PAD_PX;
const spaceAbove = trigger.top - VIEWPORT_PAD_PX;
Expand All @@ -77,8 +78,8 @@ export function computeSelectMenuStyle(
minWidth: width,
maxHeight: Math.max(0, Math.min(MAX_MENU_HEIGHT_PX, spaceAbove - MENU_GAP_PX)),
};
if (align === "right") {
style.right = vw - trigger.right;
if (effectiveAlign === "right") {
style.right = Math.max(VIEWPORT_PAD_PX, vw - trigger.right);
} else {
style.left = Math.max(VIEWPORT_PAD_PX, Math.min(trigger.left, vw - VIEWPORT_PAD_PX - width));
}
Expand All @@ -91,8 +92,8 @@ export function computeSelectMenuStyle(
minWidth: width,
maxHeight: Math.max(0, Math.min(MAX_MENU_HEIGHT_PX, spaceBelow - MENU_GAP_PX)),
};
if (align === "right") {
style.right = vw - trigger.right;
if (effectiveAlign === "right") {
style.right = Math.max(VIEWPORT_PAD_PX, vw - trigger.right);
} else {
style.left = Math.max(VIEWPORT_PAD_PX, Math.min(trigger.left, vw - VIEWPORT_PAD_PX - width));
}
Expand Down
14 changes: 14 additions & 0 deletions gui/tests/select-position.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,17 @@ test("right alignment anchors the menu to the trigger's right edge", () => {
expect(style.right).toBe(704);
expect(style.left).toBeUndefined();
});

test("automatically defaults to right alignment when trigger sits in right half of viewport", () => {
const style = computeSelectMenuStyle({
top: 120,
bottom: 156,
left: 800,
right: 960,
width: 160,
height: 36,
}, { menuHeight: 120 });
expect(style.right).toBe(64);
expect(style.left).toBeUndefined();
});

Loading