From 370fd5a5af6fce85f64f0c8b42209c1da5c1e3fc Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Thu, 11 Jan 2024 11:23:38 +0100 Subject: [PATCH] SSO Config: Add generic OAuth (#79972) * Setup route * Set up the page * Add orgs * Load settings * Make API call * Remove log * Add FormPrompt * Update types * Add tests * Fix tests * Cleanup * Load settings * Fix naming * Switch to PUT endpoint * Switch to CSS object * Setup fields * Render fields * Extend types * Dynamic provider page * Rename page * Filter out non-implemented providers * Fix types * Add teamIDs validation * Update tests * Fix URL * Update name * Send full data * Add password input * Update test * Expand default values * Fix test * Use SecretInput * Remove dev mode for the feature toggle * Convert fields * Remove fieldFormat utils * Update fields logic * Update tests * Update betterer * SSO: Add Generic OAuth page * SSO: Add Generic OAuth page * SSO: Make client secret not required * Update field name * Revert feature toggle to dev mode * Use provider endpoint * Fix form state check * Update tests * Fix URL redirect after form submit * Mock locationService * Separate Form component * Update fields * Add more fields * Add more fields * Fix spacing * Add UserMapping fields * Add rest of the fields * Add FieldRenderer * Update types * Update comment * Update feature toggle * Add checkbox * Do not submit form if there are errors * Fix revalidation * Redirect on success only * Fix redirect behavior * Add missing descriptions * Use inline checkbox * Add enabled field * Restore feature toggle * Remove source field from PUT request * Add URL to the fields * Add hidden prop to fields and sections * Add Delete button * Prettier * Add authStyle, still not working, description updates * Fix saving select values * Run prettier * Use defaultValue in Select field --------- Co-authored-by: Mihaly Gyongyosi --- .../src/components/Forms/Checkbox.tsx | 2 +- .../auth-config/AuthProvidersListPage.tsx | 4 +- .../features/auth-config/FieldRenderer.tsx | 149 +++++++ .../auth-config/ProviderConfigForm.test.tsx | 1 + .../auth-config/ProviderConfigForm.tsx | 268 +++++++------ public/app/features/auth-config/fields.ts | 120 ------ public/app/features/auth-config/fields.tsx | 372 ++++++++++++++++++ public/app/features/auth-config/types.ts | 19 +- public/app/features/auth-config/utils/data.ts | 15 +- 9 files changed, 689 insertions(+), 261 deletions(-) create mode 100644 public/app/features/auth-config/FieldRenderer.tsx delete mode 100644 public/app/features/auth-config/fields.ts create mode 100644 public/app/features/auth-config/fields.tsx diff --git a/packages/grafana-ui/src/components/Forms/Checkbox.tsx b/packages/grafana-ui/src/components/Forms/Checkbox.tsx index 1802382d588..74716ec57d5 100644 --- a/packages/grafana-ui/src/components/Forms/Checkbox.tsx +++ b/packages/grafana-ui/src/components/Forms/Checkbox.tsx @@ -12,7 +12,7 @@ export interface CheckboxProps extends Omit, 'value' /** Label to display next to checkbox */ label?: string; /** Description to display under the label */ - description?: string; + description?: string | React.ReactElement; /** Current value of the checkbox */ value?: boolean; /** htmlValue allows to specify the input "value" attribute */ diff --git a/public/app/features/auth-config/AuthProvidersListPage.tsx b/public/app/features/auth-config/AuthProvidersListPage.tsx index 53d31756529..77acdcc2c01 100644 --- a/public/app/features/auth-config/AuthProvidersListPage.tsx +++ b/public/app/features/auth-config/AuthProvidersListPage.tsx @@ -75,8 +75,8 @@ export const AuthConfigPageUnconnected = ({ ) : ( {providerList - // Temporarily filter providers that don't have the UI implemented - .filter(({ provider }) => !['grafana_com', 'generic_oauth'].includes(provider)) + // Temporarily filter out providers that don't have the UI implemented + .filter(({ provider }) => !['grafana_com'].includes(provider)) .map(({ provider, settings }) => ( , 'register' | 'control' | 'watch' | 'setValue' | 'unregister'> { + field: SSOSettingsField; + errors: UseFormReturn['formState']['errors']; + secretConfigured: boolean; +} + +export const FieldRenderer = ({ + field, + register, + errors, + watch, + setValue, + control, + unregister, + secretConfigured, +}: FieldRendererProps) => { + const [isSecretConfigured, setIsSecretConfigured] = useState(secretConfigured); + const isDependantField = typeof field !== 'string'; + const name = isDependantField ? field.name : field; + const parentValue = isDependantField ? watch(field.dependsOn) : null; + const fieldData = fieldMap[name]; + const theme = useTheme2(); + // Unregister a field that depends on a toggle to clear its data + useEffect(() => { + if (isDependantField) { + if (!parentValue) { + unregister(name); + } + } + }, [unregister, name, parentValue, isDependantField]); + + if (!field) { + console.log('missing field:', name); + return null; + } + + // Dependant field means the field depends on another field's value and shouldn't be rendered if the parent field is false + if (isDependantField) { + const parentValue = watch(field.dependsOn); + if (!parentValue) { + return null; + } + } + const fieldProps = { + label: fieldData.label, + required: !!fieldData.validation?.required, + invalid: !!errors[name], + error: fieldData.validation?.message, + key: name, + description: fieldData.description, + defaultValue: fieldData.defaultValue, + }; + + switch (fieldData.type) { + case 'text': + return ( + + + + ); + case 'secret': + return ( + + ( + { + setIsSecretConfigured(false); + setValue(name, ''); + }} + /> + )} + /> + + ); + case 'select': + const watchOptions = watch(name); + let options = fieldData.options; + + if (!fieldData.options?.length) { + options = isSelectableValue(watchOptions) ? watchOptions : [{ label: '', value: '' }]; + } + return ( + + { + return ( + - - ); - case 'secret': - return ( - - ( - { - setIsSecretConfigured(false); - setValue(name, ''); - }} - /> - )} - /> - - ); - case 'select': - const watchOptions = watch(name); - const options = isSelectableValue(watchOptions) ? watchOptions : [{ label: '', value: '' }]; - return ( - - { - return ( -