mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
feat: connection status bubble (#8099)
Fully working cycle ![image](https://github.com/user-attachments/assets/cf20788b-29fa-4489-91e7-7db9f592da9b)
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