diff --git a/components/dashboard/src/admin/BlockedRepositories.tsx b/components/dashboard/src/admin/BlockedRepositories.tsx index 6ac8f0824350de..bb2773e0bce3df 100644 --- a/components/dashboard/src/admin/BlockedRepositories.tsx +++ b/components/dashboard/src/admin/BlockedRepositories.tsx @@ -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"; @@ -299,14 +299,15 @@ function Details(props: { }} /> - { + onChange={(checked) => { if (!!props.update) { - props.update({ blockUser: v.target.checked }); + props.update({ blockUser: checked }); } }} /> diff --git a/components/dashboard/src/admin/Settings.tsx b/components/dashboard/src/admin/Settings.tsx index b1d83514682706..94a74883008e5b 100644 --- a/components/dashboard/src/admin/Settings.tsx +++ b/components/dashboard/src/admin/Settings.tsx @@ -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"; @@ -65,34 +65,27 @@ export default function Settings() { Read our Privacy Policy

- - Enable usage telemetry on your Gitpod instance. A preview of your telemetry is available - below. - - } + + onChange={(checked) => actuallySetTelemetryPrefs({ ...adminSettings, - sendTelemetry: evt.target.checked, + sendTelemetry: checked, } as InstallationAdminSettings) } /> - - Include an optional customer ID in usage telemetry to provide individualized support. - - } + + + onChange={(checked) => actuallySetTelemetryPrefs({ ...adminSettings, - sendCustomerID: evt.target.checked, + sendCustomerID: checked, } as InstallationAdminSettings) } /> diff --git a/components/dashboard/src/admin/UserDetail.tsx b/components/dashboard/src/admin/UserDetail.tsx index 351a17305f2081..ba5ed9130d6974 100644 --- a/components/dashboard/src/admin/UserDetail.tsx +++ b/components/dashboard/src/admin/UserDetail.tsx @@ -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"; @@ -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"; @@ -424,12 +424,20 @@ export default function UserDetail(p: { user: User }) { , ]} > -

Edit feature access by adding or removing feature flags for this user.

-
+ {flags.map((e) => ( - + ))} -
+ , ]} > -

Edit user permissions by adding or removing roles for this user.

-
+ {rop.map((e) => ( - + ))} -
+
); diff --git a/components/dashboard/src/components/forms/CheckboxInputField.tsx b/components/dashboard/src/components/forms/CheckboxInputField.tsx index 5e42de90fb4240..3da8d73c08f1ef 100644 --- a/components/dashboard/src/components/forms/CheckboxInputField.tsx +++ b/components/dashboard/src/components/forms/CheckboxInputField.tsx @@ -10,12 +10,14 @@ 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 = ({ label, error, className, children }) => { + +// CheckboxListField is a wrapper for a list of related CheckboxInputField components. +export const CheckboxListField: FC = ({ label, error, className, children }) => { return (
{children}
@@ -23,22 +25,26 @@ export const CheckboxInputField: FC = ({ label, error, ); }; -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 = ({ +export const CheckboxInputField: FC = ({ id, value, label, hint, + error, checked, disabled = false, + topMargin = true, onChange, }) => { const maybeId = useId(); @@ -52,33 +58,36 @@ export const CheckboxInput: FC = ({ ); return ( - +
); }; diff --git a/components/dashboard/src/components/forms/InputField.tsx b/components/dashboard/src/components/forms/InputField.tsx index 056b771750628a..1940eb22d01235 100644 --- a/components/dashboard/src/components/forms/InputField.tsx +++ b/components/dashboard/src/components/forms/InputField.tsx @@ -13,26 +13,29 @@ type Props = { id?: string; hint?: ReactNode; error?: ReactNode; + topMargin?: boolean; className?: string; }; -export const InputField: FunctionComponent = memo(({ label, id, hint, error, className, children }) => { - return ( -
- {label && ( - - )} - {children} - {error && {error}} - {hint && {hint}} -
- ); -}); +export const InputField: FunctionComponent = memo( + ({ label, id, hint, error, topMargin = true, className, children }) => { + return ( +
+ {label && ( + + )} + {children} + {error && {error}} + {hint && {hint}} +
+ ); + }, +); diff --git a/components/dashboard/src/onboarding/StepOrgInfo.tsx b/components/dashboard/src/onboarding/StepOrgInfo.tsx index 255037b645116c..87ffeee94b3b74 100644 --- a/components/dashboard/src/onboarding/StepOrgInfo.tsx +++ b/components/dashboard/src/onboarding/StepOrgInfo.tsx @@ -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"; @@ -189,13 +189,14 @@ export const StepOrgInfo: FC = ({ user, onComplete }) => { onBlur={websiteError.onBlur} /> - + {explorationReasonsOptions.map((o) => ( - { if (checked) { addExplorationReason(o.value); @@ -205,7 +206,7 @@ export const StepOrgInfo: FC = ({ user, onComplete }) => { }} /> ))} - + {explorationReasons.includes(EXPLORE_REASON_WORK) && ( = ({ user, onComplete }) => { )} - + {signupGoalsOptions.map((o) => ( - { if (checked) { addSignupGoal(o.value); @@ -239,7 +241,7 @@ export const StepOrgInfo: FC = ({ user, onComplete }) => { }} /> ))} - + {signupGoals.includes(SIGNUP_GOALS_OTHER) && ( )} - Enable Incremental Prebuilds } - desc={ + When possible, use an earlier successful prebuild as a base to create new prebuilds. This can make your prebuilds significantly faster, especially if they normally take longer than 10 @@ -137,16 +137,16 @@ export default function ProjectSettingsView() { } checked={project.settings?.useIncrementalPrebuilds ?? false} - onChange={({ target }) => updateProjectSettings({ useIncrementalPrebuilds: target.checked })} + onChange={(checked) => updateProjectSettings({ useIncrementalPrebuilds: checked })} /> - Cancel Prebuilds on Outdated Commits } - desc={Cancel pending or running prebuilds on the same branch when new commits are pushed.} + updateProjectSettings({ keepOutdatedPrebuildsRunning: !target.checked })} + onChange={(checked) => updateProjectSettings({ keepOutdatedPrebuildsRunning: !checked })} /> - Use Last Successful Prebuild{" "} @@ -154,18 +154,14 @@ export default function ProjectSettingsView() { } - desc={ - - Skip waiting for prebuilds in progress and use the last successful prebuild from previous - commits on the same branch. - - } + hint="Skip waiting for prebuilds in progress and use the last successful prebuild from previous + commits on the same branch." checked={!!project.settings?.allowUsingPreviousPrebuilds} - onChange={({ target }) => + onChange={(checked) => updateProjectSettings({ - allowUsingPreviousPrebuilds: target.checked, + allowUsingPreviousPrebuilds: checked, // we are disabling prebuild cancellation when incremental workspaces are enabled - keepOutdatedPrebuildsRunning: target.checked || project?.settings?.keepOutdatedPrebuildsRunning, + keepOutdatedPrebuildsRunning: checked || project?.settings?.keepOutdatedPrebuildsRunning, }) } /> diff --git a/components/dashboard/src/projects/ProjectVariables.tsx b/components/dashboard/src/projects/ProjectVariables.tsx index f434ad7a285363..54f8073b9f4279 100644 --- a/components/dashboard/src/projects/ProjectVariables.tsx +++ b/components/dashboard/src/projects/ProjectVariables.tsx @@ -8,7 +8,7 @@ import { Project, ProjectEnvVar } from "@gitpod/gitpod-protocol"; import { useEffect, useState } from "react"; import { Redirect } from "react-router"; import Alert from "../components/Alert"; -import CheckBox from "../components/CheckBox"; +import { CheckboxInputField } from "../components/forms/CheckboxInputField"; import InfoBox from "../components/InfoBox"; import { Item, ItemField, ItemFieldContextMenu, ItemsList } from "../components/ItemsList"; import Modal, { ModalBody, ModalFooter, ModalHeader } from "../components/Modal"; @@ -171,14 +171,12 @@ function AddVariableModal(props: { project?: Project; onClose: () => void }) { onChange={(e) => setValue(e.target.value)} /> -
- setCensored(!censored)} - /> -
+ setCensored(!censored)} + /> {!censored && (
diff --git a/components/dashboard/src/teams/TeamSettings.tsx b/components/dashboard/src/teams/TeamSettings.tsx index 413f3dc9f3faa5..559c83e15eaee8 100644 --- a/components/dashboard/src/teams/TeamSettings.tsx +++ b/components/dashboard/src/teams/TeamSettings.tsx @@ -8,7 +8,7 @@ import { OrganizationSettings } from "@gitpod/gitpod-protocol"; import React, { useCallback, useState } from "react"; import Alert from "../components/Alert"; import { Button } from "../components/Button"; -import CheckBox from "../components/CheckBox"; +import { CheckboxInputField } from "../components/forms/CheckboxInputField"; import ConfirmationModal from "../components/ConfirmationModal"; import { TextInputField } from "../components/forms/TextInputField"; import { Heading2, Subheading } from "../components/typography/headings"; @@ -146,17 +146,11 @@ export default function TeamSettingsPage() { Collaboration & Sharing - Workspace Sharing} - desc={ - - Allow workspaces creаted within an Organization to share the workspace with any authenticated user. - - } + - handleUpdateTeamSettings({ workspaceSharingDisabled: !target.checked }) - } + onChange={(checked) => handleUpdateTeamSettings({ workspaceSharingDisabled: !checked })} disabled={isLoading} /> diff --git a/components/dashboard/src/user-settings/Integrations.tsx b/components/dashboard/src/user-settings/Integrations.tsx index 8d557d9f6dfb65..5152f46ba1d6d2 100644 --- a/components/dashboard/src/user-settings/Integrations.tsx +++ b/components/dashboard/src/user-settings/Integrations.tsx @@ -9,7 +9,7 @@ import { SelectAccountPayload } from "@gitpod/gitpod-protocol/lib/auth"; import { useQuery } from "@tanstack/react-query"; import React, { useCallback, useContext, useEffect, useState } from "react"; import Alert from "../components/Alert"; -import CheckBox from "../components/CheckBox"; +import { CheckboxInputField, CheckboxListField } from "../components/forms/CheckboxInputField"; import ConfirmationModal from "../components/ConfirmationModal"; import { ContextMenuEntry } from "../components/ContextMenu"; import { Delayed } from "../components/Delayed"; @@ -213,13 +213,13 @@ function GitProviders() { } setEditModal(undefined); }; - const onChangeScopeHandler = (e: React.ChangeEvent) => { + const onChangeScopeHandler = (checked: boolean, scope: string) => { if (!editModal) { return; } - const scope = e.target.name; + const nextScopes = new Set(editModal.nextScopes); - if (e.target.checked) { + if (checked) { nextScopes.add(scope); } else { nextScopes.delete(scope); @@ -301,20 +301,20 @@ function GitProviders() { setEditModal(undefined)}> Edit Permissions -
Configure provider permissions.
- {(editModal.provider.scopes || []).map((scope) => ( -
- + {(editModal.provider.scopes || []).map((scope) => ( + -
- ))} + topMargin={false} + onChange={(checked) => onChangeScopeHandler(checked, scope)} + /> + ))} +
diff --git a/components/dashboard/src/user-settings/SelectIDE.tsx b/components/dashboard/src/user-settings/SelectIDE.tsx index 1e554cbb5c5c61..1652c2f8c6ab2b 100644 --- a/components/dashboard/src/user-settings/SelectIDE.tsx +++ b/components/dashboard/src/user-settings/SelectIDE.tsx @@ -6,7 +6,7 @@ import { useCallback, useContext, useEffect, useState } from "react"; import { UserContext } from "../user-context"; -import CheckBox from "../components/CheckBox"; +import { CheckboxInputField } from "../components/forms/CheckboxInputField"; import { User } from "@gitpod/gitpod-protocol"; import SelectIDEComponent from "../components/SelectIDEComponent"; import PillLabel from "../components/PillLabel"; @@ -103,9 +103,9 @@ export default function SelectIDE(props: SelectIDEProps) {

)} - Use the latest version for each editor.{" "} } checked={useLatestVersion} - onChange={(e) => actuallySetUseLatestVersion(e.target.checked)} + onChange={(checked) => actuallySetUseLatestVersion(checked)} /> );