mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: Change usage of ChooseOne (no final condition) (#4158)
* Change contract of Cond: no condition on default case * Handle no children case * Format
This commit is contained in:
@@ -11,6 +11,7 @@ export const FirstIsTrue: Story = () => (
|
||||
<ChooseOne>
|
||||
<Cond condition>The first one shows.</Cond>
|
||||
<Cond condition={false}>The second one does not show.</Cond>
|
||||
<Cond>The default does not show.</Cond>
|
||||
</ChooseOne>
|
||||
)
|
||||
|
||||
@@ -18,6 +19,7 @@ export const SecondIsTrue: Story = () => (
|
||||
<ChooseOne>
|
||||
<Cond condition={false}>The first one does not show.</Cond>
|
||||
<Cond condition>The second one shows.</Cond>
|
||||
<Cond>The default does not show.</Cond>
|
||||
</ChooseOne>
|
||||
)
|
||||
|
||||
@@ -25,12 +27,20 @@ export const AllAreTrue: Story = () => (
|
||||
<ChooseOne>
|
||||
<Cond condition>Only the first one shows.</Cond>
|
||||
<Cond condition>The second one does not show.</Cond>
|
||||
<Cond>The default does not show.</Cond>
|
||||
</ChooseOne>
|
||||
)
|
||||
|
||||
export const NoneAreTrue: Story = () => (
|
||||
<ChooseOne>
|
||||
<Cond condition={false}>The first one does not show.</Cond>
|
||||
<Cond condition={false}>The second shows because it is the fallback.</Cond>
|
||||
<Cond condition={false}>The second one does not show.</Cond>
|
||||
<Cond>The default shows.</Cond>
|
||||
</ChooseOne>
|
||||
)
|
||||
|
||||
export const OneCond: Story = () => (
|
||||
<ChooseOne>
|
||||
<Cond>An only child renders.</Cond>
|
||||
</ChooseOne>
|
||||
)
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Children, PropsWithChildren } from "react"
|
||||
|
||||
export interface CondProps {
|
||||
condition: boolean
|
||||
condition?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper component that attaches a condition to a child component so that ChooseOne can
|
||||
* determine which child to render. The last Cond in a ChooseOne is the fallback case; set
|
||||
* its `condition` to `true` to avoid confusion.
|
||||
* @param condition boolean expression indicating whether the child should be rendered
|
||||
* determine which child to render. The last Cond in a ChooseOne is the fallback case and
|
||||
* should not have a condition.
|
||||
* @param condition boolean expression indicating whether the child should be rendered, or undefined
|
||||
* @returns child. Note that Cond alone does not enforce the condition; it should be used inside ChooseOne.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const Cond = ({ children, condition }: PropsWithChildren<CondProps>): JSX.Element => {
|
||||
export const Cond = ({ children }: PropsWithChildren<CondProps>): JSX.Element => {
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
@@ -20,10 +19,24 @@ export const Cond = ({ children, condition }: PropsWithChildren<CondProps>): JSX
|
||||
* Wrapper component for rendering exactly one of its children. Wrap each child in Cond to associate it
|
||||
* with a condition under which it should be rendered. If no conditions are met, the final child
|
||||
* will be rendered.
|
||||
* @returns one of its children
|
||||
* @returns one of its children, or null if there are no children
|
||||
* @throws an error if its last child has a condition prop, or any non-final children do not have a condition prop
|
||||
*/
|
||||
export const ChooseOne = ({ children }: PropsWithChildren): JSX.Element => {
|
||||
export const ChooseOne = ({ children }: PropsWithChildren): JSX.Element | null => {
|
||||
const childArray = Children.toArray(children) as JSX.Element[]
|
||||
const chosen = childArray.find((child) => child.props.condition)
|
||||
return chosen ?? childArray[childArray.length - 1]
|
||||
if (childArray.length === 0) {
|
||||
return null
|
||||
}
|
||||
const conditionedOptions = childArray.slice(0, childArray.length - 1)
|
||||
const defaultCase = childArray[childArray.length - 1]
|
||||
if (defaultCase.props.condition !== undefined) {
|
||||
throw new Error(
|
||||
"The last Cond in a ChooseOne was given a condition prop, but it is the default case.",
|
||||
)
|
||||
}
|
||||
if (conditionedOptions.some((cond) => cond.props.condition === undefined)) {
|
||||
throw new Error("A non-final Cond in a ChooseOne does not have a condition prop.")
|
||||
}
|
||||
const chosen = conditionedOptions.find((child) => child.props.condition)
|
||||
return chosen ?? defaultCase
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ export const TemplatesPageView: FC<React.PropsWithChildren<TemplatesPageViewProp
|
||||
defaultMessage={t("errors.getTemplatesError")}
|
||||
/>
|
||||
</Cond>
|
||||
<Cond condition>
|
||||
<Cond>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
@@ -173,7 +173,7 @@ export const TemplatesPageView: FC<React.PropsWithChildren<TemplatesPageViewProp
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</Cond>
|
||||
<Cond condition>
|
||||
<Cond>
|
||||
{props.templates?.map((template) => {
|
||||
const templatePageLink = `/templates/${template.name}`
|
||||
const hasIcon = template.icon && template.icon !== ""
|
||||
|
||||
Reference in New Issue
Block a user