Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ba71dcf
refactor(admin-ui): migrate permission gating to Cedarling usePermiss…
faisalsiddique4400 Jun 9, 2026
749e9d5
coderabbit fixes
faisalsiddique4400 Jun 9, 2026
0a4212f
cedarling permission tab fixes
faisalsiddique4400 Jun 9, 2026
c221786
storage util added
faisalsiddique4400 Jun 9, 2026
ee446ec
cedarling reivew fixed
faisalsiddique4400 Jun 9, 2026
ff816e9
leftover cleanup
faisalsiddique4400 Jun 9, 2026
af85fa1
chore(admin-ui): redundant dependencies and unscanned dead test code …
faisalsiddique4400 Jun 9, 2026
1d05d9c
merge with main
faisalsiddique4400 Jun 10, 2026
514b317
further clenaup
faisalsiddique4400 Jun 10, 2026
858c0f3
tooltip implemented
faisalsiddique4400 Jun 10, 2026
068ea85
coderabbit fixes
faisalsiddique4400 Jun 10, 2026
a8b58c7
coderabbit fixes
faisalsiddique4400 Jun 10, 2026
b848ffb
idletimer and file picker design fixed
faisalsiddique4400 Jun 11, 2026
30ec8e4
coderabbit fixes
faisalsiddique4400 Jun 11, 2026
5a92717
chore(admin-ui): removal two more redundant UI dependencies (#2878)
faisalsiddique4400 Jun 11, 2026
3608d7d
autocomplete fixed
faisalsiddique4400 Jun 11, 2026
dedf767
merge with main
faisalsiddique4400 Jun 12, 2026
a123a11
coderabbit fixes
faisalsiddique4400 Jun 12, 2026
dd81cee
merge with main
faisalsiddique4400 Jun 12, 2026
bc14a81
coderabbit fix
faisalsiddique4400 Jun 12, 2026
0abafe6
merge with main
faisalsiddique4400 Jun 16, 2026
7e9becf
knip cleanup
faisalsiddique4400 Jun 16, 2026
5b72041
error fixed
faisalsiddique4400 Jun 16, 2026
76ce049
user issue fixed
faisalsiddique4400 Jun 16, 2026
6a5febf
user issue fixed
faisalsiddique4400 Jun 16, 2026
538f4ee
gap fixed
faisalsiddique4400 Jun 16, 2026
f1ce1de
gap fixed in cedarling
faisalsiddique4400 Jun 16, 2026
71c9a13
coderabbit fix
faisalsiddique4400 Jun 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
6 changes: 4 additions & 2 deletions admin-ui/app/components/GluuTable/GluuTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import GluuText from '@/routes/Apps/Gluu/GluuText'
import { GluuButton } from '@/components/GluuButton'
import { GluuSpinner } from '@/components/GluuSpinner'
import { useStyles, TABLE_MIN_WIDTH, TABLE_RESPONSIVE_BREAKPOINT } from './GluuTable.style'
import { T_KEYS } from './constants'
import { T_KEYS, EMPTY_CELL_PLACEHOLDER } from './constants'
import type { CellValue, ColumnKey, GluuTableProps, SortDirection } from './types'
import { ChevronIcon } from '@/components/SVG'
import {
Expand Down Expand Up @@ -652,7 +652,9 @@ const GluuTable = <T,>(props: Readonly<GluuTableProps<T>>) => {
})
) : (
<GluuText variant="span" disableThemeColor>
{String(value ?? '')}
{value === null || value === undefined || value === ''
? EMPTY_CELL_PLACEHOLDER
: String(value)}
</GluuText>
)}
</td>
Expand Down
2 changes: 2 additions & 0 deletions admin-ui/app/components/GluuTable/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const COLUMN_WIDTHS = {
PILL_LIST: 280,
} as const

export const EMPTY_CELL_PLACEHOLDER = '—'

export const T_KEYS = {
FIELDS_ACTIONS: 'fields.actions',
FIELDS_OF: 'fields.of',
Expand Down
5 changes: 2 additions & 3 deletions admin-ui/app/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { LayoutNavbar } from './LayoutNavbar'
import { LayoutSidebar } from './LayoutSidebar'
import { PageConfigContext } from './PageConfigContext'
import { ThemeClass } from './../Theme'
import { siteDescription, siteKeywords } from '@/config/site'
import type {
LayoutPartComponentType,
LayoutProps,
Expand Down Expand Up @@ -89,8 +88,8 @@ const initialLayoutState: LayoutState = {
screenSize: (typeof window !== 'undefined' ? getScreenSize() : '') as ScreenSize,
animationsDisabled: true,
pageTitle: null,
pageDescription: siteDescription,
pageKeywords: siteKeywords,
pageDescription: 'Jans-server admin Ui',
pageKeywords: 'jans-server oauth jans gluu',
}

const Layout: React.FC<LayoutProps> = (props) => {
Expand Down
1 change: 0 additions & 1 deletion admin-ui/app/components/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export { default as AccessTimeIcon } from '@mui/icons-material/AccessTime'
export { default as Add } from '@mui/icons-material/Add'
export { default as AddCircleOutline } from '@mui/icons-material/AddCircleOutlineOutlined'
export { default as CachedIcon } from '@mui/icons-material/Cached'
export { default as Check } from '@mui/icons-material/Check'
export { default as CheckCircleOutline } from '@mui/icons-material/CheckCircleOutlineOutlined'
Expand Down
2 changes: 0 additions & 2 deletions admin-ui/app/config/site.ts

This file was deleted.

18 changes: 18 additions & 0 deletions admin-ui/app/constants/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@ export const ICON_SIZE = {

export const ICON_BUTTON_SIZE = 32

export const TOGGLE = {
TRACK_WIDTH: 50,
TRACK_HEIGHT: 24,
TRACK_RADIUS: 30,
THUMB_SIZE: 22,
THUMB_INSET: 1,
THUMB_CHECKED_LEFT: 27,
ICON_HEIGHT: 10,
CHECK_WIDTH: 14,
CHECK_LEFT: 8,
X_WIDTH: 10,
X_RIGHT: 10,
FOCUS_RING_BLUR: 2,
FOCUS_RING_SPREAD: 3,
ACTIVE_RING_BLUR: 5,
ACTIVE_RING_SPREAD: 5,
} as const

export const TOOLTIP = {
ARROW_SIZE: 8,
PADDING_VERTICAL: 8,
Expand Down
4 changes: 2 additions & 2 deletions admin-ui/app/layout/components/DefaultSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { Link } from 'react-router-dom'
import { useAppSelector } from '@/redux/hooks'
import { Sidebar } from 'Components'
import { LogoThemed } from 'Routes/components/LogoThemed/LogoThemed'
import GluuSuspenseLoader from 'Routes/Apps/Gluu/GluuSuspenseLoader'
import GluuText from '@/routes/Apps/Gluu/GluuText'
import GluuAppSidebar from 'Routes/Apps/Gluu/GluuAppSidebar'
import type { DefaultSidebarProps } from './types'
import { useTranslation } from 'react-i18next'
import { ROUTES } from '@/helpers/navigation'
import { useStyles } from './DefaultSidebar.style'
import { GluuSpinner } from '@/components/GluuSpinner'

const DefaultSidebar: React.FC<DefaultSidebarProps> = () => {
const { t } = useTranslation()
Expand All @@ -26,7 +26,7 @@ const DefaultSidebar: React.FC<DefaultSidebarProps> = () => {
</div>
) : (
<div className={classes.sidebarLoaderRoot}>
<GluuSuspenseLoader />
<GluuSpinner />
</div>
)

Expand Down
1 change: 0 additions & 1 deletion admin-ui/app/layout/default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { STORAGE_KEYS } from '@/constants'

import 'Styles/bootstrap.scss'
import 'Styles/main.scss'
import 'Styles/plugins/plugins.css'
import 'Styles/plugins/plugins.scss'

import { RoutedNavbars, RoutedSidebars } from '../routes'
Expand Down
105 changes: 58 additions & 47 deletions admin-ui/app/routes/Apps/Gluu/GluuAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const GluuAutocomplete = ({
const { t } = useTranslation()
const { state: themeState } = useTheme()
const selectedTheme = themeState?.theme ?? DEFAULT_THEME
const themeColors = getThemeColor(selectedTheme)
const themeColors = React.useMemo(() => getThemeColor(selectedTheme), [selectedTheme])
const { classes } = useStyles({
themeColors,
allowCustom,
Expand All @@ -63,7 +63,7 @@ const GluuAutocomplete = ({
const resolvedHelperText = helperText ?? t('messages.multi_select_hint')

const optionValues = React.useMemo(
() => options.map((o) => (typeof o === 'string' ? o : o.value)),
() => [...new Set(options.map((o) => (typeof o === 'string' ? o : o.value)))],
[options],
)
const labelByValue = React.useMemo(() => {
Expand All @@ -81,13 +81,62 @@ const GluuAutocomplete = ({
[labelByValue],
)

const selectedItems = Array.isArray(value)
? value.filter((v): v is string => typeof v === 'string')
: []
const selectedItems = React.useMemo(
() =>
Array.isArray(value)
? [...new Set(value.filter((v): v is string => typeof v === 'string'))]
: [],
[value],
)

const [inputValue, setInputValue] = React.useState('')
const lockedPlacementRef = React.useRef<Placement | null>(null)

const autocompleteOptions = React.useMemo(
() =>
allowCustom
? [...optionValues, ...selectedItems.filter((s) => !optionValues.includes(s))]
: optionValues,
[allowCustom, optionValues, selectedItems],
)

const popperSlotProps = React.useMemo(
() => ({
paper: { className: classes.dropdownPaper },
popper: {
placement: 'bottom-start' as const,
className: classes.popperRoot,
modifiers: [
{
name: 'computeStyles',
options: { adaptive: false, gpuAcceleration: false },
},
{
name: 'sameWidth',
enabled: true,
phase: 'afterWrite' as const,
fn: sameWidthModifier,
},
{
name: 'lockPlacement',
enabled: true,
phase: 'main' as const,
requires: ['flip'],
fn: ({ state }: ModifierArguments<Obj>) => {
if (lockedPlacementRef.current == null) {
lockedPlacementRef.current = state.placement
} else if (state.placement !== lockedPlacementRef.current) {
state.placement = lockedPlacementRef.current
state.reset = true
}
},
},
],
},
}),
[classes.dropdownPaper, classes.popperRoot],
)

const handleChange = useCallback(
(_event: React.SyntheticEvent, newValue: string[]) => {
const normalized = newValue
Expand Down Expand Up @@ -161,11 +210,7 @@ const GluuAutocomplete = ({
onSearch?.(val)
}
}}
options={
allowCustom
? [...optionValues, ...selectedItems.filter((s) => !optionValues.includes(s))]
: optionValues
}
options={autocompleteOptions}
value={selectedItems}
isOptionEqualToValue={(option, val) => option === val}
onChange={handleChange}
Expand All @@ -178,41 +223,7 @@ const GluuAutocomplete = ({
disableCloseOnSelect
disablePortal
className={classes.autocompleteRoot}
slotProps={{
paper: {
className: classes.dropdownPaper,
},
popper: {
placement: 'bottom-start' as const,
className: classes.popperRoot,
modifiers: [
{
name: 'computeStyles',
options: { adaptive: false, gpuAcceleration: false },
},
{
name: 'sameWidth',
enabled: true,
phase: 'afterWrite' as const,
fn: sameWidthModifier,
},
{
name: 'lockPlacement',
enabled: true,
phase: 'main' as const,
requires: ['flip'],
fn: ({ state }: ModifierArguments<Obj>) => {
if (lockedPlacementRef.current == null) {
lockedPlacementRef.current = state.placement
} else if (state.placement !== lockedPlacementRef.current) {
state.placement = lockedPlacementRef.current
state.reset = true
}
},
},
],
},
}}
slotProps={popperSlotProps}
forcePopupIcon
popupIcon={<ChevronIcon width={20} height={20} direction="down" />}
filterOptions={filterOptions}
Expand Down Expand Up @@ -268,8 +279,8 @@ const GluuAutocomplete = ({
const trimmed = inputValue.trim()
if (
trimmed &&
!optionValues.some((o) =>
getDisplayLabel(o).toLowerCase().includes(trimmed.toLowerCase()),
!optionValues.some(
(o) => getDisplayLabel(o).toLowerCase() === trimmed.toLowerCase(),
) &&
!selectedItems.some(
(s) => getDisplayLabel(s).toLowerCase() === trimmed.toLowerCase(),
Expand Down
61 changes: 0 additions & 61 deletions admin-ui/app/routes/Apps/Gluu/GluuBooleanSelectBox.tsx

This file was deleted.

4 changes: 3 additions & 1 deletion admin-ui/app/routes/Apps/Gluu/GluuCommitDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ const GluuCommitDialog = ({
{operations.map((operation, index) => (
<div key={`${operation.path}-${index}`} className={classes.operationRow}>
<span className={classes.operationLabel}>{t('set')}</span>
<span className={classes.operationBadge}>{operation.path}</span>
<span className={classes.operationBadge}>
{operation.label || operation.path}
</span>
<span className={classes.operationLabel}>{t('to')}</span>
<span className={classes.operationBadge}>
{operation.value === null || operation.value === ''
Expand Down
28 changes: 15 additions & 13 deletions admin-ui/app/routes/Apps/Gluu/GluuInlineInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Check, Close } from '@/components/icons'
import { OPACITY } from '@/constants'
import GluuLabel from './GluuLabel'
import GluuToggle from './GluuToggle'
import { Typeahead } from 'react-bootstrap-typeahead'
import GluuAutocomplete from './GluuAutocomplete'
import type { AutocompleteOption } from './types/GluuAutocomplete.types'
import applicationStyle from '@/routes/Apps/Gluu/styles/applicationStyle'
import { useStyles } from '@/routes/Apps/Gluu/styles/GluuInlineInput.style'
import { Col, FormGroup, Input, Button } from 'Components'
Expand Down Expand Up @@ -137,8 +138,11 @@ const GluuInlineInput = ({
[value],
)

const filteredOptions = useMemo(
() => (Array.isArray(options) ? options.filter((item) => item != null) : []),
const filteredOptions = useMemo<AutocompleteOption[]>(
() =>
Array.isArray(options)
? options.filter((item) => item != null).map((item) => ({ value: item, label: item }))
: [],
[options],
)
const resolvedId = id || name
Expand Down Expand Up @@ -173,21 +177,19 @@ const GluuInlineInput = ({
data-testid={resolvedId}
name={name}
handler={onValueChanged}
value={value as boolean}
value={Boolean(data)}
disabled={disabled}
/>
)}
{isArray && (
<Typeahead
id={resolvedId}
data-testid={resolvedId}
allowNew
emptyLabel=""
labelKey={name}
onChange={handleTypeAheadChange}
multiple={true}
defaultSelected={filteredValue}
<GluuAutocomplete
hideLabel
allowCustom
name={name}
label={label}
value={filteredValue}
options={filteredOptions}
onChange={handleTypeAheadChange}
disabled={disabled}
/>
)}
Expand Down
Loading
Loading