@ibdop/platform-kit 1.0.10 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useFeatures.d.ts +98 -0
- package/dist/hooks/useFeatures.d.ts.map +1 -0
- package/dist/index.js +10 -10
- package/dist/index.mjs +811 -603
- package/dist/index.umd.js +10 -10
- package/dist/types/index.d.ts +88 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useFeatures.ts +445 -0
- package/src/types/index.ts +99 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for working with feature toggles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useState, useEffect, useCallback, useMemo } from 'react'
|
|
6
|
+
import { useShellAuth } from './useShellAuth'
|
|
7
|
+
import type {
|
|
8
|
+
FeatureToggleInfo,
|
|
9
|
+
FeaturesResponse,
|
|
10
|
+
FeatureToggleAdmin,
|
|
11
|
+
FeatureAdminResponse,
|
|
12
|
+
FeatureCreateRequest,
|
|
13
|
+
FeatureUpdateRequest,
|
|
14
|
+
MicrofrontendWithFeatures,
|
|
15
|
+
MicrofrontendsFeaturesResponse,
|
|
16
|
+
} from '../types'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Result of useFeatures hook
|
|
20
|
+
*/
|
|
21
|
+
export interface UseFeaturesResult {
|
|
22
|
+
features: FeatureToggleInfo[]
|
|
23
|
+
totalCount: number
|
|
24
|
+
userRoles: string[]
|
|
25
|
+
isLoading: boolean
|
|
26
|
+
error: string | null
|
|
27
|
+
refetch: () => Promise<void>
|
|
28
|
+
isFeatureEnabled: (featureName: string) => boolean
|
|
29
|
+
getFeaturesByMf: (mfName: string) => FeatureToggleInfo[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Hook to get feature toggles for the current user
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { useFeatures } from '@ib-dop/platform-kit'
|
|
38
|
+
*
|
|
39
|
+
* function FeatureFlagComponent() {
|
|
40
|
+
* const { features, isFeatureEnabled, isLoading } = useFeatures()
|
|
41
|
+
*
|
|
42
|
+
* if (isLoading) return <Spinner />
|
|
43
|
+
*
|
|
44
|
+
* return (
|
|
45
|
+
* <div>
|
|
46
|
+
* {isFeatureEnabled('new-dashboard') && <NewDashboard />}
|
|
47
|
+
* {!isFeatureEnabled('new-dashboard') && <OldDashboard />}
|
|
48
|
+
* </div>
|
|
49
|
+
* )
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function useFeatures(): UseFeaturesResult {
|
|
54
|
+
const auth = useShellAuth()
|
|
55
|
+
const [features, setFeatures] = useState<FeatureToggleInfo[]>([])
|
|
56
|
+
const [totalCount, setTotalCount] = useState(0)
|
|
57
|
+
const [userRoles, setUserRoles] = useState<string[]>([])
|
|
58
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
59
|
+
const [error, setError] = useState<string | null>(null)
|
|
60
|
+
|
|
61
|
+
const fetchFeatures = useCallback(async () => {
|
|
62
|
+
if (!auth.isAuthenticated) {
|
|
63
|
+
console.debug('[useFeatures] Not authenticated')
|
|
64
|
+
setIsLoading(false)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setIsLoading(true)
|
|
69
|
+
setError(null)
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const headers: Record<string, string> = {
|
|
73
|
+
'Content-Type': 'application/json',
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const token = auth.user?.access_token
|
|
77
|
+
if (token) {
|
|
78
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const response = await fetch('/api/features', { headers })
|
|
82
|
+
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result: FeaturesResponse = await response.json()
|
|
88
|
+
setFeatures(result.features || [])
|
|
89
|
+
setTotalCount(result.totalCount || 0)
|
|
90
|
+
setUserRoles(result.userRoles || [])
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.debug('Features fetch error:', err)
|
|
93
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
94
|
+
setFeatures([])
|
|
95
|
+
setUserRoles([])
|
|
96
|
+
} finally {
|
|
97
|
+
setIsLoading(false)
|
|
98
|
+
}
|
|
99
|
+
}, [auth.isAuthenticated, auth.user?.access_token])
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
fetchFeatures()
|
|
103
|
+
}, [fetchFeatures])
|
|
104
|
+
|
|
105
|
+
const isFeatureEnabled = useCallback(
|
|
106
|
+
(featureName: string): boolean => {
|
|
107
|
+
const feature = features.find((f) => f.name === featureName)
|
|
108
|
+
return feature?.userEnabled ?? false
|
|
109
|
+
},
|
|
110
|
+
[features]
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
const getFeaturesByMf = useCallback(
|
|
114
|
+
(mfName: string): FeatureToggleInfo[] => {
|
|
115
|
+
return features.filter((f) => f.mfDependencies?.includes(mfName))
|
|
116
|
+
},
|
|
117
|
+
[features]
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
features,
|
|
122
|
+
totalCount,
|
|
123
|
+
userRoles,
|
|
124
|
+
isLoading,
|
|
125
|
+
error,
|
|
126
|
+
refetch: fetchFeatures,
|
|
127
|
+
isFeatureEnabled,
|
|
128
|
+
getFeaturesByMf,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Result of useFeatureAdmin hook
|
|
134
|
+
*/
|
|
135
|
+
export interface UseFeatureAdminResult {
|
|
136
|
+
features: FeatureToggleAdmin[]
|
|
137
|
+
microfrontends: string[]
|
|
138
|
+
isAdmin: boolean
|
|
139
|
+
isLoading: boolean
|
|
140
|
+
error: string | null
|
|
141
|
+
refetch: () => Promise<void>
|
|
142
|
+
createFeature: (feature: FeatureCreateRequest) => Promise<boolean>
|
|
143
|
+
updateFeature: (name: string, feature: FeatureUpdateRequest) => Promise<boolean>
|
|
144
|
+
toggleFeature: (name: string, enabled: boolean) => Promise<boolean>
|
|
145
|
+
deleteFeature: (name: string) => Promise<boolean>
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Hook for admin operations with feature toggles
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* import { useFeatureAdmin } from '@ib-dop/platform-kit'
|
|
154
|
+
*
|
|
155
|
+
* function AdminPanel() {
|
|
156
|
+
* const {
|
|
157
|
+
* features,
|
|
158
|
+
* isAdmin,
|
|
159
|
+
* isLoading,
|
|
160
|
+
* toggleFeature
|
|
161
|
+
* } = useFeatureAdmin()
|
|
162
|
+
*
|
|
163
|
+
* if (isLoading) return <Spinner />
|
|
164
|
+
* if (!isAdmin) return <AccessDenied />
|
|
165
|
+
*
|
|
166
|
+
* return (
|
|
167
|
+
* <table>
|
|
168
|
+
* {features.map(f => (
|
|
169
|
+
* <tr key={f.name}>
|
|
170
|
+
* <td>{f.name}</td>
|
|
171
|
+
* <td>{f.enabled ? 'ON' : 'OFF'}</td>
|
|
172
|
+
* <button onClick={() => toggleFeature(f.name, !f.enabled)}>
|
|
173
|
+
* Toggle
|
|
174
|
+
* </button>
|
|
175
|
+
* </tr>
|
|
176
|
+
* ))}
|
|
177
|
+
* </table>
|
|
178
|
+
* )
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export function useFeatureAdmin(): UseFeatureAdminResult {
|
|
183
|
+
const auth = useShellAuth()
|
|
184
|
+
const [features, setFeatures] = useState<FeatureToggleAdmin[]>([])
|
|
185
|
+
const [microfrontends, setMicrofrontends] = useState<string[]>([])
|
|
186
|
+
const [isAdmin, setIsAdmin] = useState(false)
|
|
187
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
188
|
+
const [error, setError] = useState<string | null>(null)
|
|
189
|
+
|
|
190
|
+
const fetchFeatures = useCallback(async () => {
|
|
191
|
+
if (!auth.isAuthenticated) {
|
|
192
|
+
console.debug('[useFeatureAdmin] Not authenticated')
|
|
193
|
+
setIsLoading(false)
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
setIsLoading(true)
|
|
198
|
+
setError(null)
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const headers: Record<string, string> = {
|
|
202
|
+
'Content-Type': 'application/json',
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const token = auth.user?.access_token
|
|
206
|
+
if (token) {
|
|
207
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const response = await fetch('/api/features/admin', { headers })
|
|
211
|
+
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
if (response.status === 403) {
|
|
214
|
+
console.warn('[useFeatureAdmin] 403 Forbidden - checking if token has admin role')
|
|
215
|
+
setIsAdmin(false)
|
|
216
|
+
setFeatures([])
|
|
217
|
+
setMicrofrontends([])
|
|
218
|
+
setIsLoading(false)
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const result: FeatureAdminResponse = await response.json()
|
|
225
|
+
setFeatures(result.featureToggles || [])
|
|
226
|
+
setMicrofrontends(result.microfrontends || [])
|
|
227
|
+
setIsAdmin(result.isAdmin || false)
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.debug('FeatureAdmin fetch error:', err)
|
|
230
|
+
setFeatures([])
|
|
231
|
+
setMicrofrontends([])
|
|
232
|
+
setIsAdmin(false)
|
|
233
|
+
} finally {
|
|
234
|
+
setIsLoading(false)
|
|
235
|
+
}
|
|
236
|
+
}, [auth.isAuthenticated, auth.user?.access_token])
|
|
237
|
+
|
|
238
|
+
const createFeature = useCallback(
|
|
239
|
+
async (feature: FeatureCreateRequest): Promise<boolean> => {
|
|
240
|
+
try {
|
|
241
|
+
const headers: Record<string, string> = {
|
|
242
|
+
'Content-Type': 'application/json',
|
|
243
|
+
}
|
|
244
|
+
const token = auth.user?.access_token
|
|
245
|
+
if (token) {
|
|
246
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const response = await fetch('/api/features/admin', {
|
|
250
|
+
method: 'POST',
|
|
251
|
+
headers,
|
|
252
|
+
body: JSON.stringify(feature),
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
const errorData = await response.json().catch(() => ({}))
|
|
257
|
+
throw new Error(errorData.error || `HTTP ${response.status}`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
await fetchFeatures()
|
|
261
|
+
return true
|
|
262
|
+
} catch (err) {
|
|
263
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
264
|
+
return false
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
[fetchFeatures]
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
const updateFeature = useCallback(
|
|
271
|
+
async (name: string, feature: FeatureUpdateRequest): Promise<boolean> => {
|
|
272
|
+
try {
|
|
273
|
+
const headers: Record<string, string> = {
|
|
274
|
+
'Content-Type': 'application/json',
|
|
275
|
+
}
|
|
276
|
+
const token = auth.user?.access_token
|
|
277
|
+
if (token) {
|
|
278
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const response = await fetch(`/api/features/admin/${encodeURIComponent(name)}`, {
|
|
282
|
+
method: 'PUT',
|
|
283
|
+
headers,
|
|
284
|
+
body: JSON.stringify(feature),
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
if (!response.ok) {
|
|
288
|
+
const errorData = await response.json().catch(() => ({}))
|
|
289
|
+
throw new Error(errorData.error || `HTTP ${response.status}`)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
await fetchFeatures()
|
|
293
|
+
return true
|
|
294
|
+
} catch (err) {
|
|
295
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
296
|
+
return false
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
[fetchFeatures]
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
const toggleFeature = useCallback(
|
|
303
|
+
async (name: string, enabled: boolean): Promise<boolean> => {
|
|
304
|
+
try {
|
|
305
|
+
const headers: Record<string, string> = {}
|
|
306
|
+
const token = auth.user?.access_token
|
|
307
|
+
if (token) {
|
|
308
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const response = await fetch(
|
|
312
|
+
`/api/features/admin/${encodeURIComponent(name)}/toggle?enabled=${enabled}`,
|
|
313
|
+
{
|
|
314
|
+
method: 'POST',
|
|
315
|
+
headers,
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
if (!response.ok) {
|
|
320
|
+
const errorData = await response.json().catch(() => ({}))
|
|
321
|
+
throw new Error(errorData.error || `HTTP ${response.status}`)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
await fetchFeatures()
|
|
325
|
+
return true
|
|
326
|
+
} catch (err) {
|
|
327
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
328
|
+
return false
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
[fetchFeatures]
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
const deleteFeature = useCallback(
|
|
335
|
+
async (name: string): Promise<boolean> => {
|
|
336
|
+
try {
|
|
337
|
+
const headers: Record<string, string> = {}
|
|
338
|
+
const token = auth.user?.access_token
|
|
339
|
+
if (token) {
|
|
340
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const response = await fetch(`/api/features/admin/${encodeURIComponent(name)}`, {
|
|
344
|
+
method: 'DELETE',
|
|
345
|
+
headers,
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
if (!response.ok) {
|
|
349
|
+
const errorData = await response.json().catch(() => ({}))
|
|
350
|
+
throw new Error(errorData.error || `HTTP ${response.status}`)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
await fetchFeatures()
|
|
354
|
+
return true
|
|
355
|
+
} catch (err) {
|
|
356
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
357
|
+
return false
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
[fetchFeatures]
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
fetchFeatures()
|
|
365
|
+
}, [fetchFeatures])
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
features,
|
|
369
|
+
microfrontends,
|
|
370
|
+
isAdmin,
|
|
371
|
+
isLoading,
|
|
372
|
+
error,
|
|
373
|
+
refetch: fetchFeatures,
|
|
374
|
+
createFeature,
|
|
375
|
+
updateFeature,
|
|
376
|
+
toggleFeature,
|
|
377
|
+
deleteFeature,
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Hook to get microfrontends with their features
|
|
383
|
+
*/
|
|
384
|
+
export interface UseMicrofrontendsFeaturesResult {
|
|
385
|
+
microfrontends: MicrofrontendWithFeatures[]
|
|
386
|
+
totalCount: number
|
|
387
|
+
isLoading: boolean
|
|
388
|
+
error: string | null
|
|
389
|
+
refetch: () => Promise<void>
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function useMicrofrontendsFeatures(): UseMicrofrontendsFeaturesResult {
|
|
393
|
+
const auth = useShellAuth()
|
|
394
|
+
const [microfrontends, setMicrofrontends] = useState<MicrofrontendWithFeatures[]>([])
|
|
395
|
+
const [totalCount, setTotalCount] = useState(0)
|
|
396
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
397
|
+
const [error, setError] = useState<string | null>(null)
|
|
398
|
+
|
|
399
|
+
const fetchData = useCallback(async () => {
|
|
400
|
+
if (!auth.isAuthenticated) {
|
|
401
|
+
setIsLoading(false)
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
setIsLoading(true)
|
|
406
|
+
setError(null)
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
const headers: Record<string, string> = {
|
|
410
|
+
'Content-Type': 'application/json',
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const token = auth.user?.access_token
|
|
414
|
+
if (token) {
|
|
415
|
+
headers['Authorization'] = `Bearer ${token}`
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const response = await fetch('/api/features/microfrontends', { headers })
|
|
419
|
+
|
|
420
|
+
if (!response.ok) {
|
|
421
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const result: MicrofrontendsFeaturesResponse = await response.json()
|
|
425
|
+
setMicrofrontends(result.microfrontends || [])
|
|
426
|
+
setTotalCount(result.totalCount || 0)
|
|
427
|
+
} catch (err) {
|
|
428
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
429
|
+
} finally {
|
|
430
|
+
setIsLoading(false)
|
|
431
|
+
}
|
|
432
|
+
}, [auth.isAuthenticated, auth.user?.access_token])
|
|
433
|
+
|
|
434
|
+
useEffect(() => {
|
|
435
|
+
fetchData()
|
|
436
|
+
}, [fetchData])
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
microfrontends,
|
|
440
|
+
totalCount,
|
|
441
|
+
isLoading,
|
|
442
|
+
error,
|
|
443
|
+
refetch: fetchData,
|
|
444
|
+
}
|
|
445
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -225,3 +225,102 @@ export type MfeNameSource =
|
|
|
225
225
|
| 'sessionStorage.mf-config'
|
|
226
226
|
| 'import.meta.env.VITE_MFE_NAME'
|
|
227
227
|
| 'import.meta.env.MFE_NAME'
|
|
228
|
+
|
|
229
|
+
// ==================== Feature Types ====================
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Feature toggle for a user
|
|
233
|
+
*/
|
|
234
|
+
export interface FeatureToggleInfo {
|
|
235
|
+
name: string
|
|
236
|
+
enabled: boolean
|
|
237
|
+
description?: string
|
|
238
|
+
roles?: string[]
|
|
239
|
+
percentage?: number
|
|
240
|
+
microfrontends?: string[]
|
|
241
|
+
userEnabled: boolean
|
|
242
|
+
mfDependencies?: string[]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Response from /api/features endpoint
|
|
247
|
+
*/
|
|
248
|
+
export interface FeaturesResponse {
|
|
249
|
+
features: FeatureToggleInfo[]
|
|
250
|
+
totalCount: number
|
|
251
|
+
userRoles: string[]
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Admin feature toggle (full info)
|
|
256
|
+
*/
|
|
257
|
+
export interface FeatureToggleAdmin {
|
|
258
|
+
name: string
|
|
259
|
+
enabled: boolean
|
|
260
|
+
description: string
|
|
261
|
+
roles: string[]
|
|
262
|
+
percentage: number
|
|
263
|
+
microfrontends: string[]
|
|
264
|
+
mfDependencies: string[]
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Admin response from /api/features/admin endpoint
|
|
269
|
+
*/
|
|
270
|
+
export interface FeatureAdminResponse {
|
|
271
|
+
featureToggles: FeatureToggleAdmin[]
|
|
272
|
+
isAdmin: boolean
|
|
273
|
+
microfrontends: string[]
|
|
274
|
+
totalCount: number
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Feature creation request
|
|
279
|
+
*/
|
|
280
|
+
export interface FeatureCreateRequest {
|
|
281
|
+
name: string
|
|
282
|
+
enabled?: boolean
|
|
283
|
+
description?: string
|
|
284
|
+
roles?: string[]
|
|
285
|
+
percentage?: number
|
|
286
|
+
microfrontends?: string[]
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Feature update request
|
|
291
|
+
*/
|
|
292
|
+
export interface FeatureUpdateRequest {
|
|
293
|
+
enabled?: boolean
|
|
294
|
+
description?: string
|
|
295
|
+
roles?: string[]
|
|
296
|
+
percentage?: number
|
|
297
|
+
microfrontends?: string[]
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Microfrontend with its features
|
|
302
|
+
*/
|
|
303
|
+
export interface MicrofrontendWithFeatures {
|
|
304
|
+
name: string
|
|
305
|
+
description?: string
|
|
306
|
+
featureToggles: string[]
|
|
307
|
+
features: FeatureInfo[]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Feature info for a microfrontend
|
|
312
|
+
*/
|
|
313
|
+
export interface FeatureInfo {
|
|
314
|
+
name: string
|
|
315
|
+
enabled: boolean
|
|
316
|
+
global: boolean
|
|
317
|
+
required: boolean
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Response from /api/features/microfrontends endpoint
|
|
322
|
+
*/
|
|
323
|
+
export interface MicrofrontendsFeaturesResponse {
|
|
324
|
+
microfrontends: MicrofrontendWithFeatures[]
|
|
325
|
+
totalCount: number
|
|
326
|
+
}
|