mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: avoid erasing previous environments data on refetch (#990)
* refactor: avoid duplicate useLoading call * fix: avoid erasing previous environments data on refetch * refactor: keep mutataion logic within useEnvironments
This commit is contained in:
		
							parent
							
								
									159c54ed37
								
							
						
					
					
						commit
						98b6214c28
					
				| @ -26,7 +26,8 @@ const EnvironmentList = () => { | |||||||
|         enabled: true, |         enabled: true, | ||||||
|         protected: false, |         protected: false, | ||||||
|     }; |     }; | ||||||
|     const { environments, refetchEnvironments } = useEnvironments(); |     const { environments, mutateEnvironments, refetchEnvironments } = | ||||||
|  |         useEnvironments(); | ||||||
|     const { uiConfig } = useUiConfig(); |     const { uiConfig } = useUiConfig(); | ||||||
|     const { refetch: refetchProjectRolePermissions } = |     const { refetch: refetchProjectRolePermissions } = | ||||||
|         useProjectRolePermissions(); |         useProjectRolePermissions(); | ||||||
| @ -52,7 +53,7 @@ const EnvironmentList = () => { | |||||||
|         const item = newEnvList.splice(dragIndex, 1)[0]; |         const item = newEnvList.splice(dragIndex, 1)[0]; | ||||||
| 
 | 
 | ||||||
|         newEnvList.splice(hoverIndex, 0, item); |         newEnvList.splice(hoverIndex, 0, item); | ||||||
|         refetchEnvironments({ environments: newEnvList }, false); |         mutateEnvironments(newEnvList); | ||||||
|         return newEnvList; |         return newEnvList; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,28 +1,23 @@ | |||||||
| import { useEffect, useState } from 'react'; | import { useEffect, useState } from 'react'; | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { useStyles } from './ProjectEnvironment.styles'; | import { useStyles } from './ProjectEnvironment.styles'; | ||||||
| 
 |  | ||||||
| import useLoading from 'hooks/useLoading'; |  | ||||||
| import { PageContent } from 'component/common/PageContent/PageContent'; | import { PageContent } from 'component/common/PageContent/PageContent'; | ||||||
| import { PageHeader } from 'component/common/PageHeader/PageHeader'; | import { PageHeader } from 'component/common/PageHeader/PageHeader'; | ||||||
| import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions'; | import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions'; | ||||||
| 
 |  | ||||||
| import ApiError from 'component/common/ApiError/ApiError'; | import ApiError from 'component/common/ApiError/ApiError'; | ||||||
| import useToast from 'hooks/useToast'; | import useToast from 'hooks/useToast'; | ||||||
| import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | ||||||
| import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; | import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; | ||||||
| import useProject from 'hooks/api/getters/useProject/useProject'; | import useProject from 'hooks/api/getters/useProject/useProject'; | ||||||
| import { FormControlLabel, FormGroup } from '@mui/material'; | import { FormControlLabel, FormGroup, Alert } from '@mui/material'; | ||||||
| import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | ||||||
| import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm'; | import EnvironmentDisableConfirm from './EnvironmentDisableConfirm/EnvironmentDisableConfirm'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
| import { Alert } from '@mui/material'; |  | ||||||
| import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; | import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; | ||||||
| import { IProjectEnvironment } from 'interfaces/environments'; | import { IProjectEnvironment } from 'interfaces/environments'; | ||||||
| import { getEnabledEnvs } from './helpers'; | import { getEnabledEnvs } from './helpers'; | ||||||
| import StringTruncator from 'component/common/StringTruncator/StringTruncator'; | import StringTruncator from 'component/common/StringTruncator/StringTruncator'; | ||||||
| import { useThemeStyles } from 'themes/themeStyles'; | import { useThemeStyles } from 'themes/themeStyles'; | ||||||
| import { isDescendantOrSelf } from '@testing-library/user-event/dist/types/utils'; |  | ||||||
| 
 | 
 | ||||||
| interface IProjectEnvironmentListProps { | interface IProjectEnvironmentListProps { | ||||||
|     projectId: string; |     projectId: string; | ||||||
| @ -45,7 +40,6 @@ const ProjectEnvironmentList = ({ | |||||||
|     // local state
 |     // local state
 | ||||||
|     const [selectedEnv, setSelectedEnv] = useState<IProjectEnvironment>(); |     const [selectedEnv, setSelectedEnv] = useState<IProjectEnvironment>(); | ||||||
|     const [confirmName, setConfirmName] = useState(''); |     const [confirmName, setConfirmName] = useState(''); | ||||||
|     const ref = useLoading(loading); |  | ||||||
|     const { classes: styles } = useStyles(); |     const { classes: styles } = useStyles(); | ||||||
|     const { isOss } = useUiConfig(); |     const { isOss } = useUiConfig(); | ||||||
| 
 | 
 | ||||||
| @ -179,68 +173,60 @@ const ProjectEnvironmentList = ({ | |||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <div ref={ref}> |         <PageContent | ||||||
|             <PageContent |             header={ | ||||||
|                 header={ |                 <PageHeader | ||||||
|                     <PageHeader |                     title={`Configure environments for "${project?.name}" project`} | ||||||
|                         title={`Configure environments for "${project?.name}" project`} |  | ||||||
|                     /> |  | ||||||
|                 } |  | ||||||
|             > |  | ||||||
|                 <ConditionallyRender |  | ||||||
|                     condition={uiConfig.flags.E} |  | ||||||
|                     show={ |  | ||||||
|                         <div className={styles.container}> |  | ||||||
|                             <ConditionallyRender |  | ||||||
|                                 condition={error} |  | ||||||
|                                 show={renderError()} |  | ||||||
|                             /> |  | ||||||
|                             <Alert |  | ||||||
|                                 severity="info" |  | ||||||
|                                 style={{ marginBottom: '20px' }} |  | ||||||
|                             > |  | ||||||
|                                 <b>Important!</b> In order for your application |  | ||||||
|                                 to retrieve configured activation strategies for |  | ||||||
|                                 a specific environment, the application |  | ||||||
|                                 <br /> must use an environment specific API key. |  | ||||||
|                                 You can look up the environment-specific API |  | ||||||
|                                 keys <Link to="/admin/api">here.</Link> |  | ||||||
|                                 <br /> |  | ||||||
|                                 <br /> |  | ||||||
|                                 Your administrator can configure an |  | ||||||
|                                 environment-specific API key to be used in the |  | ||||||
|                                 SDK. If you are an administrator you can{' '} |  | ||||||
|                                 <Link to="/admin/api"> |  | ||||||
|                                     create a new API key. |  | ||||||
|                                 </Link> |  | ||||||
|                             </Alert> |  | ||||||
|                             <ConditionallyRender |  | ||||||
|                                 condition={environments.length < 1 && !loading} |  | ||||||
|                                 show={<div>No environments available.</div>} |  | ||||||
|                                 elseShow={renderEnvironments()} |  | ||||||
|                             /> |  | ||||||
|                             <EnvironmentDisableConfirm |  | ||||||
|                                 env={selectedEnv} |  | ||||||
|                                 open={Boolean(selectedEnv)} |  | ||||||
|                                 handleDisableEnvironment={ |  | ||||||
|                                     handleDisableEnvironment |  | ||||||
|                                 } |  | ||||||
|                                 handleCancelDisableEnvironment={ |  | ||||||
|                                     handleCancelDisableEnvironment |  | ||||||
|                                 } |  | ||||||
|                                 confirmName={confirmName} |  | ||||||
|                                 setConfirmName={setConfirmName} |  | ||||||
|                             /> |  | ||||||
|                         </div> |  | ||||||
|                     } |  | ||||||
|                     elseShow={ |  | ||||||
|                         <Alert security="success"> |  | ||||||
|                             This feature has not been Unleashed for you yet. |  | ||||||
|                         </Alert> |  | ||||||
|                     } |  | ||||||
|                 /> |                 /> | ||||||
|             </PageContent> |             } | ||||||
|         </div> |             isLoading={loading} | ||||||
|  |         > | ||||||
|  |             <ConditionallyRender | ||||||
|  |                 condition={uiConfig.flags.E} | ||||||
|  |                 show={ | ||||||
|  |                     <div className={styles.container}> | ||||||
|  |                         <ConditionallyRender | ||||||
|  |                             condition={Boolean(error)} | ||||||
|  |                             show={renderError()} | ||||||
|  |                         /> | ||||||
|  |                         <Alert severity="info" style={{ marginBottom: '20px' }}> | ||||||
|  |                             <b>Important!</b> In order for your application to | ||||||
|  |                             retrieve configured activation strategies for a | ||||||
|  |                             specific environment, the application | ||||||
|  |                             <br /> must use an environment specific API key. You | ||||||
|  |                             can look up the environment-specific API keys{' '} | ||||||
|  |                             <Link to="/admin/api">here.</Link> | ||||||
|  |                             <br /> | ||||||
|  |                             <br /> | ||||||
|  |                             Your administrator can configure an | ||||||
|  |                             environment-specific API key to be used in the SDK. | ||||||
|  |                             If you are an administrator you can{' '} | ||||||
|  |                             <Link to="/admin/api">create a new API key.</Link> | ||||||
|  |                         </Alert> | ||||||
|  |                         <ConditionallyRender | ||||||
|  |                             condition={environments.length < 1 && !loading} | ||||||
|  |                             show={<div>No environments available.</div>} | ||||||
|  |                             elseShow={renderEnvironments()} | ||||||
|  |                         /> | ||||||
|  |                         <EnvironmentDisableConfirm | ||||||
|  |                             env={selectedEnv} | ||||||
|  |                             open={Boolean(selectedEnv)} | ||||||
|  |                             handleDisableEnvironment={handleDisableEnvironment} | ||||||
|  |                             handleCancelDisableEnvironment={ | ||||||
|  |                                 handleCancelDisableEnvironment | ||||||
|  |                             } | ||||||
|  |                             confirmName={confirmName} | ||||||
|  |                             setConfirmName={setConfirmName} | ||||||
|  |                         /> | ||||||
|  |                     </div> | ||||||
|  |                 } | ||||||
|  |                 elseShow={ | ||||||
|  |                     <Alert security="success"> | ||||||
|  |                         This feature has not been Unleashed for you yet. | ||||||
|  |                     </Alert> | ||||||
|  |                 } | ||||||
|  |             /> | ||||||
|  |         </PageContent> | ||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,35 +1,49 @@ | |||||||
| import useSWR, { mutate } from 'swr'; | import useSWR from 'swr'; | ||||||
| import { useCallback, useMemo } from 'react'; | import { useMemo, useCallback } from 'react'; | ||||||
| import { IEnvironmentResponse } from 'interfaces/environments'; | import { IEnvironmentResponse, IEnvironment } from 'interfaces/environments'; | ||||||
| import { formatApiPath } from 'utils/formatPath'; | import { formatApiPath } from 'utils/formatPath'; | ||||||
| import handleErrorResponses from '../httpErrorResponseHandler'; | import handleErrorResponses from '../httpErrorResponseHandler'; | ||||||
| 
 | 
 | ||||||
| const PATH = formatApiPath(`api/admin/environments`); | interface IUseEnvironmentsOutput { | ||||||
|  |     environments: IEnvironment[]; | ||||||
|  |     loading: boolean; | ||||||
|  |     error?: Error; | ||||||
|  |     mutateEnvironments: (environments: IEnvironment[]) => Promise<void>; | ||||||
|  |     refetchEnvironments: () => Promise<void>; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| export const useEnvironments = () => { | export const useEnvironments = (): IUseEnvironmentsOutput => { | ||||||
|     const { data, error } = useSWR<IEnvironmentResponse>(PATH, fetcher); |     const { data, error, mutate } = useSWR<IEnvironmentResponse>( | ||||||
| 
 |         formatApiPath(`api/admin/environments`), | ||||||
|     const refetchEnvironments = useCallback( |         fetcher | ||||||
|         (data?: IEnvironmentResponse, revalidate?: boolean) => { |  | ||||||
|             mutate(PATH, data, revalidate).catch(console.warn); |  | ||||||
|         }, |  | ||||||
|         [] |  | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     const environments = useMemo(() => { |     const environments = useMemo(() => { | ||||||
|         return data?.environments || []; |         return data?.environments || []; | ||||||
|     }, [data]); |     }, [data]); | ||||||
| 
 | 
 | ||||||
|  |     const refetchEnvironments = useCallback(async () => { | ||||||
|  |         await mutate(); | ||||||
|  |     }, [mutate]); | ||||||
|  | 
 | ||||||
|  |     const mutateEnvironments = useCallback( | ||||||
|  |         async (environments: IEnvironment[]) => { | ||||||
|  |             await mutate({ environments }, false); | ||||||
|  |         }, | ||||||
|  |         [mutate] | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     return { |     return { | ||||||
|         environments, |         environments, | ||||||
|         refetchEnvironments, |         refetchEnvironments, | ||||||
|  |         mutateEnvironments, | ||||||
|         loading: !error && !data, |         loading: !error && !data, | ||||||
|         error, |         error, | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const fetcher = (): Promise<IEnvironmentResponse> => { | const fetcher = (path: string): Promise<IEnvironmentResponse> => { | ||||||
|     return fetch(PATH) |     return fetch(path) | ||||||
|         .then(handleErrorResponses('Environments')) |         .then(handleErrorResponses('Environments')) | ||||||
|         .then(res => res.json()); |         .then(res => res.json()); | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user