Files
paseo/packages/app/src/usage/controls.tsx
T
Mohamed Boudra 01f9bc8291 Modernize compact headers and sidebar affordances (#6431)
* feat(app): modernize compact headers and sidebar affordances

Use a shared island header with quick tab creation and keep sheet footers inside their visible layout. Opt sidebar rows into touch sizing without changing global appearance settings.

* test(app): match darker light-theme workspace selection

* test(app): align plugin journeys with compact header
2026-10-10 20:53:09 +01:00

93 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { View } from "react-native";
import { StyleSheet } from "react-native-unistyles";
import { HostFilter } from "@/components/hosts/host-filter";
import { useMemo, type ReactElement } from "react";
import { UsageRefreshButton } from "./refresh-button";
import { UsageOptions } from "./options";
import type { UsageHost } from "./model";
import { useHostUsage } from "./queries";
import type { UsageView } from "./types";
/** The hosts to choose between, and which one is shown. */
export interface UsageHostSelection {
hosts: UsageHost[];
serverId: string;
onSelect: (serverId: string) => void;
}
/**
* The controls on the right of every usage title row: the host filter when there is more than one
* host, Refresh all, and the Settings cog. A host that cannot report usage keeps only the host filter.
*/
export function UsageControls({
view,
onRefresh,
hostSelection,
}: {
view: UsageView;
onRefresh: () => void;
hostSelection?: UsageHostSelection;
}) {
const busy = view.kind === "loading" || (view.kind === "ready" && view.isRefreshing);
return (
<View style={styles.controls}>
{hasHostChoice(hostSelection) ? (
<HostFilter
hosts={hostSelection.hosts}
selectedHost={hostSelection.serverId}
onSelectHost={hostSelection.onSelect}
includeAllHost={false}
triggerTestID="usage-host-filter-trigger"
hostOptionTestID={usageHostOptionTestID}
/>
) : null}
{view.kind === "unavailable" ? null : (
<>
<UsageRefreshButton busy={busy} onRefresh={onRefresh} />
<UsageOptions />
</>
)}
</View>
);
}
function hasHostChoice(
hostSelection: UsageHostSelection | undefined,
): hostSelection is UsageHostSelection {
return hostSelection !== undefined && hostSelection.hosts.length > 1;
}
function usageHostOptionTestID(serverId: string): string {
return `usage-host-filter-item-${serverId}`;
}
const styles = StyleSheet.create((theme) => ({
controls: {
flexShrink: 1,
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
},
}));
/**
* One host’s usage and title-row controls for the Usage modal.
* Returns null when there is nothing to control, so headers leave no empty island.
*/
export function useHostUsageWithControls(hostSelection: UsageHostSelection): {
view: UsageView;
refresh: () => void;
controls: ReactElement | null;
} {
const { view, refresh } = useHostUsage(hostSelection.serverId);
const hasControls = hasHostChoice(hostSelection) || view.kind !== "unavailable";
const controls = useMemo(
() =>
hasControls ? (
<UsageControls view={view} onRefresh={refresh} hostSelection={hostSelection} />
) : null,
[hasControls, hostSelection, refresh, view],
);
return { view, refresh, controls };
}