mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: connection status bubble (#8099)
Fully working cycle 
This commit is contained in:
		
							parent
							
								
									397b44bfd3
								
							
						
					
					
						commit
						01fb748c01
					
				| @ -0,0 +1,44 @@ | ||||
| import { alpha, Avatar, styled } from '@mui/material'; | ||||
| 
 | ||||
| export const PulsingAvatar = styled(Avatar, { | ||||
|     shouldForwardProp: (prop) => prop !== 'active', | ||||
| })<{ active: boolean }>(({ theme, active }) => ({ | ||||
|     transition: 'background-color 0.5s ease', | ||||
|     color: theme.palette.common.white, | ||||
|     backgroundColor: active | ||||
|         ? theme.palette.primary.main | ||||
|         : theme.palette.divider, | ||||
|     '@keyframes pulse': { | ||||
|         '0%': { | ||||
|             boxShadow: `0 0 0 0px ${alpha(theme.palette.primary.main, 0.7)}`, | ||||
|         }, | ||||
|         '100%': { | ||||
|             boxShadow: `0 0 0 20px ${alpha(theme.palette.primary.main, 0.0)}`, | ||||
|         }, | ||||
|     }, | ||||
|     animation: active ? 'pulse 2s infinite' : '', | ||||
| })); | ||||
| 
 | ||||
| /** | ||||
|  * Temporary component until we decide how all the colors will look like | ||||
|  * Then we can use PulsingAvatar with a color prop perhaps | ||||
|  * PulsingAvatar was not working nicely on purple background | ||||
|  */ | ||||
| export const WhitePulsingAvatar = styled(Avatar, { | ||||
|     shouldForwardProp: (prop) => prop !== 'active', | ||||
| })<{ active: boolean }>(({ theme, active }) => ({ | ||||
|     transition: 'background-color 0.5s ease', | ||||
|     color: theme.palette.primary.main, | ||||
|     backgroundColor: active | ||||
|         ? theme.palette.background.default | ||||
|         : theme.palette.divider, | ||||
|     '@keyframes pulse': { | ||||
|         '0%': { | ||||
|             boxShadow: `0 0 0 0px ${alpha(theme.palette.background.default, 0.7)}`, | ||||
|         }, | ||||
|         '100%': { | ||||
|             boxShadow: `0 0 0 20px ${alpha(theme.palette.background.default, 0.0)}`, | ||||
|         }, | ||||
|     }, | ||||
|     animation: active ? 'pulse 2s infinite' : '', | ||||
| })); | ||||
| @ -9,14 +9,11 @@ import { | ||||
| import { GenerateApiKey } from './GenerateApiKey'; | ||||
| import { useEffect, useState } from 'react'; | ||||
| import { SelectSdk } from './SelectSdk'; | ||||
| import { | ||||
|     ConceptsDefinitionsWrapper, | ||||
|     GenrateApiKeyConcepts, | ||||
|     SelectSdkConcepts, | ||||
| } from './UnleashConcepts'; | ||||
| import { GenerateApiKeyConcepts, SelectSdkConcepts } from './UnleashConcepts'; | ||||
| import { TestSdkConnection } from './TestSdkConnection'; | ||||
| 
 | ||||
| import type { Sdk } from './sharedTypes'; | ||||
| import { ConnectionInformation } from './ConnectionInformation'; | ||||
| 
 | ||||
| interface IConnectSDKDialogProps { | ||||
|     open: boolean; | ||||
| @ -180,10 +177,15 @@ export const ConnectSdkDialog = ({ | ||||
|                     <SelectSdkConcepts /> | ||||
|                 ) : null} | ||||
|                 {isLargeScreen && isGenerateApiKeyStage ? ( | ||||
|                     <GenrateApiKeyConcepts /> | ||||
|                     <GenerateApiKeyConcepts /> | ||||
|                 ) : null} | ||||
|                 {isLargeScreen && isTestConnectionStage ? ( | ||||
|                     <ConceptsDefinitionsWrapper /> | ||||
|                     <ConnectionInformation | ||||
|                         projectId={project} | ||||
|                         sdk={sdk.name} | ||||
|                         environment={environment} | ||||
|                         onConnection={onClose} | ||||
|                     /> | ||||
|                 ) : null} | ||||
|             </Box> | ||||
|         </StyledDialog> | ||||
|  | ||||
							
								
								
									
										113
									
								
								frontend/src/component/onboarding/ConnectionInformation.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								frontend/src/component/onboarding/ConnectionInformation.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | ||||
| import { styled, Typography, useTheme } from '@mui/material'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { WhitePulsingAvatar } from 'component/common/PulsingAvatar/PulsingAvatar'; | ||||
| import Pending from '@mui/icons-material/Pending'; | ||||
| import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview'; | ||||
| import { useEffect } from 'react'; | ||||
| 
 | ||||
| interface IConnectionInformationProps { | ||||
|     onConnection: () => void; | ||||
|     projectId: string; | ||||
|     sdk: string; | ||||
|     environment: string; | ||||
| } | ||||
| export const Container = styled('div')(({ theme }) => ({ | ||||
|     backgroundColor: theme.palette.background.sidebar, | ||||
|     padding: theme.spacing(6, 9, 6, 9), | ||||
|     minWidth: '400px', | ||||
|     display: 'flex', | ||||
|     flexDirection: 'column', | ||||
|     color: theme.palette.primary.contrastText, | ||||
| })); | ||||
| 
 | ||||
| export const Title = styled(Typography)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     alignItems: 'center', | ||||
|     justifyContent: 'center', | ||||
|     fontWeight: theme.typography.fontWeightBold, | ||||
| })); | ||||
| 
 | ||||
| export const SdkInfo = styled('div')(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     flexDirection: 'row', | ||||
|     padding: theme.spacing(4, 0, 12, 0), | ||||
|     justifyContent: 'space-between', | ||||
|     fontSize: theme.spacing(1), | ||||
| })); | ||||
| 
 | ||||
| export const Info = styled('div')(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     gap: theme.spacing(1), | ||||
|     flexDirection: 'column', | ||||
| })); | ||||
| 
 | ||||
| export const ConnectionStatus = styled('div')(({ theme }) => ({ | ||||
|     alignItems: 'center', | ||||
|     justifyContent: 'center', | ||||
|     display: 'flex', | ||||
|     gap: theme.spacing(2), | ||||
|     flexDirection: 'column', | ||||
|     fontSize: theme.fontSizes.smallBody, | ||||
| })); | ||||
| 
 | ||||
| export const ConnectionInformation = ({ | ||||
|     onConnection, | ||||
|     projectId, | ||||
|     sdk, | ||||
|     environment, | ||||
| }: IConnectionInformationProps) => { | ||||
|     const theme = useTheme(); | ||||
|     const { project } = useProjectOverview(projectId, { | ||||
|         refreshInterval: 1000, | ||||
|     }); | ||||
| 
 | ||||
|     const onboarded = project.onboardingStatus.status === 'onboarded'; | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         if (onboarded) { | ||||
|             onConnection(); | ||||
|         } | ||||
|     }, [onboarded]); | ||||
| 
 | ||||
|     return ( | ||||
|         <Container> | ||||
|             <Title>Connection information</Title> | ||||
|             <SdkInfo> | ||||
|                 <Info> | ||||
|                     <Typography fontWeight='bold' variant='body2'> | ||||
|                         Environment | ||||
|                     </Typography> | ||||
|                     <Typography variant='body2'>{environment}</Typography> | ||||
|                 </Info> | ||||
|                 <Info> | ||||
|                     <Typography fontWeight='bold' variant='body2'> | ||||
|                         SDK | ||||
|                     </Typography> | ||||
|                     <Typography variant='body2'>{sdk}</Typography> | ||||
|                 </Info> | ||||
|             </SdkInfo> | ||||
|             <ConnectionStatus> | ||||
|                 <Typography fontWeight='bold' variant='body2'> | ||||
|                     Connection status | ||||
|                 </Typography> | ||||
|                 <Typography sx={{ mb: theme.spacing(4) }} variant='body2'> | ||||
|                     Waiting for SDK data... | ||||
|                 </Typography> | ||||
|                 <ConditionallyRender | ||||
|                     condition={true} | ||||
|                     show={ | ||||
|                         <WhitePulsingAvatar | ||||
|                             sx={{ | ||||
|                                 width: 80, | ||||
|                                 height: 80, | ||||
|                             }} | ||||
|                             active={true} | ||||
|                         > | ||||
|                             <Pending fontSize='large' /> | ||||
|                         </WhitePulsingAvatar> | ||||
|                     } | ||||
|                 /> | ||||
|             </ConnectionStatus> | ||||
|         </Container> | ||||
|     ); | ||||
| }; | ||||
| @ -40,7 +40,7 @@ const ConceptSummary = styled('div')(({ theme }) => ({ | ||||
|     marginBottom: theme.spacing(2), | ||||
| })); | ||||
| 
 | ||||
| export const GenrateApiKeyConcepts = () => ( | ||||
| export const GenerateApiKeyConcepts = () => ( | ||||
|     <ConceptsDefinitionsWrapper> | ||||
|         <ConceptItem> | ||||
|             <StyledProjectIcon /> | ||||
|  | ||||
| @ -1,20 +0,0 @@ | ||||
| import { alpha, Avatar, styled } from '@mui/material'; | ||||
| 
 | ||||
| export const PulsingAvatar = styled(Avatar, { | ||||
|     shouldForwardProp: (prop) => prop !== 'active', | ||||
| })<{ active: boolean }>(({ theme, active }) => ({ | ||||
|     transition: 'background-color 0.5s ease', | ||||
|     color: theme.palette.common.white, | ||||
|     backgroundColor: active | ||||
|         ? theme.palette.primary.main | ||||
|         : theme.palette.divider, | ||||
|     '@keyframes pulse': { | ||||
|         '0%': { | ||||
|             boxShadow: `0 0 0 0px ${alpha(theme.palette.primary.main, 0.7)}`, | ||||
|         }, | ||||
|         '100%': { | ||||
|             boxShadow: `0 0 0 20px ${alpha(theme.palette.primary.main, 0.0)}`, | ||||
|         }, | ||||
|     }, | ||||
|     animation: active ? 'pulse 2s infinite' : '', | ||||
| })); | ||||
| @ -9,7 +9,7 @@ import { | ||||
| } from '@mui/material'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { StyledFileDropZone } from './StyledFileDropZone'; | ||||
| import { PulsingAvatar } from '../PulsingAvatar'; | ||||
| import { PulsingAvatar } from 'component/common/PulsingAvatar/PulsingAvatar'; | ||||
| import ArrowUpward from '@mui/icons-material/ArrowUpward'; | ||||
| import { ImportExplanation } from './ImportExplanation'; | ||||
| import { type FC, type ReactNode, useState } from 'react'; | ||||
|  | ||||
| @ -8,7 +8,7 @@ import { ActionsContainer } from '../ActionsContainer'; | ||||
| import Check from '@mui/icons-material/Check'; | ||||
| import ErrorIcon from '@mui/icons-material/Error'; | ||||
| import Pending from '@mui/icons-material/Pending'; | ||||
| import { PulsingAvatar } from '../PulsingAvatar'; | ||||
| import { PulsingAvatar } from 'component/common/PulsingAvatar/PulsingAvatar'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { Box } from '@mui/system'; | ||||
| import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user