Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import { type JSX, type ReactNode } from "react";
import { EditableSelect } from "./EditableSelect.js";
import type { Environment } from "../../hooks/types.js";
import styles from "./EnvironmentSelect.module.scss";
/** Props for EnvironmentSelect. */
export interface EnvironmentSelectProps {
/** Currently selected environment ID. */
value: string;
/** Called when the user selects a new environment. */
onSave: (envId: string) => void;
/** Available environments. */
environments: Environment[];
/** Whether to include a "None" option. */
allowNone?: boolean;
/** Unique field identifier for coordination with other editable fields. */
fieldId?: string;
/** Which field is currently being edited (parent coordination). */
activeFieldId?: string | null; // eslint-disable-line @rushstack/no-new-null
/** Callback to tell the parent which field is active. */
onActivate?: (fieldId: string | null) => void; // eslint-disable-line @rushstack/no-new-null
/** Placeholder text when no value is selected. */
placeholder?: string;
/** Accessible label. */
ariaLabel?: string;
/** Base test ID. */
"data-testid"?: string;
}
/** Map environment status to a CSS class for the status dot. */
function envStatusClass(status: string): string {
const s = status.toLowerCase();
if (s === "ready" || s === "running" || s === "available" || s === "connected")
return styles.envDotGreen;
if (s === "provisioning" || s === "starting" || s === "pending" || s === "connecting")
return styles.envDotYellow;
if (s === "error" || s === "failed" || s === "disconnected") return styles.envDotRed;
return styles.envDotGray;
}
/** Reusable environment selector with status dot display. Click-to-edit EditableSelect. */
export function EnvironmentSelect(props: EnvironmentSelectProps): JSX.Element {
const {
value,
onSave,
environments,
allowNone = false,
fieldId = "environment",
activeFieldId,
onActivate,
placeholder = "No environment",
ariaLabel = "Environment",
"data-testid": testId,
} = props;
const selectedEnv = environments.find((e) => e.id === value);
const options = [
...(allowNone ? [{ value: "", label: "None" }] : []),
...environments.map((env) => ({ value: env.id, label: env.displayName })),
];
const renderDisplay = (): ReactNode | undefined => {
if (selectedEnv) {
return (
<span className={styles.envRow}>
<span className={`${styles.envDot} ${envStatusClass(selectedEnv.status)}`} />
{selectedEnv.displayName}
</span>
);
}
return undefined;
};
return (
<EditableSelect
value={value}
onSave={onSave}
options={options}
fieldId={fieldId}
activeFieldId={activeFieldId}
onActivate={onActivate}
renderDisplay={renderDisplay}
placeholder={placeholder}
ariaLabel={ariaLabel}
data-testid={testId}
/>
);
}
|