-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
484 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
catalog/app/containers/Admin/UsersAndRoles/SsoConfig.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import * as FF from 'final-form' | ||
import * as React from 'react' | ||
import * as RF from 'react-final-form' | ||
import * as M from '@material-ui/core' | ||
import * as Lab from '@material-ui/lab' | ||
|
||
import Lock from 'components/Lock' | ||
import { loadMode } from 'components/FileEditor/loader' | ||
import type * as Model from 'model' | ||
import type * as Dialogs from 'utils/GlobalDialogs' | ||
import * as GQL from 'utils/GraphQL' | ||
import assertNever from 'utils/assertNever' | ||
import * as validators from 'utils/validators' | ||
|
||
import SET_SSO_CONFIG_MUTATION from './gql/SetSsoConfig.generated' | ||
import SSO_CONFIG_QUERY from './gql/SsoConfig.generated' | ||
|
||
const TextEditor = React.lazy(() => import('components/FileEditor/TextEditor')) | ||
|
||
type TextFieldProps = RF.FieldRenderProps<string> & M.TextFieldProps | ||
|
||
const TEXT_EDITOR_TYPE = { brace: 'yaml' as const } | ||
|
||
const ERRORS = { | ||
required: 'Enter an SSO config', | ||
} | ||
|
||
function TextField({ errors, input, meta }: TextFieldProps) { | ||
// TODO: lint yaml | ||
const errorMessage = meta.submitFailed && errors[meta.error] | ||
return ( | ||
<TextEditor | ||
error={errorMessage ? new Error(errorMessage) : null} | ||
onChange={input.onChange} | ||
type={TEXT_EDITOR_TYPE} | ||
value={meta.initial} | ||
/> | ||
) | ||
} | ||
|
||
const useStyles = M.makeStyles((t) => ({ | ||
lock: { | ||
bottom: t.spacing(6.5), | ||
top: t.spacing(8), | ||
}, | ||
error: { | ||
marginTop: t.spacing(2), | ||
}, | ||
})) | ||
|
||
type FormValues = Record<'config', string> | ||
|
||
interface FormProps { | ||
formApi: RF.FormRenderProps<FormValues> | ||
close: Dialogs.Close<string | void> | ||
ssoConfig: Pick<Model.GQLTypes.SsoConfig, 'text'> | null | ||
error: null | Error | ||
} | ||
|
||
function Form({ | ||
close, | ||
error, | ||
ssoConfig, | ||
formApi: { | ||
dirtySinceLastSubmit, | ||
handleSubmit, | ||
hasValidationErrors, | ||
pristine, | ||
submitFailed, | ||
submitting, | ||
}, | ||
}: FormProps) { | ||
const classes = useStyles() | ||
return ( | ||
<> | ||
<M.DialogTitle disableTypography> | ||
<M.Typography variant="h5">SSO role mapping config</M.Typography> | ||
</M.DialogTitle> | ||
<M.DialogContent> | ||
<RF.Field | ||
component={TextField} | ||
errors={ERRORS} | ||
initialValue={ssoConfig?.text} | ||
label="SSO config" | ||
name="config" | ||
validate={validators.required as FF.FieldValidator<any>} | ||
/> | ||
{!!error && !dirtySinceLastSubmit && ( | ||
<Lab.Alert className={classes.error} severity="error"> | ||
{error.message} | ||
</Lab.Alert> | ||
)} | ||
</M.DialogContent> | ||
<M.DialogActions> | ||
<M.Button onClick={() => close('cancel')} color="primary" disabled={submitting}> | ||
Cancel | ||
</M.Button> | ||
<M.Button | ||
color="primary" | ||
disabled={pristine || submitting || (submitFailed && hasValidationErrors)} | ||
onClick={handleSubmit} | ||
> | ||
Save | ||
</M.Button> | ||
</M.DialogActions> | ||
{submitting && ( | ||
<Lock className={classes.lock}> | ||
<M.CircularProgress size={80} /> | ||
</Lock> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
interface DataProps { | ||
children: (props: FormProps) => React.ReactNode | ||
close: Dialogs.Close<string | void> | ||
} | ||
|
||
function Data({ children, close }: DataProps) { | ||
const data = GQL.useQueryS(SSO_CONFIG_QUERY) | ||
loadMode('yaml') | ||
const setSsoConfig = GQL.useMutation(SET_SSO_CONFIG_MUTATION) | ||
const [error, setError] = React.useState<null | Error>(null) | ||
|
||
const onSubmit = React.useCallback( | ||
async ({ config }: FormValues) => { | ||
try { | ||
if (!config) { | ||
throw new Error('Enter an SSO config') | ||
} | ||
const { | ||
admin: { setSsoConfig: r }, | ||
} = await setSsoConfig({ config }) | ||
switch (r.__typename) { | ||
case 'Ok': | ||
return close('submit') | ||
case 'InvalidInput': | ||
return setError(new Error('Unable to update SSO config')) | ||
case 'OperationError': | ||
return setError(new Error(`Unable to update SSO config: ${r.message}`)) | ||
default: | ||
assertNever(r) | ||
} | ||
} catch (e) { | ||
return setError(e instanceof Error ? e : new Error('Error updating SSO config')) | ||
} | ||
}, | ||
[close, setSsoConfig], | ||
) | ||
|
||
return ( | ||
<RF.Form onSubmit={onSubmit}> | ||
{(formApi) => | ||
children({ formApi, close, error: error, ssoConfig: data.admin?.ssoConfig }) | ||
} | ||
</RF.Form> | ||
) | ||
} | ||
|
||
interface SuspendedProps { | ||
close: Dialogs.Close<string | void> | ||
} | ||
|
||
export default function Suspended({ close }: SuspendedProps) { | ||
return ( | ||
<React.Suspense fallback={<M.CircularProgress size={80} />}> | ||
<Data close={close}>{(props) => <Form {...props} />}</Data> | ||
</React.Suspense> | ||
) | ||
} |
57 changes: 57 additions & 0 deletions
57
catalog/app/containers/Admin/UsersAndRoles/gql/HasSsoConfig.generated.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* eslint-disable @typescript-eslint/naming-convention */ | ||
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' | ||
import * as Types from '../../../../model/graphql/types.generated' | ||
|
||
export type containers_Admin_UsersAndRoles_gql_HasSsoConfigQueryVariables = Types.Exact<{ | ||
[key: string]: never | ||
}> | ||
|
||
export type containers_Admin_UsersAndRoles_gql_HasSsoConfigQuery = { | ||
readonly __typename: 'Query' | ||
} & { | ||
readonly admin: { readonly __typename: 'AdminQueries' } & { | ||
readonly ssoConfig: Types.Maybe< | ||
{ readonly __typename: 'SsoConfig' } & Pick<Types.SsoConfig, 'timestamp'> | ||
> | ||
} | ||
} | ||
|
||
export const containers_Admin_UsersAndRoles_gql_HasSsoConfigDocument = { | ||
kind: 'Document', | ||
definitions: [ | ||
{ | ||
kind: 'OperationDefinition', | ||
operation: 'query', | ||
name: { kind: 'Name', value: 'containers_Admin_UsersAndRoles_gql_HasSsoConfig' }, | ||
selectionSet: { | ||
kind: 'SelectionSet', | ||
selections: [ | ||
{ | ||
kind: 'Field', | ||
name: { kind: 'Name', value: 'admin' }, | ||
selectionSet: { | ||
kind: 'SelectionSet', | ||
selections: [ | ||
{ | ||
kind: 'Field', | ||
name: { kind: 'Name', value: 'ssoConfig' }, | ||
selectionSet: { | ||
kind: 'SelectionSet', | ||
selections: [ | ||
{ kind: 'Field', name: { kind: 'Name', value: 'timestamp' } }, | ||
], | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
} as unknown as DocumentNode< | ||
containers_Admin_UsersAndRoles_gql_HasSsoConfigQuery, | ||
containers_Admin_UsersAndRoles_gql_HasSsoConfigQueryVariables | ||
> | ||
|
||
export { containers_Admin_UsersAndRoles_gql_HasSsoConfigDocument as default } |
7 changes: 7 additions & 0 deletions
7
catalog/app/containers/Admin/UsersAndRoles/gql/HasSsoConfig.graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
query { | ||
admin { | ||
ssoConfig { | ||
timestamp | ||
} | ||
} | ||
} |
Oops, something went wrong.