Skip to content

Commit

Permalink
Add the options panel to role editor
Browse files Browse the repository at this point in the history
  • Loading branch information
bl-nero committed Dec 4, 2024
1 parent 17771a2 commit 1bf29a4
Show file tree
Hide file tree
Showing 5 changed files with 506 additions and 10 deletions.
2 changes: 1 addition & 1 deletion web/packages/design/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import CardSuccess, { CardSuccessLogin } from './CardSuccess';
import { Indicator } from './Indicator';
import Input from './Input';
import Label from './Label';
import LabelInput from './LabelInput';
import { LabelInput } from './LabelInput';
import LabelState from './LabelState';
import Link from './Link';
import { Mark } from './Mark';
Expand Down
210 changes: 210 additions & 0 deletions web/packages/teleport/src/Roles/RoleEditor/StandardEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
Flex,
H3,
H4,
Input,
LabelInput,
Mark,
Text,
} from 'design';
Expand All @@ -46,6 +48,10 @@ import {
} from 'shared/components/FieldSelect';
import { SlideTabs } from 'design/SlideTabs';

import { RadioGroup } from 'design/RadioGroup';

import Select from 'shared/components/Select';

import { Role, RoleWithYaml } from 'teleport/services/resources';
import { LabelsInput } from 'teleport/components/LabelsInput';

Expand Down Expand Up @@ -73,6 +79,9 @@ import {
resourceKindOptions,
verbOptions,
newRuleModel,
OptionsModel,
requireMFATypeOptions,
createHostUserModeOptions,
} from './standardmodel';
import {
validateRoleEditorModel,
Expand Down Expand Up @@ -200,6 +209,13 @@ export const StandardEditor = ({
});
}

function setOptions(options: OptionsModel) {
handleChange({
...standardEditorModel,
options,
});
}

return (
<Validation>
{({ validator }) => (
Expand Down Expand Up @@ -337,6 +353,18 @@ export const StandardEditor = ({
validation={validation.rules}
/>
</div>
<div
id={optionsTabId}
style={{
display: currentTab === StandardEditorTab.Options ? '' : 'none',
}}
>
<Options
isProcessing={isProcessing}
value={roleModel.options}
onChange={setOptions}
/>
</div>
</EditorWrapper>
<EditorSaveCancelButton
onSave={() => handleSave(validator)}
Expand Down Expand Up @@ -996,6 +1024,188 @@ function AdminRule({
);
}

function Options({
value,
isProcessing,
onChange,
}: SectionProps<OptionsModel, never>) {
const theme = useTheme();
const id = useId();
const maxSessionTTLId = `${id}-max-session-ttl`;
const clientIdleTimeoutId = `${id}-client-idle-timeout`;
const requireMFATypeId = `${id}-require-mfa-type`;
const createHostUserModeId = `${id}-create-host-user-mode`;
return (
<Box
border={1}
borderColor={theme.colors.interactive.tonal.neutral[0]}
borderRadius={3}
p={3}
css={`
display: grid;
grid-template-columns: 1fr 1fr;
align-items: baseline;
row-gap: ${theme.space[3]}px;
`}
>
<H4
css={`
grid-column: 1/3;
`}
>
Global Settings
</H4>

<OptionLabel htmlFor={maxSessionTTLId}>Max Session TTL</OptionLabel>
<Input
id={maxSessionTTLId}
value={value.maxSessionTTL}
disabled={isProcessing}
onChange={e => onChange({ ...value, maxSessionTTL: e.target.value })}
/>

<OptionLabel htmlFor={clientIdleTimeoutId}>
Client Idle Timeout
</OptionLabel>
<Input
id={clientIdleTimeoutId}
value={value.clientIdleTimeout}
disabled={isProcessing}
onChange={e =>
onChange({ ...value, clientIdleTimeout: e.target.value })
}
/>

<div>Disconnect When Certificate Expires</div>
<BoolRadioGroup
name="disconnect-expired-cert"
value={value.disconnectExpiredCert}
onChange={d => onChange({ ...value, disconnectExpiredCert: d })}
/>

<OptionLabel htmlFor={requireMFATypeId}>Require Session MFA</OptionLabel>
<Select
inputId={requireMFATypeId}
isDisabled={isProcessing}
options={requireMFATypeOptions}
value={value.requireMFAType}
onChange={t => onChange?.({ ...value, requireMFAType: t })}
/>

<H4
css={`
grid-column: 1/3;
border-top: ${theme.borders[1]}
${theme.colors.interactive.tonal.neutral[0]};
padding-top: ${theme.space[3]}px;
`}
>
SSH
</H4>

<OptionLabel htmlFor={createHostUserModeId}>
Create Host User Mode
</OptionLabel>
<Select
inputId={createHostUserModeId}
isDisabled={isProcessing}
options={createHostUserModeOptions}
value={value.createHostUserMode}
onChange={m => onChange?.({ ...value, createHostUserMode: m })}
/>

<H4
css={`
grid-column: 1/3;
border-top: ${theme.borders[1]}
${theme.colors.interactive.tonal.neutral[0]};
padding-top: ${theme.space[3]}px;
`}
>
Database
</H4>

<div>Create Database User</div>
<BoolRadioGroup
name="create-db-user"
value={value.createDBUser}
onChange={c => onChange({ ...value, createDBUser: c })}
/>

{/* TODO(bl-nero): a bug in YAML unmarshalling backend breaks this option. Fix it. */}
{/* <OptionLabel htmlFor={createDBUserModeId}>
Create Database User Mode
</OptionLabel>
<Select
inputId={createDBUserModeId}
isDisabled={isProcessing}
options={createDBUserModeOptions}
value={value.createDBUserMode}
onChange={m => onChange?.({ ...value, createDBUserMode: m })}
/> */}

<H4
css={`
grid-column: 1/3;
border-top: ${theme.borders[1]}
${theme.colors.interactive.tonal.neutral[0]};
padding-top: ${theme.space[3]}px;
`}
>
Desktop
</H4>

<div>Create Desktop User</div>
<BoolRadioGroup
name="create-desktop-user"
value={value.createDesktopUser}
onChange={c => onChange({ ...value, createDesktopUser: c })}
/>

<div>Allow Clipboard Sharing</div>
<BoolRadioGroup
name="desktop-clipboard"
value={value.desktopClipboard}
onChange={c => onChange({ ...value, desktopClipboard: c })}
/>

<div>Allow Directory Sharing</div>
<BoolRadioGroup
name="desktop-directory-sharing"
value={value.desktopDirectorySharing}
onChange={s => onChange({ ...value, desktopDirectorySharing: s })}
/>
</Box>
);
}

function BoolRadioGroup({
name,
value,
onChange,
}: {
name: string;
value: boolean;
onChange(b: boolean): void;
}) {
return (
<RadioGroup
name={name}
flexDirection="row"
options={[
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' },
]}
value={String(value)}
onChange={d => onChange(d === 'true')}
/>
);
}

const OptionLabel = styled(LabelInput)`
${props => props.theme.typography.body2}
`;

export const EditorWrapper = styled(Box)<{ mute?: boolean }>`
opacity: ${p => (p.mute ? 0.4 : 1)};
pointer-events: ${p => (p.mute ? 'none' : '')};
Expand Down
Loading

0 comments on commit 1bf29a4

Please sign in to comment.