Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
785ca4f
feat(admin-ui): work in process fro the users
faisalsiddique4400 Mar 5, 2026
308d9b8
Merge branch with the main
faisalsiddique4400 Mar 5, 2026
8fa4507
feat(admin-ui): revamp User Management module as per Figma (#2630)
faisalsiddique4400 Mar 10, 2026
6589738
Merge branch 'main' into admin-ui-issue-2630
faisalsiddique4400 Mar 10, 2026
e52dfb1
Resolve code rabbit issues
faisalsiddique4400 Mar 10, 2026
49e8122
Merge branch 'admin-ui-issue-2630' of github-faisal:GluuFederation/fl…
faisalsiddique4400 Mar 10, 2026
1e904f1
Resolve code rabbit issues
faisalsiddique4400 Mar 10, 2026
e9dcc3a
feat(admin-ui): Resolve coderabbit issues
faisalsiddique4400 Mar 11, 2026
842e639
Resolve code rabbit issues
faisalsiddique4400 Mar 11, 2026
69792e1
Resolve code rabbit issues
faisalsiddique4400 Mar 11, 2026
bd3a5dc
color fixes
faisalsiddique4400 Mar 11, 2026
b4ae6ad
webhook issue fixed
faisalsiddique4400 Mar 11, 2026
683a937
webhook issue fixed
faisalsiddique4400 Mar 11, 2026
4a45359
pass issue
faisalsiddique4400 Mar 11, 2026
b271bc3
generalize modal spacing
faisalsiddique4400 Mar 12, 2026
60a1b34
form
faisalsiddique4400 Mar 12, 2026
44eb4e9
form colors fixed
faisalsiddique4400 Mar 12, 2026
cc91d7d
formatting applied
faisalsiddique4400 Mar 12, 2026
4c78fed
Initial commit
faisalsiddique4400 Mar 12, 2026
fec51f8
Initial commit
faisalsiddique4400 Mar 16, 2026
635b361
merged with main
faisalsiddique4400 Mar 16, 2026
5458592
theme changed fixed
faisalsiddique4400 Mar 16, 2026
b9432a1
code rabbit fixes
faisalsiddique4400 Mar 16, 2026
7df40ad
code rabbit fixes
faisalsiddique4400 Mar 16, 2026
b855509
code rabbit fixes
faisalsiddique4400 Mar 16, 2026
09d988c
code rabbit fixes
faisalsiddique4400 Mar 16, 2026
21bcafc
two newly added fields issue, fixed
faisalsiddique4400 Mar 16, 2026
71e88b3
two newly added fields issue, fixed
faisalsiddique4400 Mar 16, 2026
2c48115
code rabbit fixes
faisalsiddique4400 Mar 17, 2026
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
12 changes: 6 additions & 6 deletions admin-ui/app/cedarling/hooks/useCedarling.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useSelector, useDispatch } from 'react-redux'
import { useCallback } from 'react'
import { useAppDispatch, useAppSelector } from '@/redux/hooks'
import { setCedarlingPermission } from '@/redux/features/cedarPermissionsSlice'
import { cedarlingClient, buildCedarPermissionKey, CEDARLING_CONSTANTS } from '@/cedarling'
import type {
RootState,
UseCedarlingReturn,
AuthorizationResult,
ResourceScopeEntry,
Expand All @@ -13,25 +12,26 @@ import type {
import { OPENID, REVOKE_SESSION, SCIM_BULK, SSA_ADMIN, SSA_DEVELOPER } from '@/utils/PermChecker'
import { updateToast } from '@/redux/features/toastSlice'

const executeUrls = new Set([SSA_ADMIN, SSA_DEVELOPER, SCIM_BULK, REVOKE_SESSION, OPENID])

export function useCedarling(): UseCedarlingReturn {
const { ACTION_TYPE, RESOURCE_TYPE } = CEDARLING_CONSTANTS

const dispatch = useDispatch()
const dispatch = useAppDispatch()

const {
userinfo_jwt: userinfo_token,
idToken: id_token,
jwtToken: access_token,
} = useSelector((state: RootState) => state.authReducer)
} = useAppSelector((state) => state.authReducer)

const {
permissions: permissionsByResourceId,
loading: isLoading,
error,
initialized: cedarlingInitialized,
isInitializing,
} = useSelector((state: RootState) => state.cedarPermissions)
const executeUrls = new Set([SSA_ADMIN, SSA_DEVELOPER, SCIM_BULK, REVOKE_SESSION, OPENID])
} = useAppSelector((state) => state.cedarPermissions)

const getActionLabelFromUrl = useCallback((url: string): CedarAction => {
const lowerUrl = url.toLowerCase()
Expand Down
27 changes: 6 additions & 21 deletions admin-ui/app/components/App/PermissionsPolicyInitializer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useDispatch, useSelector } from 'react-redux'
import { useEffect, useState, useRef } from 'react'
import { useAppDispatch, useAppSelector } from '@/redux/hooks'
import {
setCedarFailedStatusAfterMaxTries,
setCedarlingInitialized,
Expand All @@ -8,23 +8,9 @@ import {
import { cedarlingClient, CedarlingLogType } from '@/cedarling'
import bootstrap from '@/cedarling/config/cedarling-bootstrap-TBAC.json'
import { devLogger } from '@/utils/devLogger'
// Extended state interface for this component
interface ExtendedRootState {
authReducer: {
hasSession?: boolean
config?: {
cedarlingLogType?: CedarlingLogType
}
}
cedarPermissions: {
initialized: boolean
isInitializing: boolean
policyStoreJson: string
}
}

const PermissionsPolicyInitializer = () => {
const dispatch = useDispatch()
const dispatch = useAppDispatch()

const retryCount = useRef({
tryCount: 0,
Expand All @@ -33,13 +19,12 @@ const PermissionsPolicyInitializer = () => {

const [maxRetries] = useState(10)

const hasSession = useSelector((state: ExtendedRootState) => state.authReducer.hasSession)
const { initialized, isInitializing, policyStoreJson } = useSelector(
(state: ExtendedRootState) => state.cedarPermissions,
const hasSession = useAppSelector((state) => state.authReducer.hasSession)
const { initialized, isInitializing, policyStoreJson } = useAppSelector(
(state) => state.cedarPermissions,
)
const cedarlingLogType =
useSelector((state: ExtendedRootState) => state.authReducer?.config?.cedarlingLogType) ||
CedarlingLogType.OFF
useAppSelector((state) => state.authReducer?.config?.cedarlingLogType) || CedarlingLogType.OFF

useEffect(() => {
// Helper function to check if policyStoreJson is valid
Expand Down
4 changes: 2 additions & 2 deletions admin-ui/app/constants/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export const MAPPING_SPACING = {
PAGE_PADDING_TOP: 53,
ALERT_TO_CARD: 24,
CARD_PADDING: 33,
CARD_HEADER_HEIGHT: 73,
CARD_BORDER_RADIUS: 16,
CARD_HEADER_HEIGHT: 52,
CARD_BORDER_RADIUS: 6,
CARD_MARGIN_BOTTOM: 16,
PERMISSION_ROW_GAP: 20,
PERMISSION_ITEM_GAP: 30,
Expand Down
24 changes: 24 additions & 0 deletions admin-ui/app/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@
"logging_level": "Logging Level",
"logging_layout": "Logging Layout",
"external_logger_configuration": "External Logger Configuration",
"disable_external_logger_configuration": "Disable External Logger",
"metric_reporter_interval": "Metric Reporter Interval",
"metric_reporter_keep_data_days": "Metric Reporter Keep Data Days",
"metric_reporter_enabled": "Enable Metric Reporter",
Expand Down Expand Up @@ -906,6 +907,29 @@
"smtp_username_required": "SMTP user name is required.",
"smtp_password_required": "SMTP user password is required.",
"no_configuration_loaded": "No configuration loaded",
"no_changes_detected": "No changes detected",
"scim_application_url_invalid": "Application URL must be a valid URL with http:// or https:// protocol",
"scim_protection_mode_invalid": "Protection Mode must be OAUTH or BYPASS",
"scim_max_count_type": "Max Count must be a number",
"scim_max_count_positive": "Max Count must be positive",
"scim_max_count_integer": "Max Count must be an integer",
"scim_max_count_max": "Max Count cannot exceed 2,147,483,647",
"scim_bulk_max_operations_type": "Bulk Max Operations must be a number",
"scim_bulk_max_operations_positive": "Bulk Max Operations must be positive",
"scim_bulk_max_operations_integer": "Bulk Max Operations must be an integer",
"scim_bulk_max_operations_max": "Bulk Max Operations cannot exceed 100,000",
"scim_bulk_max_payload_type": "Bulk Max Payload Size must be a number",
"scim_bulk_max_payload_positive": "Bulk Max Payload Size must be positive",
"scim_bulk_max_payload_integer": "Bulk Max Payload Size must be an integer",
"scim_bulk_max_payload_max": "Bulk Max Payload Size cannot exceed 100 MB (104,857,600 bytes)",
"scim_metric_interval_type": "Metric Reporter Interval must be a number",
"scim_metric_interval_positive": "Metric Reporter Interval must be positive",
"scim_metric_interval_integer": "Metric Reporter Interval must be an integer",
"scim_metric_interval_max": "Metric Reporter Interval cannot exceed 86,400 seconds (24 hours)",
"scim_metric_keep_days_type": "Metric Reporter Keep Data Days must be a number",
"scim_metric_keep_days_positive": "Metric Reporter Keep Data Days must be positive",
"scim_metric_keep_days_integer": "Metric Reporter Keep Data Days must be an integer",
"scim_metric_keep_days_max": "Metric Reporter Keep Data Days cannot exceed 3,650 days (10 years)",
"insufficient_permissions_to_modify": "You do not have permission to modify this configuration",
"action_commit_question": "Audit log: Want to apply changes made on this page?",
"list_of_changes": "List of changes",
Expand Down
24 changes: 24 additions & 0 deletions admin-ui/app/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@
"logging_level": "Nivel de Registro",
"logging_layout": "Formato de Registro",
"external_logger_configuration": "Configuración de Logger Externo",
"disable_external_logger_configuration": "Deshabilitar Logger Externo",
"metric_reporter_interval": "Intervalo del Informe de Métricas",
"metric_reporter_keep_data_days": "Días para Mantener Datos del Informe de Métricas",
"metric_reporter_enabled": "Habilitar Informe de Métricas",
Expand Down Expand Up @@ -905,6 +906,29 @@
"smtp_username_required": "El nombre de usuario SMTP es obligatorio.",
"smtp_password_required": "La contraseña de usuario SMTP es obligatoria.",
"no_configuration_loaded": "No se cargó ninguna configuración",
"no_changes_detected": "No se detectaron cambios",
"scim_application_url_invalid": "La URL de la aplicación debe ser una URL válida con protocolo http:// o https://",
"scim_protection_mode_invalid": "El modo de protección debe ser OAUTH o BYPASS",
"scim_max_count_type": "El conteo máximo debe ser un número",
"scim_max_count_positive": "El conteo máximo debe ser positivo",
"scim_max_count_integer": "El conteo máximo debe ser un número entero",
"scim_max_count_max": "El conteo máximo no puede exceder 2.147.483.647",
"scim_bulk_max_operations_type": "Las operaciones masivas máximas deben ser un número",
"scim_bulk_max_operations_positive": "Las operaciones masivas máximas deben ser positivas",
"scim_bulk_max_operations_integer": "Las operaciones masivas máximas deben ser un número entero",
"scim_bulk_max_operations_max": "Las operaciones masivas máximas no pueden exceder 100.000",
"scim_bulk_max_payload_type": "El tamaño máximo de carga masiva debe ser un número",
"scim_bulk_max_payload_positive": "El tamaño máximo de carga masiva debe ser positivo",
"scim_bulk_max_payload_integer": "El tamaño máximo de carga masiva debe ser un número entero",
"scim_bulk_max_payload_max": "El tamaño máximo de carga masiva no puede exceder 100 MB (104.857.600 bytes)",
"scim_metric_interval_type": "El intervalo del reportador de métricas debe ser un número",
"scim_metric_interval_positive": "El intervalo del reportador de métricas debe ser positivo",
"scim_metric_interval_integer": "El intervalo del reportador de métricas debe ser un número entero",
"scim_metric_interval_max": "El intervalo del reportador de métricas no puede exceder 86.400 segundos (24 horas)",
"scim_metric_keep_days_type": "Los días de retención de métricas deben ser un número",
"scim_metric_keep_days_positive": "Los días de retención de métricas deben ser positivos",
"scim_metric_keep_days_integer": "Los días de retención de métricas deben ser un número entero",
"scim_metric_keep_days_max": "Los días de retención de métricas no pueden exceder 3.650 días (10 años)",
"insufficient_permissions_to_modify": "No tiene permiso para modificar esta configuración",
"insufficient_token_read_permission": "El acceso a los datos del token no está concedido.",
"action_commit_question": "Registro de auditoría: ¿Desea aplicar los cambios realizados en esta página?",
Expand Down
1 change: 1 addition & 0 deletions admin-ui/app/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@
"logging_level": "Niveau de Journalisation",
"logging_layout": "Disposition de la Journalisation",
"external_logger_configuration": "Configuration du Journal Externe",
"disable_external_logger_configuration": "Désactiver le Journal Externe",
"metric_reporter_interval": "Intervalle du Rapporteur de Métriques",
"metric_reporter_keep_data_days": "Durée de Conservation des Données du Rapporteur de Métriques",
"metric_reporter_enabled": "Activer le Rapporteur de Métriques",
Expand Down
1 change: 1 addition & 0 deletions admin-ui/app/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@
"logging_level": "Nível de Registo",
"logging_layout": "Layout de Registo",
"external_logger_configuration": "Configuração de Registo Externo",
"disable_external_logger_configuration": "Desativar Registo Externo",
"metric_reporter_interval": "Intervalo do Relatório de Métricas",
"metric_reporter_keep_data_days": "Dias de Manutenção de Dados do Relatório de Métricas",
"metric_reporter_enabled": "Ativar Relatório de Métricas",
Expand Down
6 changes: 3 additions & 3 deletions admin-ui/app/routes/Apps/Gluu/GluuAppSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useContext, useMemo, useCallback, useRef } from 'react'
import { SidebarMenu, SidebarMenuItem } from 'Components'
import { useSelector } from 'react-redux'
import { useAppSelector } from '@/redux/hooks'
import { ErrorBoundary } from 'react-error-boundary'
import GluuErrorFallBack from './GluuErrorFallBack'
import { processMenus } from 'Plugins/PluginMenuResolver'
Expand Down Expand Up @@ -69,8 +69,8 @@ const selectLogoutAuditSucceeded = (state: RootState): boolean | null =>
state.logoutAuditReducer.logoutAuditSucceeded

function GluuAppSidebar(): JSX.Element {
const health = useSelector(selectHealth)
const logoutAuditSucceeded = useSelector(selectLogoutAuditSucceeded)
const health = useAppSelector(selectHealth)
const logoutAuditSucceeded = useAppSelector(selectLogoutAuditSucceeded)
const [pluginMenus, setPluginMenus] = useState<PluginMenu[]>([])
const didAnimateMenusRef = useRef<boolean>(false)
const isReady = pluginMenus.length > 0
Expand Down
6 changes: 2 additions & 4 deletions admin-ui/app/routes/Apps/Gluu/GluuRemovableSelectRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ interface GluuRemovableSelectRowProps {
formik: FormikProps<FormikValues>
values?: CountryOption[]
lsize?: number
rsize?: number
handler: () => void
doc_category?: string
isDirect?: boolean
Expand All @@ -30,21 +29,20 @@ interface GluuRemovableSelectRowProps {
setModifiedFields: React.Dispatch<React.SetStateAction<Record<string, ModifiedFieldValue>>>
}

function GluuRemovableSelectRow({
const GluuRemovableSelectRow = ({
label,
name,
value,
formik,
values = [],
lsize = 12,
rsize = 12,
handler,
doc_category,
isDirect,
hideRemoveButton,
modifiedFields,
setModifiedFields,
}: GluuRemovableSelectRowProps) {
}: GluuRemovableSelectRowProps) => {
const currentValue = (formik.values[name] as string | undefined) ?? value ?? ''

const { t } = useTranslation()
Expand Down
8 changes: 4 additions & 4 deletions admin-ui/app/routes/Apps/Gluu/GluuSessionTimeout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useRef, useState } from 'react'
import SessionTimeoutDialog from './GluuSessionTimeoutDialog'
import { withIdleTimer } from 'react-idle-timer'
import { useDispatch, useSelector } from 'react-redux'
import { useAppDispatch, useAppSelector } from '@/redux/hooks'
import { auditLogoutLogs } from 'Redux/features/sessionSlice'
import { useAppNavigation, ROUTES } from '@/helpers/navigation'
import { devLogger } from '@/utils/devLogger'
Expand All @@ -17,10 +17,10 @@ const SessionTimeout = ({ isAuthenticated }: any) => {
const [timeoutCountdown, setTimeoutCountdown] = useState(0)
const idleTimer = useRef(null)
const sessionTimeout =
useSelector((state: any) => state.authReducer?.config?.sessionTimeoutInMins) || 5
const { logoutAuditSucceeded } = useSelector((state: any) => state.logoutAuditReducer)
Number(useAppSelector((state) => state.authReducer?.config?.sessionTimeoutInMins)) || 5
const { logoutAuditSucceeded } = useAppSelector((state) => state.logoutAuditReducer)

const dispatch = useDispatch()
const dispatch = useAppDispatch()
const { navigateToRoute } = useAppNavigation()

const clearSessionTimeout = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,49 @@
import React, { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import React, { useCallback } from 'react'
import { useCedarling } from '@/cedarling'
import { ADMIN_UI_RESOURCES } from '@/cedarling/utility'
import { useAppSelector } from '@/redux/hooks'
import GluuCommitDialog from 'Routes/Apps/Gluu/GluuCommitDialog'
import GluuLoader from 'Routes/Apps/Gluu/GluuLoader'
import { useWebhookDialogAction } from 'Utils/hooks'
import { adminUiFeatures, type AdminUiFeatureKey } from 'Plugins/admin/helper/utils'
import type { GluuCommitDialogOperation } from 'Routes/Apps/Gluu/types/index'
import type { FormikProps } from 'formik'
import type { UserEditFormValues } from '../types/ComponentTypes'
import { revokeSessionWhenFieldsModifiedInUserForm } from '../helper/constants'

interface UserFormCommitDialogProps {
type GluuWebhookCommitDialogProps = {
handler: () => void
modal: boolean
onAccept: (message: string) => void | Promise<void>
formik: FormikProps<UserEditFormValues>
operations: GluuCommitDialogOperation[]
formik?: {
setFieldValue: (
field: string,
value: string,
shouldValidate?: boolean,
) => void | Promise<unknown>
} | null
operations?: GluuCommitDialogOperation[]
webhookFeature: string
autoCloseOnAccept?: boolean
webhookFeature: AdminUiFeatureKey
alertMessage?: string
alertSeverity?: 'error' | 'warning' | 'info' | 'success'
}

const UserFormCommitDialog = ({
const GluuWebhookCommitDialog: React.FC<GluuWebhookCommitDialogProps> = ({
handler,
modal,
onAccept,
formik,
operations,
autoCloseOnAccept = false,
webhookFeature,
}: UserFormCommitDialogProps) => {
const { t } = useTranslation()
autoCloseOnAccept = false,
alertMessage,
alertSeverity,
}) => {
const { hasCedarReadPermission } = useCedarling()
const canReadWebhooks = hasCedarReadPermission(ADMIN_UI_RESOURCES.Webhooks)
const webhookModal = useAppSelector((state) => state.webhookReducer?.webhookModal ?? false)
const { webhookTriggerModal, onCloseModal, webhookCheckComplete } = useWebhookDialogAction({
feature: adminUiFeatures[webhookFeature],
feature: webhookFeature,
modal,
})

const sessionRevokeAlert = useMemo(() => {
const hasSessionRevokingField = operations.some((op) =>
revokeSessionWhenFieldsModifiedInUserForm.includes(op.path),
)
return hasSessionRevokingField ? t('messages.revokeUserSession') : undefined
}, [operations, t])

const handleClose = useCallback(() => {
handler()
onCloseModal()
Expand All @@ -68,10 +65,10 @@ const UserFormCommitDialog = ({
formik={formik}
operations={operations}
autoCloseOnAccept={autoCloseOnAccept}
alertMessage={sessionRevokeAlert}
alertSeverity="warning"
alertMessage={alertMessage}
alertSeverity={alertSeverity}
/>
)
}

export default React.memo(UserFormCommitDialog)
export default React.memo(GluuWebhookCommitDialog)
5 changes: 2 additions & 3 deletions admin-ui/app/routes/Apps/Gluu/GluuWebhookErrorDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useMemo, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch } from 'react-redux'
import { useAppSelector } from '@/redux/hooks'
import { useAppDispatch, useAppSelector } from '@/redux/hooks'
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'
import {
setShowErrorModal,
Expand All @@ -19,7 +18,7 @@ import type { WebhookTriggerResponseItem } from 'Plugins/admin/redux/types/webho

const GluuWebhookErrorDialog = () => {
const { t } = useTranslation()
const dispatch = useDispatch()
const dispatch = useAppDispatch()
const webhookState = useAppSelector((state) => state.webhookReducer)
const { hasCedarReadPermission, authorizeHelper } = useCedarling()
const { state: themeState } = useTheme()
Expand Down
Loading
Loading