Skip to content

Migrate checkbox component #17171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 12, 2023
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
13 changes: 7 additions & 6 deletions components/dashboard/src/admin/BlockedRepositories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AdminPageHeader } from "./AdminPageHeader";
import { BlockedRepository } from "@gitpod/gitpod-protocol/lib/blocked-repositories-protocol";
import ConfirmationModal from "../components/ConfirmationModal";
import Modal from "../components/Modal";
import CheckBox from "../components/CheckBox";
import { CheckboxInputField } from "../components/forms/CheckboxInputField";
import { ItemFieldContextMenu } from "../components/ItemsList";
import { ContextMenuEntry } from "../components/ContextMenu";
import Alert from "../components/Alert";
Expand Down Expand Up @@ -299,14 +299,15 @@ function Details(props: {
}}
/>
</div>
<CheckBox
title={"Block Users"}
desc={"Block any user that tries to open a workspace for a repository URL that matches this RegEx."}

<CheckboxInputField
label="Block Users"
hint="Block any user that tries to open a workspace for a repository URL that matches this RegEx."
checked={props.br.blockUser}
disabled={!props.update}
onChange={(v) => {
onChange={(checked) => {
if (!!props.update) {
props.update({ blockUser: v.target.checked });
props.update({ blockUser: checked });
}
}}
/>
Expand Down
33 changes: 13 additions & 20 deletions components/dashboard/src/admin/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React, { useContext } from "react";
import { TelemetryData, InstallationAdminSettings } from "@gitpod/gitpod-protocol";
import { AdminContext } from "../admin-context";
import CheckBox from "../components/CheckBox";
import { CheckboxInputField } from "../components/forms/CheckboxInputField";
import { getGitpodService } from "../service/service";
import { useEffect, useState } from "react";
import InfoBox from "../components/InfoBox";
Expand Down Expand Up @@ -65,34 +65,27 @@ export default function Settings() {
Read our Privacy Policy
</a>
</p>
<CheckBox
title="Enable usage telemetry"
desc={
<span>
Enable usage telemetry on your Gitpod instance. A preview of your telemetry is available
below.
</span>
}
<CheckboxInputField
label="Enable usage telemetry"
hint="Enable usage telemetry on your Gitpod instance. A preview of your telemetry is available
below."
checked={adminSettings?.sendTelemetry ?? false}
onChange={(evt) =>
onChange={(checked) =>
actuallySetTelemetryPrefs({
...adminSettings,
sendTelemetry: evt.target.checked,
sendTelemetry: checked,
} as InstallationAdminSettings)
}
/>
<CheckBox
title="Include customer ID in telemetry"
desc={
<span>
Include an optional customer ID in usage telemetry to provide individualized support.
</span>
}

<CheckboxInputField
label="Include customer ID in telemetry"
hint="Include an optional customer ID in usage telemetry to provide individualized support."
checked={adminSettings?.sendCustomerID ?? false}
onChange={(evt) =>
onChange={(checked) =>
actuallySetTelemetryPrefs({
...adminSettings,
sendCustomerID: evt.target.checked,
sendCustomerID: checked,
} as InstallationAdminSettings)
}
/>
Expand Down
34 changes: 25 additions & 9 deletions components/dashboard/src/admin/UserDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { AccountStatement, Subscription } from "@gitpod/gitpod-protocol/lib/acco
import { Plans } from "@gitpod/gitpod-protocol/lib/plans";
import dayjs from "dayjs";
import { useEffect, useRef, useState } from "react";
import CheckBox from "../components/CheckBox";
import Modal from "../components/Modal";
import { getGitpodService } from "../service/service";
import { WorkspaceSearch } from "./WorkspacesSearch";
Expand All @@ -26,6 +25,7 @@ import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
import CaretDown from "../icons/CaretDown.svg";
import ContextMenu from "../components/ContextMenu";
import { CheckboxInputField, CheckboxListField } from "../components/forms/CheckboxInputField";
import { CostCenterJSON, CostCenter_BillingStrategy } from "@gitpod/gitpod-protocol/lib/usage";
import { Heading2, Subheading } from "../components/typography/headings";

Expand Down Expand Up @@ -424,12 +424,20 @@ export default function UserDetail(p: { user: User }) {
</button>,
]}
>
<p>Edit feature access by adding or removing feature flags for this user.</p>
<div className="flex flex-col">
<CheckboxListField
label="Edit feature access by adding or removing feature flags for this user."
className="mt-0"
>
{flags.map((e) => (
<CheckBox key={e.title} title={e.title} desc="" checked={!!e.checked} onChange={e.onClick} />
<CheckboxInputField
key={e.title}
label={e.title}
checked={!!e.checked}
topMargin={false}
onChange={e.onClick}
/>
))}
</div>
</CheckboxListField>
</Modal>
<Modal
visible={editRoles}
Expand All @@ -441,12 +449,20 @@ export default function UserDetail(p: { user: User }) {
</button>,
]}
>
<p>Edit user permissions by adding or removing roles for this user.</p>
<div className="flex flex-col">
<CheckboxListField
label="Edit user permissions by adding or removing roles for this user."
className="mt-0"
>
{rop.map((e) => (
<CheckBox key={e.title} title={e.title} desc="" checked={!!e.checked} onChange={e.onClick} />
<CheckboxInputField
key={e.title}
label={e.title}
checked={!!e.checked}
topMargin={false}
onChange={e.onClick}
/>
))}
</div>
</CheckboxListField>
</Modal>
</>
);
Expand Down
73 changes: 41 additions & 32 deletions components/dashboard/src/components/forms/CheckboxInputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,41 @@ import { useId } from "../../hooks/useId";
import { InputField } from "./InputField";
import { InputFieldHint } from "./InputFieldHint";

type CheckboxInputFieldProps = {
type CheckboxListFieldProps = {
label: string;
error?: ReactNode;
className?: string;
};
export const CheckboxInputField: FC<CheckboxInputFieldProps> = ({ label, error, className, children }) => {

// CheckboxListField is a wrapper for a list of related CheckboxInputField components.
export const CheckboxListField: FC<CheckboxListFieldProps> = ({ label, error, className, children }) => {
return (
<InputField label={label} className={className} error={error}>
<div className="space-y-2 ml-2">{children}</div>
</InputField>
);
};

type CheckboxInputProps = {
type CheckboxInputFieldProps = {
id?: string;
value: string;
value?: string;
checked: boolean;
disabled?: boolean;
label: string;
hint?: string;
label: ReactNode;
hint?: ReactNode;
error?: ReactNode;
topMargin?: boolean;
onChange: (checked: boolean) => void;
};
export const CheckboxInput: FC<CheckboxInputProps> = ({
export const CheckboxInputField: FC<CheckboxInputFieldProps> = ({
id,
value,
label,
hint,
error,
checked,
disabled = false,
topMargin = true,
onChange,
}) => {
const maybeId = useId();
Expand All @@ -52,33 +58,36 @@ export const CheckboxInput: FC<CheckboxInputProps> = ({
);

return (
<label className="flex space-x-2 justify-start items-start" htmlFor={elementId}>
<input
type="checkbox"
className={classNames(
"h-4 w-4 mt-0.5 rounded cursor-pointer border-2 dark:filter-invert",
"focus:ring-2 focus:border-gray-900 ring-blue-400 dark:focus:border-gray-800",
"border-gray-600 dark:border-gray-900 bg-transparent",
{ "bg-gray-600 dark:bg-gray-900": checked },
)}
value={value}
id={elementId}
checked={checked}
disabled={disabled}
onChange={handleChange}
/>
<div className="flex flex-col">
<span
// Intentionally not passing label and hint to InputField because we want to render them differently for checkboxes.
<InputField error={error} topMargin={topMargin}>
<label className="flex space-x-2 justify-start items-start max-w-lg" htmlFor={elementId}>
<input
type="checkbox"
className={classNames(
"text-sm font-semibold cursor-pointer",
disabled ? "text-gray-400 dark:text-gray-400" : "text-gray-600 dark:text-gray-100",
"h-4 w-4 mt-0.5 rounded cursor-pointer border-2 dark:filter-invert",
"focus:ring-2 ring-blue-400",
"border-gray-600 dark:border-gray-900 bg-transparent",
{ "bg-gray-600 dark:bg-gray-900": checked },
)}
>
{label}
</span>
id={elementId}
checked={checked}
disabled={disabled}
value={value}
onChange={handleChange}
/>
<div className="flex flex-col">
<span
className={classNames(
"text-sm font-semibold cursor-pointer",
disabled ? "text-gray-400 dark:text-gray-400" : "text-gray-600 dark:text-gray-100",
)}
>
{label}
</span>

{hint && <InputFieldHint disabled={disabled}>{hint}</InputFieldHint>}
</div>
</label>
{hint && <InputFieldHint disabled={disabled}>{hint}</InputFieldHint>}
</div>
</label>
</InputField>
);
};
43 changes: 23 additions & 20 deletions components/dashboard/src/components/forms/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,29 @@ type Props = {
id?: string;
hint?: ReactNode;
error?: ReactNode;
topMargin?: boolean;
className?: string;
};

export const InputField: FunctionComponent<Props> = memo(({ label, id, hint, error, className, children }) => {
return (
<div className={classNames("mt-4 flex flex-col space-y-2", className)}>
{label && (
<label
className={classNames(
"text-md font-semibold dark:text-gray-400",
error ? "text-red-600" : "text-gray-600",
)}
htmlFor={id}
>
{label}
</label>
)}
{children}
{error && <span className="text-red-500 text-sm">{error}</span>}
{hint && <InputFieldHint>{hint}</InputFieldHint>}
</div>
);
});
export const InputField: FunctionComponent<Props> = memo(
({ label, id, hint, error, topMargin = true, className, children }) => {
return (
<div className={classNames("flex flex-col space-y-2", { "mt-4": topMargin }, className)}>
{label && (
<label
className={classNames(
"text-md font-semibold dark:text-gray-400",
error ? "text-red-600" : "text-gray-600",
)}
htmlFor={id}
>
{label}
</label>
)}
{children}
{error && <span className="text-red-500 text-sm">{error}</span>}
{hint && <InputFieldHint>{hint}</InputFieldHint>}
</div>
);
},
);
16 changes: 9 additions & 7 deletions components/dashboard/src/onboarding/StepOrgInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { User } from "@gitpod/gitpod-protocol";
import { FC, useCallback, useMemo, useState } from "react";
import { CheckboxInput, CheckboxInputField } from "../components/forms/CheckboxInputField";
import { CheckboxInputField, CheckboxListField } from "../components/forms/CheckboxInputField";
import { SelectInputField } from "../components/forms/SelectInputField";
import { TextInputField } from "../components/forms/TextInputField";
import { useUpdateCurrentUserMutation } from "../data/current-user/update-mutation";
Expand Down Expand Up @@ -189,13 +189,14 @@ export const StepOrgInfo: FC<Props> = ({ user, onComplete }) => {
onBlur={websiteError.onBlur}
/>

<CheckboxInputField label="I'm exploring Gitpod...">
<CheckboxListField label="I'm exploring Gitpod...">
{explorationReasonsOptions.map((o) => (
<CheckboxInput
<CheckboxInputField
key={o.value}
value={o.value}
label={o.label}
checked={explorationReasons.includes(o.value)}
topMargin={false}
onChange={(checked) => {
if (checked) {
addExplorationReason(o.value);
Expand All @@ -205,7 +206,7 @@ export const StepOrgInfo: FC<Props> = ({ user, onComplete }) => {
}}
/>
))}
</CheckboxInputField>
</CheckboxListField>

{explorationReasons.includes(EXPLORE_REASON_WORK) && (
<SelectInputField
Expand All @@ -223,13 +224,14 @@ export const StepOrgInfo: FC<Props> = ({ user, onComplete }) => {
</SelectInputField>
)}

<CheckboxInputField label="I'm signing up for Gitpod for...">
<CheckboxListField label="I'm signing up for Gitpod for...">
{signupGoalsOptions.map((o) => (
<CheckboxInput
<CheckboxInputField
key={o.value}
value={o.value}
label={o.label}
checked={signupGoals.includes(o.value)}
topMargin={false}
onChange={(checked) => {
if (checked) {
addSignupGoal(o.value);
Expand All @@ -239,7 +241,7 @@ export const StepOrgInfo: FC<Props> = ({ user, onComplete }) => {
}}
/>
))}
</CheckboxInputField>
</CheckboxListField>

{signupGoals.includes(SIGNUP_GOALS_OTHER) && (
<TextInputField
Expand Down
Loading