Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions admin-ui/plugins/saml/components/SamlConfigurationForm.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import { useFormik } from 'formik'
import React, { useState, useEffect, useMemo, useCallback, memo, useRef } from 'react'
import { Row, Col, Form, FormGroup, CustomInput } from 'Components'
import { useDispatch, useSelector } from 'react-redux'
import GluuCommitDialog from 'Routes/Apps/Gluu/GluuCommitDialog'
import GluuFormFooter from 'Routes/Apps/Gluu/GluuFormFooter'
import GluuLoader from 'Routes/Apps/Gluu/GluuLoader'
import { useCedarling } from '@/cedarling'
import GluuLabel from 'Routes/Apps/Gluu/GluuLabel'
import GluuToogleRow from 'Routes/Apps/Gluu/GluuToogleRow'
import { useTranslation } from 'react-i18next'
import { putSamlProperties, getSamlConfiguration } from 'Plugins/saml/redux/features/SamlSlice'
import SetTitle from 'Utils/SetTitle'
import { adminUiFeatures } from 'Plugins/admin/helper/utils'
import { ADMIN_UI_RESOURCES } from '@/cedarling/utility'
import { CEDAR_RESOURCE_SCOPES } from '@/cedarling/constants/resourceScopes'
import { samlConfigurationValidationSchema } from '../helper/validations'
import { transformToFormValues } from '../helper/utils'
import { useSamlConfiguration, useUpdateSamlConfiguration } from './hooks'
import type { SamlConfigurationFormValues } from '../types'
import type { SamlRootState } from '../types/state'

const DOC_SECTION = 'samlConfiguration' as const

const SamlConfigurationForm: React.FC = () => {
const { t } = useTranslation()
const { authorizeHelper, hasCedarWritePermission } = useCedarling()
const dispatch = useDispatch()
const [modal, setModal] = useState<boolean>(false)
const { configuration, loading } = useSelector((state: SamlRootState) => state.idpSamlReducer)
SetTitle(t('titles.saml_management'))

useEffect(() => {
dispatch(getSamlConfiguration())
}, [dispatch])
// Use React Query hooks instead of Redux
const { data: configuration, isLoading: queryLoading } = useSamlConfiguration()
const updateConfigMutation = useUpdateSamlConfiguration()
const loading = queryLoading || updateConfigMutation.isPending

SetTitle(t('titles.saml_management'))

const samlResourceId = useMemo(() => ADMIN_UI_RESOURCES.SAML, [])
const samlScopes = useMemo(() => CEDAR_RESOURCE_SCOPES[samlResourceId], [samlResourceId])
Expand Down Expand Up @@ -61,14 +59,17 @@ const SamlConfigurationForm: React.FC = () => {
})

const handleSubmit = useCallback(
(values: SamlConfigurationFormValues, messages: string) => {
dispatch(
putSamlProperties({
action: { action_message: messages, action_data: values },
}),
)
async (values: SamlConfigurationFormValues, messages: string) => {
try {
await updateConfigMutation.mutateAsync({
data: values,
userMessage: messages,
})
} catch (error) {
console.error('Failed to update SAML configuration:', error)
}
},
[dispatch],
[updateConfigMutation],
)

const { setFieldValue, resetForm, handleSubmit: formikHandleSubmit } = formik
Expand Down
18 changes: 5 additions & 13 deletions admin-ui/plugins/saml/components/SamlPage.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import React, { useMemo, useCallback } from 'react'
import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle'
import { Card, CardBody } from 'Components'
import GluuLoader from 'Routes/Apps/Gluu/GluuLoader'
import GluuTabs from 'Routes/Apps/Gluu/GluuTabs'
import SetTitle from 'Utils/SetTitle'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { ROUTES } from '@/helpers/navigation'
import SamlConfigurationForm from './SamlConfigurationForm'
import WebsiteSsoIdentityBrokeringList from './WebsiteSsoIdentityBrokeringList'
import WebsiteSsoServiceProviderList from './WebsiteSsoServiceProviderList'
import type { SamlRootState } from '../types/state'

const SamlPage = React.memo(() => {
const { t } = useTranslation()
const { loadingSamlIdp, loadingWebsiteSsoServiceProvider } = useSelector(
(state: SamlRootState) => state.idpSamlReducer,
)

SetTitle(t('titles.saml_management'))

Expand Down Expand Up @@ -46,13 +40,11 @@ const SamlPage = React.memo(() => {
)

return (
<GluuLoader blocking={loadingSamlIdp || loadingWebsiteSsoServiceProvider}>
<Card className="mb-3" style={applicationStyle.mainCard}>
<CardBody>
<GluuTabs tabNames={tabNames} tabToShow={tabToShow} withNavigation={true} />
</CardBody>
</Card>
</GluuLoader>
<Card className="mb-3" style={applicationStyle.mainCard}>
<CardBody>
<GluuTabs tabNames={tabNames} tabToShow={tabToShow} withNavigation={true} />
</CardBody>
</Card>
)
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React, { useCallback, useEffect, useContext, useMemo, useState, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { debounce } from 'lodash'
import { getSamlIdentities, deleteSamlIdentity } from 'Plugins/saml/redux/features/SamlSlice'
import MaterialTable, { type Action } from '@material-table/core'
import { useTranslation } from 'react-i18next'
import GluuViewWrapper from 'Routes/Apps/Gluu/GluuViewWrapper'
Expand All @@ -20,8 +18,7 @@ import { ADMIN_UI_RESOURCES } from '@/cedarling/utility'
import { CEDAR_RESOURCE_SCOPES } from '@/cedarling/constants/resourceScopes'
import { useAppNavigation, ROUTES } from '@/helpers/navigation'
import { PaperContainer, getIdentityProviderTableCols } from '../helper/tableUtils'
import type { SamlIdentity } from '../types/redux'
import type { SamlRootState } from '../types/state'
import { useIdentityProviders, useDeleteIdentityProvider, type IdentityProvider } from './hooks'

interface DeleteItem {
inum?: string
Expand Down Expand Up @@ -51,12 +48,23 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
const prevPatternRef = useRef<string | null>(null)

const { t } = useTranslation()
const dispatch = useDispatch()
const { navigateToRoute } = useAppNavigation()
const { items, loadingSamlIdp, totalItems } = useSelector(
(state: SamlRootState) => state.idpSamlReducer,

const queryParams = useMemo(
() => ({
startIndex: pageNumber * limit,
limit,
...(pattern ? { pattern } : {}),
}),
[pageNumber, limit, pattern],
)

const { data: idpData, isLoading: loadingSamlIdp } = useIdentityProviders(queryParams)
const deleteIdentityProviderMutation = useDeleteIdentityProvider()

const items = idpData?.entries ?? []
const totalItems = idpData?.totalEntriesCount ?? 0

const samlResourceId = useMemo(() => ADMIN_UI_RESOURCES.SAML, [])
const samlScopes = useMemo(() => CEDAR_RESOURCE_SCOPES[samlResourceId], [samlResourceId])
const canReadIdentities = useMemo(
Expand Down Expand Up @@ -97,22 +105,10 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
}
}, [pattern])

useEffect(() => {
if (!canReadIdentities) return
const startIndex = pageNumber * limit
dispatch(
getSamlIdentities({
startIndex,
limit,
...(pattern ? { pattern } : {}),
}),
)
}, [dispatch, canReadIdentities, pageNumber, limit, pattern])

const toggle = useCallback(() => setModal((prev) => !prev), [])

const handleGoToEditPage = useCallback(
(rowData: SamlIdentity, viewOnly?: boolean): void => {
(rowData: IdentityProvider, viewOnly?: boolean): void => {
navigateToRoute(ROUTES.SAML_IDP_EDIT, { state: { rowData: rowData, viewOnly: viewOnly } })
},
[navigateToRoute],
Expand All @@ -123,15 +119,15 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
}, [navigateToRoute])

const handleDelete = useCallback(
(row: SamlIdentity): void => {
setItem(row)
(row: IdentityProvider): void => {
setItem({ inum: row.inum, displayName: row.displayName })
toggle()
},
[toggle],
)

const onDeletionConfirmed = useCallback(
(message: string): void => {
async (message: string): Promise<void> => {
if (!item.inum) {
return
}
Expand All @@ -140,17 +136,17 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
action_data: '',
}
buildPayload(userAction, message, item.inum)
dispatch(
deleteSamlIdentity({
action: {
action_message: userAction.action_message,
action_data: userAction.action_data,
},
}),
)
try {
await deleteIdentityProviderMutation.mutateAsync({
inum: userAction.action_data,
userMessage: userAction.action_message,
})
} catch (error) {
console.error('Failed to delete identity provider:', error)
}
toggle()
},
[dispatch, item.inum, toggle],
[deleteIdentityProviderMutation, item.inum, toggle],
)

const onRowCountChangeClick = useCallback((count: number): void => {
Expand Down Expand Up @@ -229,15 +225,18 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
}, [limit, searchInput, handleOptionsChange, handleOptionsKeyDown])

const tableActions = useMemo(() => {
const actions: Action<SamlIdentity>[] = []
const actions: Action<IdentityProvider>[] = []
if (canWriteIdentities) {
actions.push({
icon: 'edit',
tooltip: `${t('titles.edit_identity_provider')}`,
iconProps: { style: { color: customColors.darkGray } },
onClick: (_event: React.MouseEvent, rowData: SamlIdentity | SamlIdentity[]): void => {
onClick: (
_event: React.MouseEvent,
rowData: IdentityProvider | IdentityProvider[],
): void => {
if (Array.isArray(rowData)) return
const { tableData, ...clean } = rowData as SamlIdentity & { tableData?: unknown }
const { tableData, ...clean } = rowData as IdentityProvider & { tableData?: unknown }
void tableData
handleGoToEditPage(clean)
},
Expand All @@ -254,7 +253,10 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
actions.push({
icon: 'visibility',
tooltip: `${t('titles.view_identity_provider')}`,
onClick: (_event: React.MouseEvent, rowData: SamlIdentity | SamlIdentity[]): void => {
onClick: (
_event: React.MouseEvent,
rowData: IdentityProvider | IdentityProvider[],
): void => {
if (Array.isArray(rowData)) return
handleGoToEditPage(rowData, true)
},
Expand All @@ -265,7 +267,10 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
icon: DeleteOutlinedIcon,
iconProps: { color: 'secondary' },
tooltip: `${t('titles.delete_identity_provider')}`,
onClick: (_event: React.MouseEvent, rowData: SamlIdentity | SamlIdentity[]): void => {
onClick: (
_event: React.MouseEvent,
rowData: IdentityProvider | IdentityProvider[],
): void => {
if (Array.isArray(rowData)) return
handleDelete(rowData)
},
Expand All @@ -285,7 +290,7 @@ const WebsiteSsoIdentityBrokeringList = React.memo(() => {
iconProps: { color: 'primary' },
isFreeAction: true,
onClick: handleRefresh,
} as Action<SamlIdentity> & { 'data-testid'?: string })
} as Action<IdentityProvider> & { 'data-testid'?: string })
return actions
}, [
canWriteIdentities,
Expand Down
Loading
Loading