Skip to content

Commit

Permalink
feat: add okta rest and form
Browse files Browse the repository at this point in the history
  • Loading branch information
jrea committed Jul 17, 2023
1 parent 1192a89 commit 1431cb5
Show file tree
Hide file tree
Showing 23 changed files with 1,602 additions and 282 deletions.
411 changes: 392 additions & 19 deletions lib/nile/spec/api2.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions lib/nile/test/RestAPI.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ describe('nile db', () => {
'getTenantUser',
'getUser',
'handleOIDCCallback',
'identifyDeveloper',
'identifyUser',
'listTenantUsers',
'loginOIDCUser',
'loginTenantUser',
Expand Down
4 changes: 4 additions & 0 deletions packages/browser/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ describe('nile db', () => {
if (k === 'auth') {
expect(props).toEqual([
'constructor',
'getSSOProviderRaw',
'getSSOProvider',
'loginRaw',
'login',
'signUpRaw',
'signUp',
'updateSSOProviderRaw',
'updateSSOProvider',
]);
}
if (k === 'users') {
Expand Down
90 changes: 90 additions & 0 deletions packages/react/src/SSO/BaseSSOForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { useMutation } from '@tanstack/react-query';
import { UpdateSSOProviderRequest } from '@theniledev/browser';

import SimpleForm from '../lib/SimpleForm';
import { useApi } from '../context';
import { Attribute, AttributeType } from '../lib/SimpleForm/types';

import { Props } from './types';

export default function BaseSSOForm(props: Props & { providerName: string }) {
const api = useApi();
const { config, providerName, onSuccess, onError, allowEdit = true } = props;
const attributes = React.useMemo(() => {
const attributes: Attribute[] = [
{
name: 'clientId',
label: 'Client id',
type: AttributeType.Text,
defaultValue: config?.clientId ?? '',
required: true,
disabled: !allowEdit,
},
{
name: 'configUrl',
label: 'Config url',
type: AttributeType.Text,
defaultValue: config?.configUrl ?? '',
required: true,
disabled: !allowEdit,
},
{
name: 'redirectURI',
label: 'Redirect URI',
type: AttributeType.Text,
helpText: 'Where users should be redirected to upon login',
defaultValue: config?.redirectURI ?? '',
required: true,
disabled: !allowEdit,
},
{
name: 'emailDomains',
label: 'Email domains',
type: AttributeType.Text,
defaultValue: config?.emailDomains?.join(', ') ?? '',
required: true,
helpText: 'A comma seperated list of email domains to be used',
disabled: !allowEdit,
},
];
if (!config?.clientId) {
attributes.splice(1, 0, {
name: 'clientSecret',
label: 'Client secret',
type: AttributeType.Text,
defaultValue: '',
required: true,
disabled: !allowEdit,
});
}
return attributes;
}, [
allowEdit,
config?.clientId,
config?.configUrl,
config?.emailDomains,
config?.redirectURI,
]);

const mutation = useMutation(
(ssoRequest: UpdateSSOProviderRequest) => {
return api.auth.updateSSOProvider({
providerName: providerName.toLowerCase(),
updateSSOProviderRequest: ssoRequest,
});
},
{
onSuccess,
onError,
}
);

return (
<SimpleForm
mutation={mutation}
buttonText="Update"
attributes={attributes}
/>
);
}
8 changes: 8 additions & 0 deletions packages/react/src/SSO/Okta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

import BaseSSOForm from './BaseSSOForm';
import { Props } from './types';

export default function Okta(props: Props) {
return <BaseSSOForm {...props} providerName="Okta" />;
}
39 changes: 39 additions & 0 deletions packages/react/src/SSO/SSO.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { Meta } from '@storybook/react';

import { NileProvider } from '../context';

import BaseSSOForm, { Okta } from '.';

const meta: Meta = {
tags: ['autodocs'],
component: BaseSSOForm,
};

export default meta;

export function BasicSSO() {
return (
<NileProvider>
<div style={{ maxWidth: '20rem', margin: '0 auto' }}>
<BaseSSOForm
providerName="placeholder"
onSuccess={() => alert('success!')}
/>
</div>
</NileProvider>
);
}
export function OktaSSO() {
return (
<NileProvider>
<div style={{ maxWidth: '20rem', margin: '0 auto' }}>
<Okta
onSuccess={() => {
alert('success!');
}}
/>
</div>
</NileProvider>
);
}
2 changes: 2 additions & 0 deletions packages/react/src/SSO/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Okta } from './Okta';
export { default } from './BaseSSOForm';
8 changes: 8 additions & 0 deletions packages/react/src/SSO/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { GetSSOProvider200Response } from '@theniledev/browser';

export type Props = {
config?: GetSSOProvider200Response;
onSuccess?: (data: unknown, variables: unknown) => void;
onError?: (e: Error) => void;
allowEdit?: boolean;
};
7 changes: 2 additions & 5 deletions packages/react/src/UserTenantList/UserList.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { DataGrid } from '@mui/x-data-grid';
import React from 'react';
import Stack from '@mui/joy/Stack';
import {
ListTenantUsers200ResponseInner,
Login200Response,
} from '@theniledev/browser';
import { IdentifyUser200Response, Login200Response } from '@theniledev/browser';
import { SxProps } from '@mui/system/styleFunctionSx/styleFunctionSx';
import { Theme } from '@mui/system/createTheme';

Expand All @@ -14,7 +11,7 @@ import useDataParser from './useDataParser';
type ColumnNames = string;

type Props = {
data: void | ListTenantUsers200ResponseInner[];
data: void | IdentifyUser200Response[];
allowCreation?: boolean;
buttonText?: string;
onUserCreateSuccess?: (user: Login200Response) => void;
Expand Down
8 changes: 4 additions & 4 deletions packages/react/src/UserTenantList/useDataParser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { GridColDef, GridRowsProp } from '@mui/x-data-grid';
import { ListTenantUsers200ResponseInner } from '@theniledev/browser';
import { IdentifyUser200Response } from '@theniledev/browser';

import getColumnSize from '../utils/getColumnSize';
import useTextSizer from '../hooks/useTextSizer';
Expand All @@ -9,7 +9,7 @@ export const internalRowId = '_nile_data_grid_identifier';

type Cleaned = { [key: string]: string | Set<string> };

const makeRenderable = (vals: ListTenantUsers200ResponseInner) => {
const makeRenderable = (vals: IdentifyUser200Response) => {
return Object.keys(vals).reduce((cleaned: Cleaned, key) => {
const val = (vals as Cleaned)[key];
if (val instanceof Set) {
Expand All @@ -24,7 +24,7 @@ const makeRenderable = (vals: ListTenantUsers200ResponseInner) => {
};

const parseResults = (
data: void | ListTenantUsers200ResponseInner[],
data: void | IdentifyUser200Response[],
ctx: CanvasRenderingContext2D | void,
include: string[]
): [GridColDef[], GridRowsProp] => {
Expand Down Expand Up @@ -59,7 +59,7 @@ const parseResults = (
};

export default function useDataParser(
data: void | ListTenantUsers200ResponseInner[],
data: void | IdentifyUser200Response[],
include: string[]
): [GridColDef[], GridRowsProp] {
const ctx = useTextSizer();
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ export { default as UserLoginForm } from './LoginForm';

export * from './UserTenantList';
export { default as UserTenantList } from './UserTenantList';

export * from './SSO';
export { default as SSOForm } from './SSO';
77 changes: 38 additions & 39 deletions packages/react/src/lib/SimpleForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import React from 'react';
import Button from '@mui/joy/Button';
import { Controller, FormProvider, useForm } from 'react-hook-form';
import Stack from '@mui/joy/Stack';
import { Select, Option, FormLabel, Box } from '@mui/joy';
import Input from '@mui/joy/Input';
import FormControl from '@mui/joy/FormControl';
import FormHelperText from '@mui/joy/FormHelperText';
import Error from '@mui/icons-material/Error';
import FormLabel from '@mui/joy/FormLabel';
import Select from '@mui/joy/Select';
import Option from '@mui/joy/Option';
import Box from '@mui/joy/Box';
import Tooltip from '@mui/joy/Tooltip';

import { Attribute, AttributeType, DisplayProps } from './types';
import CheckGroup from './CheckGroup';
import { Attribute, AttributeType, DisplayProps } from './types';

type AttrMap = { [key: string]: string | number | string[] | number[] };

Expand All @@ -31,6 +36,20 @@ export const getAttributeDefault = (
return attribute.defaultValue ?? '';
};

function Labler(props: { error?: string; attr: Attribute }) {
const { error, attr } = props;
if (error) {
return (
<Tooltip title={error} color="danger" sx={{ cursor: 'pointer' }}>
<FormLabel>
{attr.label ?? attr.name}
<Error color="error" sx={{ ml: 0.5 }} />
</FormLabel>
</Tooltip>
);
}
return <FormLabel>{attr.label ?? attr.name}</FormLabel>;
}
export default function SimpleForm(props: {
buttonText: string;
cancelButton?: React.ReactNode;
Expand Down Expand Up @@ -83,12 +102,16 @@ export default function SimpleForm(props: {
id: attr.label ?? attr.name,
placeholder: attr.placeholder ?? attr.label ?? attr.name,
error: Boolean(errors[attr.name]),
disabled: Boolean(attr.disabled),
};
const options = attr.options ?? [];
let helperText = '';
const helperText = attr.helpText ?? '';
let error = '';

if (attr.required) {
helperText = errors[attr.name] ? `${attr.name} is required` : '';
error = errors[attr.name]
? `${attr.label ?? attr.name} is required`
: '';
fieldConfig.required = true;
}

Expand All @@ -105,16 +128,8 @@ export default function SimpleForm(props: {
);
case AttributeType.Select:
return (
<FormControl
key={display.key}
sx={{
'--FormHelperText-color': 'var(--joy-palette-danger-500)',
}}
id={display.id}
>
<FormLabel htmlFor={`select-field-${attr.name}`}>
{display.label}
</FormLabel>
<FormControl key={display.key} id={display.id}>
<Labler error={error} attr={attr} />
<Controller
control={control}
rules={{ required: Boolean(attr.required) }}
Expand Down Expand Up @@ -154,14 +169,8 @@ export default function SimpleForm(props: {
);
case AttributeType.Password:
return (
<FormControl
key={display.key}
sx={{
'--FormHelperText-color': 'var(--joy-palette-danger-500)',
}}
id={display.id}
>
<FormLabel>{attr.label ?? attr.name}</FormLabel>
<FormControl key={display.key} id={display.id}>
<Labler error={error} attr={attr} />
<Input
{...display}
{...register(attr.name, fieldConfig)}
Expand All @@ -174,14 +183,8 @@ export default function SimpleForm(props: {
);
case AttributeType.Number:
return (
<FormControl
key={display.key}
sx={{
'--FormHelperText-color': 'var(--joy-palette-danger-500)',
}}
id={display.id}
>
<FormLabel>{attr.label ?? attr.name}</FormLabel>
<FormControl key={display.key} id={display.id}>
<Labler error={error} attr={attr} />
<Input
{...display}
{...register(attr.name, fieldConfig)}
Expand All @@ -196,14 +199,8 @@ export default function SimpleForm(props: {
case AttributeType.Text:
default:
return (
<FormControl
key={display.key}
sx={{
'--FormHelperText-color': 'var(--joy-palette-danger-500)',
}}
id={display.id}
>
<FormLabel>{attr.label ?? attr.name}</FormLabel>
<FormControl key={display.key} id={display.id}>
<Labler error={error} attr={attr} />
<Input {...display} {...register(attr.name, fieldConfig)} />
<FormHelperText id={`${attr.name}-helper-text`}>
{helperText}
Expand All @@ -220,7 +217,9 @@ export default function SimpleForm(props: {
</Box>
</Stack>
) : (
<Button type="submit">{buttonText}</Button>
<Box>
<Button type="submit">{buttonText}</Button>
</Box>
)}
</Stack>
</FormProvider>
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/lib/SimpleForm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export type Attribute = {
label?: string;
required?: boolean;
placeholder?: string;
helpText?: string;
disabled?: boolean;
};

export type DisplayProps = {
Expand All @@ -27,4 +29,5 @@ export type DisplayProps = {
placeholder: string;
error?: boolean;
color?: 'danger';
disabled?: boolean;
};

0 comments on commit 1431cb5

Please sign in to comment.