Skip to content

Commit 7a0d70d

Browse files
committed
fix: treat empty enabled list as default (all features) in useTenantFeatures
An empty features.enabled array is treated the same as an absent config — fall back to all features. This avoids the inconsistency where defaultFeature could resolve to a feature not present in the enabled set.
1 parent 26d2395 commit 7a0d70d

2 files changed

Lines changed: 13 additions & 9 deletions

File tree

frontend/src/hooks/__tests__/use-tenant-features.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe('useTenantFeatures', () => {
139139
expect(result.current.defaultFeature).toBe('accounts')
140140
})
141141

142-
it('returns empty string for defaultFeature when no features are enabled', () => {
142+
it('falls back to all features when enabled list is empty', () => {
143143
vi.mocked(useTenantContext).mockReturnValue(
144144
makeContext({
145145
tenantConfig: {
@@ -152,8 +152,9 @@ describe('useTenantFeatures', () => {
152152

153153
const { result } = renderHook(() => useTenantFeatures())
154154

155-
// No enabled features — defaultFeature must not point to a disabled feature
156-
expect(result.current.defaultFeature).toBe('')
157-
expect(result.current.isFeatureEnabled('dashboard')).toBe(false)
155+
// Empty enabled list is treated as "use defaults" — all features enabled
156+
expect(result.current.enabledFeatures).toEqual([...ALL_FEATURES])
157+
expect(result.current.isFeatureEnabled('dashboard')).toBe(true)
158+
expect(result.current.defaultFeature).toBe('dashboard')
158159
})
159160
})

frontend/src/hooks/use-tenant-features.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ export function useTenantFeatures(): TenantFeaturesResult {
1919

2020
return useMemo(() => {
2121
const config = tenantConfig ?? DEFAULT_UI_CONFIG
22-
const enabledFeatures = config.features?.enabled ?? [...ALL_FEATURES]
22+
23+
// Treat an empty enabled list the same as an absent one — fall back to all features
24+
const configuredEnabled = config.features?.enabled ?? [...ALL_FEATURES]
25+
const enabledFeatures = configuredEnabled.length > 0 ? configuredEnabled : [...ALL_FEATURES]
2326
const enabledSet = new Set<string>(enabledFeatures)
2427

25-
// Fall back to the first enabled feature if the configured default is not in the enabled list.
26-
// When no features are enabled at all, defaultFeature is an empty string (no valid default).
27-
const configuredDefault = config.features?.defaultFeature ?? 'dashboard'
28+
// Fall back to the first enabled feature if the configured default is not in the enabled list
29+
const configuredDefault =
30+
config.features?.defaultFeature ?? DEFAULT_UI_CONFIG.features!.defaultFeature!
2831
const defaultFeature = enabledSet.has(configuredDefault)
2932
? configuredDefault
30-
: (enabledFeatures[0] ?? '')
33+
: enabledFeatures[0]
3134

3235
return {
3336
isFeatureEnabled: (feature: string) => enabledSet.has(feature),

0 commit comments

Comments
 (0)