mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 09:42:53 +00:00
fix(hosts): keep compact row actions clear of host labels
Give compact connected-host rows separate text and action widths so long names and producer labels cannot compete with primary controls.
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { test } from "../support/fixtures";
|
||||
import {
|
||||
expectConnectedHostControlsFit,
|
||||
closeConnectedHostDetails,
|
||||
toggleConnectedHost,
|
||||
openRestartableConnectedHosts,
|
||||
beginConnectedHostDraft,
|
||||
reconnectManagingHost,
|
||||
@@ -64,3 +67,33 @@ test("connection loss retains the unsaved name and credential input", async ({ p
|
||||
await host.close();
|
||||
}
|
||||
});
|
||||
|
||||
import { startIsolatedHostDaemon } from "../support/helpers/isolated-host-daemon";
|
||||
|
||||
test.describe("compact connected host controls", () => {
|
||||
test.use({ viewport: { width: 390, height: 844 } });
|
||||
test("long host names keep both actions visible with details open and closed", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
const destination = await startIsolatedHostDaemon("srv_connected_layout");
|
||||
const label = "Production build host — development-infrastructure-europe-west";
|
||||
try {
|
||||
await openCompactConnectedHosts(page);
|
||||
await addConnectedHost(page, `127.0.0.1:${destination.port}`, label);
|
||||
await expectConnectedHostControlsFit(page, label, true);
|
||||
await inspectConnectedHost(page, label);
|
||||
await expectConnectedHostControlsFit(page, label, true);
|
||||
await closeConnectedHostDetails(page);
|
||||
await toggleConnectedHost(page, true);
|
||||
await expectConnectedHostControlsFit(page, label, false);
|
||||
await inspectConnectedHost(page, label);
|
||||
await expectConnectedHostControlsFit(page, label, false);
|
||||
await page.screenshot({ path: testInfo.outputPath("connected-host-controls.png") });
|
||||
await closeConnectedHostDetails(page);
|
||||
await toggleConnectedHost(page, false);
|
||||
await expectConnectedHostControlsFit(page, label, true);
|
||||
} finally {
|
||||
await destination.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -115,3 +115,18 @@ export async function editConnectedHost(page: Page) {
|
||||
page.getByRole("textbox", { name: "Replacement connection", exact: true }),
|
||||
).toHaveValue("");
|
||||
}
|
||||
|
||||
export async function expectConnectedHostControlsFit(page: Page, label: string, enabled: boolean) {
|
||||
const details = page.getByRole("button", { name: `Details for ${label}`, exact: true });
|
||||
const toggle = page.getByRole("button", { name: enabled ? "Disable" : "Enable", exact: true });
|
||||
await details.scrollIntoViewIfNeeded();
|
||||
await expect(details).toBeInViewport({ ratio: 1 });
|
||||
await expect(toggle).toBeInViewport({ ratio: 1 });
|
||||
}
|
||||
export async function closeConnectedHostDetails(page: Page) {
|
||||
await page.getByRole("button", { name: "Cancel", exact: true }).click();
|
||||
}
|
||||
export async function toggleConnectedHost(page: Page, enabled: boolean) {
|
||||
await page.getByRole("button", { name: enabled ? "Disable" : "Enable", exact: true }).click();
|
||||
await expect(page.getByText(enabled ? /disabled · Disabled/ : /online · Enabled/)).toBeVisible();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ export { SettingsCollapsibleRow } from "./collapsible-row";
|
||||
interface AppSettingsRowProps extends Omit<SettingsRowProps, "hint"> {
|
||||
hint?: ReactNode;
|
||||
labelAccessory?: ReactNode;
|
||||
stacked?: boolean;
|
||||
}
|
||||
|
||||
export function SettingsCard({ children, testID }: { children: ReactNode; testID?: string }) {
|
||||
@@ -55,12 +56,16 @@ export function SettingsRow({
|
||||
error,
|
||||
children,
|
||||
testID,
|
||||
stacked = false,
|
||||
}: AppSettingsRowProps) {
|
||||
const compact = useIsCompactFormFactor();
|
||||
const rowStyle = useMemo(() => [settingsStyles.row, compact && styles.compactRow], [compact]);
|
||||
const rowStyle = useMemo(
|
||||
() => [settingsStyles.row, compact && styles.compactRow, stacked && styles.stackedRow],
|
||||
[compact, stacked],
|
||||
);
|
||||
return (
|
||||
<View style={rowStyle} testID={testID}>
|
||||
<View style={styles.label}>
|
||||
<View style={[styles.label, stacked && styles.stackedLabel]}>
|
||||
{labelAccessory ? (
|
||||
<View style={styles.labelRow}>
|
||||
<Text style={[settingsStyles.rowTitle, styles.accessoryLabel]}>{label}</Text>
|
||||
@@ -76,7 +81,9 @@ export function SettingsRow({
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
{children ? <View style={styles.control}>{children}</View> : null}
|
||||
{children ? (
|
||||
<View style={[styles.control, stacked && styles.stackedControl]}>{children}</View>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -193,6 +200,9 @@ export function SettingsAction({ actionLabel, onPress, disabled, ...row }: Setti
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
stackedRow: { flexDirection: "column", alignItems: "stretch", gap: theme.spacing[3] },
|
||||
stackedLabel: { flexBasis: "auto", marginRight: 0, minWidth: 0 },
|
||||
stackedControl: { width: "100%" },
|
||||
compactRow: { flexWrap: "wrap", gap: theme.spacing[3] },
|
||||
label: { flexGrow: 1, flexShrink: 1, flexBasis: 160, marginRight: theme.spacing[3] },
|
||||
labelRow: {
|
||||
|
||||
@@ -146,10 +146,12 @@ function HostRow({
|
||||
canManage: boolean;
|
||||
pending: boolean;
|
||||
}) {
|
||||
const compact = useIsCompactFormFactor();
|
||||
const edit = useCallback(() => model.edit(host), [host, model]);
|
||||
const toggle = useCallback(() => void model.setEnabled(host), [host, model]);
|
||||
return (
|
||||
<SettingsRow
|
||||
stacked={compact}
|
||||
label={host.label ?? host.serverId ?? host.registrationId}
|
||||
hint={`${host.status} · ${host.enabled ? "Enabled" : "Disabled"} · ${sourceLabel(host.source.id)}`}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user