@@ -13,7 +13,7 @@ import {
1313} from "@forge/react" ;
1414import { Fragment , useCallback , useState } from "react" ;
1515
16- import { usePromise } from "../../common" ;
16+ import { FLAGSMITH_APP , usePromise } from "../../common" ;
1717import {
1818 Environment ,
1919 EnvironmentFeatureState ,
@@ -130,14 +130,12 @@ const makeRows = (projectUrl: string, state: FeatureState) => {
130130} ;
131131
132132type IssueFeatureTableProps = {
133- projectUrl : string ;
134133 environments : Environment [ ] ; // must be non-empty
135134 // list of same feature in the context of each environment
136135 environmentFeatures : Feature [ ] ;
137136} ;
138137
139138const IssueFeatureTable = ( {
140- projectUrl,
141139 environments,
142140 environmentFeatures,
143141} : IssueFeatureTableProps ) : JSX . Element => {
@@ -147,31 +145,60 @@ const IssueFeatureTable = ({
147145 // get id and name from first feature - assume non-empty
148146 const featureId = environmentFeatures [ 0 ] ! . id ;
149147 const featureName = environmentFeatures [ 0 ] ! . name ;
148+ const featureProjectId = environmentFeatures [ 0 ] ! . project ;
149+ const projectUrl = `${ FLAGSMITH_APP } /project/${ featureProjectId } ` ;
150150
151151 /** Read feature state for each environment */
152- const readFeatureState = useCallback (
153- async ( ) : Promise < FeatureState > => ( {
154- featureId,
155- environments : await Promise . all (
156- environments . map ( async ( environment ) => ( {
157- ...( await readEnvironmentFeatureState ( {
152+ const readFeatureState = useCallback ( async ( ) : Promise < FeatureState > => {
153+ const matchingEnvs = environments . filter (
154+ ( env ) => String ( env . project ) === String ( featureProjectId ) ,
155+ ) ;
156+
157+ const environmentFeatureStates = await Promise . all (
158+ matchingEnvs . map ( async ( environment ) => {
159+ try {
160+ const state = await readEnvironmentFeatureState ( {
158161 envApiKey : String ( environment . api_key ) ,
159162 featureName,
160- } ) ) ,
161- name : environment . name ,
162- api_key : String ( environment . api_key ) ,
163- } ) ) ,
164- ) ,
165- counts : environmentFeatures . map ( ( feature ) => ( {
163+ } ) ;
164+
165+ return {
166+ ...state ,
167+ name : environment . name ,
168+ api_key : String ( environment . api_key ) ,
169+ } ;
170+ } catch ( err ) {
171+ return null ;
172+ }
173+ } ) ,
174+ ) ;
175+
176+ const validStates = environmentFeatureStates . filter (
177+ ( state ) : state is EnvironmentFeatureState => ! ! state ,
178+ ) ;
179+
180+ const relevantFeatures = environmentFeatures . filter (
181+ ( f ) => String ( f . project ) === String ( featureProjectId ) ,
182+ ) ;
183+
184+ return {
185+ featureId,
186+ environments : validStates ,
187+ counts : relevantFeatures . map ( ( feature ) => ( {
166188 variations : feature . multivariate_options . length ,
167189 segments : feature . num_segment_overrides ?? 0 ,
168190 identities : feature . num_identity_overrides ?? 0 ,
169191 } ) ) ,
170- } ) ,
171- [ environments , environmentFeatures ] ,
172- ) ;
192+ } ;
193+ } , [ environments , environmentFeatures ] ) ;
194+
173195 const [ state ] = usePromise (
174- async ( ) => ( error === undefined ? readFeatureState ( ) : undefined ) ,
196+ async ( ) => {
197+ if ( error === undefined ) {
198+ return await readFeatureState ( ) ;
199+ }
200+ return undefined ;
201+ } ,
175202 [ error , readFeatureState ] ,
176203 setError ,
177204 ) ;
@@ -198,47 +225,63 @@ const IssueFeatureTable = ({
198225
199226type FeatureTableData = {
200227 featureId : string ;
201- baseFeature : Feature | undefined ;
202- environmentFeatures : Feature [ ] ;
228+ baseFeature : Feature ;
229+ envFeaturesForThisFeature : Feature [ ] ;
230+ matchingEnvironments : Environment [ ] ;
203231} ;
204232
205233const buildFeatureTableData = ( {
206234 issueFeatureIds,
207235 features,
236+ environments,
208237 environmentsFeatures,
209238} : {
210239 issueFeatureIds : string [ ] ;
211240 features : Feature [ ] ;
241+ environments : Environment [ ] ;
212242 environmentsFeatures : Feature [ ] [ ] ;
213243} ) : FeatureTableData [ ] => {
214- return issueFeatureIds . map ( ( featureId ) => {
215- const baseFeature = features . find ( ( f ) => String ( f . id ) === featureId ) ;
244+ return issueFeatureIds
245+ . map ( ( featureId ) => {
246+ const baseFeature = features . find ( ( f ) => String ( f . id ) === featureId ) ;
247+ if ( ! baseFeature ) {
248+ return null ;
249+ }
216250
217- const envFeaturesForThisFeature = environmentsFeatures
218- . map ( ( envFeatures ) => {
251+ const envFeaturesForThisFeature : Feature [ ] = [ ] ;
252+ const matchingEnvironments : Environment [ ] = [ ] ;
253+
254+ environmentsFeatures . forEach ( ( envFeatures , index ) => {
219255 const matchingFeature = envFeatures . find ( ( f ) => String ( f . id ) === featureId ) ;
220- return matchingFeature ;
221- } )
222- . filter ( Boolean ) as Feature [ ] ;
256+ const environment = environments [ index ] ;
257+ if ( matchingFeature && environment !== undefined ) {
258+ envFeaturesForThisFeature . push ( matchingFeature ) ;
259+ matchingEnvironments . push ( environment ) ;
260+ }
261+ } ) ;
223262
224- return {
225- featureId,
226- baseFeature,
227- environmentFeatures : envFeaturesForThisFeature ,
228- } ;
229- } ) ;
263+ if ( envFeaturesForThisFeature . length === 0 || matchingEnvironments . length === 0 ) {
264+ return null ;
265+ }
266+
267+ return {
268+ featureId,
269+ baseFeature,
270+ envFeaturesForThisFeature,
271+ matchingEnvironments,
272+ } ;
273+ } )
274+ . filter ( ( data ) : data is FeatureTableData => ! ! data ) ;
230275} ;
231276
232277type IssueFeatureTablesProps = {
233- projectUrl : string ;
234278 // environments/environmentsFeatures are assumed to be same length/order
235279 environments : Environment [ ] ;
236280 environmentsFeatures : Feature [ ] [ ] ;
237281 issueFeatureIds : string [ ] ;
238282} ;
239283
240284const IssueFeatureTables = ( {
241- projectUrl,
242285 environments,
243286 environmentsFeatures,
244287 issueFeatureIds,
@@ -254,38 +297,34 @@ const IssueFeatureTables = ({
254297 // iterate features from the first environment to get list of tables
255298 // (id/name/description are the same across environments)
256299 const features = environmentsFeatures [ 0 ] ;
257-
258300 const featureTableData = buildFeatureTableData ( {
259301 issueFeatureIds,
260302 features,
303+ environments,
261304 environmentsFeatures,
262305 } ) ;
263306
264307 return (
265308 < Fragment >
266- { featureTableData . map ( ( { featureId, baseFeature, environmentFeatures } ) => {
267- if ( ! baseFeature ) {
268- return null ;
269- }
270- return (
309+ { featureTableData . map (
310+ ( { featureId, baseFeature, matchingEnvironments, envFeaturesForThisFeature } ) => (
271311 < Fragment key = { featureId } >
272312 < Box xcss = { { marginTop : "space.300" , marginBottom : "space.100" } } >
273313 < Text >
274314 < Strong >
275- { baseFeature . name }
315+ { baseFeature . name } ( { baseFeature . project_name } )
276316 { baseFeature . description ? ": " : "" }
277317 </ Strong >
278318 { baseFeature . description }
279319 </ Text >
280320 </ Box >
281321 < IssueFeatureTable
282- projectUrl = { projectUrl }
283- environments = { environments }
284- environmentFeatures = { environmentFeatures }
322+ environments = { matchingEnvironments }
323+ environmentFeatures = { envFeaturesForThisFeature }
285324 />
286325 </ Fragment >
287- ) ;
288- } ) }
326+ ) ,
327+ ) }
289328 </ Fragment >
290329 ) ;
291330} ;
0 commit comments