mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: projects using this application (#6355)

This commit is contained in:
		
							parent
							
								
									c049374a25
								
							
						
					
					
						commit
						9cd324bd7c
					
				@ -1,5 +1,5 @@
 | 
				
			|||||||
/* eslint react/no-multi-comp:off */
 | 
					/* eslint react/no-multi-comp:off */
 | 
				
			||||||
import React, { lazy, useContext, useState } from 'react';
 | 
					import React, { useContext, useState } from 'react';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    Box,
 | 
					    Box,
 | 
				
			||||||
    Avatar,
 | 
					    Avatar,
 | 
				
			||||||
@ -31,6 +31,7 @@ import { formatUnknownError } from 'utils/formatUnknownError';
 | 
				
			|||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
import { useUiFlag } from 'hooks/useUiFlag';
 | 
					import { useUiFlag } from 'hooks/useUiFlag';
 | 
				
			||||||
import { ApplicationEdit } from './ApplicationEdit/ApplicationEdit';
 | 
					import { ApplicationEdit } from './ApplicationEdit/ApplicationEdit';
 | 
				
			||||||
 | 
					import ApplicationOverview from './ApplicationOverview';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Tab = {
 | 
					type Tab = {
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
@ -68,8 +69,6 @@ const StyledTab = styled(Tab)(({ theme }) => ({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ApplicationOverview = lazy(() => import('./ApplicationOverview'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const Application = () => {
 | 
					export const Application = () => {
 | 
				
			||||||
    const useOldApplicationScreen = !useUiFlag('sdkReporting');
 | 
					    const useOldApplicationScreen = !useUiFlag('sdkReporting');
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										227
									
								
								frontend/src/component/application/ApplicationChart.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								frontend/src/component/application/ApplicationChart.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
				
			|||||||
 | 
					import { Box, Divider, styled, Typography, useTheme } from '@mui/material';
 | 
				
			||||||
 | 
					import { ArcherContainer, ArcherElement } from 'react-archer';
 | 
				
			||||||
 | 
					import { ConditionallyRender } from '../common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
 | 
					import { FC, useLayoutEffect, useRef, useState } from 'react';
 | 
				
			||||||
 | 
					import { ApplicationOverviewSchema } from '../../openapi';
 | 
				
			||||||
 | 
					import { useRequiredPathParam } from '../../hooks/useRequiredPathParam';
 | 
				
			||||||
 | 
					import { WarningAmberRounded } from '@mui/icons-material';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledTable = styled('table')(({ theme }) => ({
 | 
				
			||||||
 | 
					    fontSize: theme.fontSizes.smallerBody,
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(2),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledCell = styled('td')(({ theme }) => ({
 | 
				
			||||||
 | 
					    verticalAlign: 'top',
 | 
				
			||||||
 | 
					    paddingLeft: 0,
 | 
				
			||||||
 | 
					    paddingRight: theme.spacing(1),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyleApplicationContainer = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(18),
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    justifyContent: 'center',
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledApplicationBox = styled(Box)<{
 | 
				
			||||||
 | 
					    mode: 'success' | 'warning';
 | 
				
			||||||
 | 
					}>(({ theme, mode }) => ({
 | 
				
			||||||
 | 
					    borderRadius: theme.shape.borderRadiusMedium,
 | 
				
			||||||
 | 
					    border: '1px solid',
 | 
				
			||||||
 | 
					    borderColor: theme.palette[mode].border,
 | 
				
			||||||
 | 
					    backgroundColor: theme.palette[mode].light,
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    flexDirection: 'column',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					    padding: theme.spacing(1.5, 3, 2, 3),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledEnvironmentBox = styled(Box)<{
 | 
				
			||||||
 | 
					    mode: 'success' | 'warning';
 | 
				
			||||||
 | 
					}>(({ theme, mode }) => ({
 | 
				
			||||||
 | 
					    borderRadius: theme.shape.borderRadiusMedium,
 | 
				
			||||||
 | 
					    border: '1px solid',
 | 
				
			||||||
 | 
					    borderColor:
 | 
				
			||||||
 | 
					        theme.palette[mode === 'success' ? 'secondary' : 'warning'].border,
 | 
				
			||||||
 | 
					    backgroundColor:
 | 
				
			||||||
 | 
					        theme.palette[mode === 'success' ? 'secondary' : 'warning'].light,
 | 
				
			||||||
 | 
					    display: 'inline-block',
 | 
				
			||||||
 | 
					    padding: theme.spacing(1.5, 1.5, 1.5, 1.5),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(2),
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(2),
 | 
				
			||||||
 | 
					    width: '100%',
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledEnvironmentsContainer = styled(Box)({
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    justifyContent: 'start',
 | 
				
			||||||
 | 
					    gap: '20px',
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const EnvironmentHeader = styled(Typography)(({ theme }) => ({
 | 
				
			||||||
 | 
					    fontSize: theme.fontSizes.smallerBody,
 | 
				
			||||||
 | 
					    fontWeight: theme.fontWeight.bold,
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const StyledStatus = styled(Typography)<{
 | 
				
			||||||
 | 
					    mode: 'success' | 'warning';
 | 
				
			||||||
 | 
					}>(({ theme, mode }) => ({
 | 
				
			||||||
 | 
					    gap: theme.spacing(1),
 | 
				
			||||||
 | 
					    fontSize: theme.fontSizes.smallBody,
 | 
				
			||||||
 | 
					    color: theme.palette[mode].dark,
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useElementWidth = () => {
 | 
				
			||||||
 | 
					    const elementRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					    const [width, setWidth] = useState('100%');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useLayoutEffect(() => {
 | 
				
			||||||
 | 
					        setWidth(`${elementRef.current?.scrollWidth}px`);
 | 
				
			||||||
 | 
					    }, [elementRef, setWidth]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        elementRef,
 | 
				
			||||||
 | 
					        width,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const SuccessStatus = () => (
 | 
				
			||||||
 | 
					    <StyledStatus mode='success'>
 | 
				
			||||||
 | 
					        <WarningAmberRounded
 | 
				
			||||||
 | 
					            sx={(theme) => ({
 | 
				
			||||||
 | 
					                color: theme.palette.success.main,
 | 
				
			||||||
 | 
					            })}
 | 
				
			||||||
 | 
					        />{' '}
 | 
				
			||||||
 | 
					        Everything looks good!
 | 
				
			||||||
 | 
					    </StyledStatus>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const WarningStatus: FC = ({ children }) => (
 | 
				
			||||||
 | 
					    <StyledStatus mode='warning'>
 | 
				
			||||||
 | 
					        <WarningAmberRounded
 | 
				
			||||||
 | 
					            sx={(theme) => ({
 | 
				
			||||||
 | 
					                color: theme.palette.warning.main,
 | 
				
			||||||
 | 
					            })}
 | 
				
			||||||
 | 
					        />{' '}
 | 
				
			||||||
 | 
					        {children}
 | 
				
			||||||
 | 
					    </StyledStatus>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IApplicationChartProps {
 | 
				
			||||||
 | 
					    data: ApplicationOverviewSchema;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ApplicationChart = ({ data }: IApplicationChartProps) => {
 | 
				
			||||||
 | 
					    const applicationName = useRequiredPathParam('name');
 | 
				
			||||||
 | 
					    const { elementRef, width } = useElementWidth();
 | 
				
			||||||
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
 | 
					    const theme = useTheme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mode: 'success' | 'warning' =
 | 
				
			||||||
 | 
					        data.issues.length === 0 ? 'success' : 'warning';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Box sx={{ width }}>
 | 
				
			||||||
 | 
					            <ArcherContainer
 | 
				
			||||||
 | 
					                strokeColor={theme.palette.secondary.border}
 | 
				
			||||||
 | 
					                endMarker={false}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <StyleApplicationContainer>
 | 
				
			||||||
 | 
					                    <ArcherElement
 | 
				
			||||||
 | 
					                        id='application'
 | 
				
			||||||
 | 
					                        relations={data.environments.map((environment) => ({
 | 
				
			||||||
 | 
					                            targetId: environment.name,
 | 
				
			||||||
 | 
					                            targetAnchor: 'top',
 | 
				
			||||||
 | 
					                            sourceAnchor: 'bottom',
 | 
				
			||||||
 | 
					                            style: {
 | 
				
			||||||
 | 
					                                strokeColor:
 | 
				
			||||||
 | 
					                                    mode === 'success'
 | 
				
			||||||
 | 
					                                        ? theme.palette.secondary.border
 | 
				
			||||||
 | 
					                                        : theme.palette.warning.border,
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
 | 
					                        }))}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <StyledApplicationBox mode={mode}>
 | 
				
			||||||
 | 
					                            <Typography
 | 
				
			||||||
 | 
					                                sx={(theme) => ({
 | 
				
			||||||
 | 
					                                    fontSize: theme.fontSizes.smallerBody,
 | 
				
			||||||
 | 
					                                })}
 | 
				
			||||||
 | 
					                                color='text.secondary'
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                Application
 | 
				
			||||||
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					                            <Typography
 | 
				
			||||||
 | 
					                                sx={(theme) => ({
 | 
				
			||||||
 | 
					                                    fontSize: theme.fontSizes.bodySize,
 | 
				
			||||||
 | 
					                                    fontWeight: theme.fontWeight.bold,
 | 
				
			||||||
 | 
					                                })}
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                {applicationName}
 | 
				
			||||||
 | 
					                            </Typography>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <StyledDivider />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <ConditionallyRender
 | 
				
			||||||
 | 
					                                condition={mode === 'success'}
 | 
				
			||||||
 | 
					                                show={<SuccessStatus />}
 | 
				
			||||||
 | 
					                                elseShow={
 | 
				
			||||||
 | 
					                                    <WarningStatus>
 | 
				
			||||||
 | 
					                                        {data.issues.length} issues detected
 | 
				
			||||||
 | 
					                                    </WarningStatus>
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        </StyledApplicationBox>
 | 
				
			||||||
 | 
					                    </ArcherElement>
 | 
				
			||||||
 | 
					                </StyleApplicationContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <StyledEnvironmentsContainer ref={elementRef}>
 | 
				
			||||||
 | 
					                    {data.environments.map((environment) => (
 | 
				
			||||||
 | 
					                        <ArcherElement
 | 
				
			||||||
 | 
					                            id={environment.name}
 | 
				
			||||||
 | 
					                            key={environment.name}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            <StyledEnvironmentBox
 | 
				
			||||||
 | 
					                                mode={mode}
 | 
				
			||||||
 | 
					                                key={environment.name}
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                <EnvironmentHeader>
 | 
				
			||||||
 | 
					                                    {environment.name} environment
 | 
				
			||||||
 | 
					                                </EnvironmentHeader>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <StyledTable>
 | 
				
			||||||
 | 
					                                    <tbody>
 | 
				
			||||||
 | 
					                                        <tr>
 | 
				
			||||||
 | 
					                                            <StyledCell>Instances:</StyledCell>
 | 
				
			||||||
 | 
					                                            <StyledCell>
 | 
				
			||||||
 | 
					                                                {environment.instanceCount}
 | 
				
			||||||
 | 
					                                            </StyledCell>
 | 
				
			||||||
 | 
					                                        </tr>
 | 
				
			||||||
 | 
					                                        <tr>
 | 
				
			||||||
 | 
					                                            <StyledCell>SDK:</StyledCell>
 | 
				
			||||||
 | 
					                                            <StyledCell>
 | 
				
			||||||
 | 
					                                                {environment.sdks.map((sdk) => (
 | 
				
			||||||
 | 
					                                                    <div key={sdk}>{sdk}</div>
 | 
				
			||||||
 | 
					                                                ))}
 | 
				
			||||||
 | 
					                                            </StyledCell>
 | 
				
			||||||
 | 
					                                        </tr>
 | 
				
			||||||
 | 
					                                        <tr>
 | 
				
			||||||
 | 
					                                            <StyledCell>Last seen:</StyledCell>
 | 
				
			||||||
 | 
					                                            <StyledCell>
 | 
				
			||||||
 | 
					                                                {environment.lastSeen}
 | 
				
			||||||
 | 
					                                            </StyledCell>
 | 
				
			||||||
 | 
					                                        </tr>
 | 
				
			||||||
 | 
					                                    </tbody>
 | 
				
			||||||
 | 
					                                </StyledTable>
 | 
				
			||||||
 | 
					                            </StyledEnvironmentBox>
 | 
				
			||||||
 | 
					                        </ArcherElement>
 | 
				
			||||||
 | 
					                    ))}
 | 
				
			||||||
 | 
					                </StyledEnvironmentsContainer>
 | 
				
			||||||
 | 
					            </ArcherContainer>
 | 
				
			||||||
 | 
					        </Box>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -6,7 +6,7 @@ import { ApplicationOverviewIssuesSchema } from 'openapi';
 | 
				
			|||||||
const WarningContainer = styled(Box)(({ theme }) => ({
 | 
					const WarningContainer = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    flexDirection: 'column',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
    paddingBottom: theme.spacing(8),
 | 
					    alignSelf: 'stretch',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const WarningHeader = styled(Box)(({ theme }) => ({
 | 
					const WarningHeader = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
				
			|||||||
@ -1,73 +1,13 @@
 | 
				
			|||||||
import { usePageTitle } from 'hooks/usePageTitle';
 | 
					import { usePageTitle } from 'hooks/usePageTitle';
 | 
				
			||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
					import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
 | 
				
			||||||
import {
 | 
					import { Alert, Box, Divider, styled } from '@mui/material';
 | 
				
			||||||
    Alert,
 | 
					 | 
				
			||||||
    Box,
 | 
					 | 
				
			||||||
    Divider,
 | 
					 | 
				
			||||||
    styled,
 | 
					 | 
				
			||||||
    Typography,
 | 
					 | 
				
			||||||
    useTheme,
 | 
					 | 
				
			||||||
} from '@mui/material';
 | 
					 | 
				
			||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
import { useNavigate } from 'react-router-dom';
 | 
					 | 
				
			||||||
import { ArcherContainer, ArcherElement } from 'react-archer';
 | 
					 | 
				
			||||||
import { FC, useLayoutEffect, useRef, useState } from 'react';
 | 
					 | 
				
			||||||
import { useApplicationOverview } from 'hooks/api/getters/useApplicationOverview/useApplicationOverview';
 | 
					import { useApplicationOverview } from 'hooks/api/getters/useApplicationOverview/useApplicationOverview';
 | 
				
			||||||
import { WarningAmberRounded } from '@mui/icons-material';
 | 
					 | 
				
			||||||
import { ApplicationIssues } from './ApplicationIssues/ApplicationIssues';
 | 
					import { ApplicationIssues } from './ApplicationIssues/ApplicationIssues';
 | 
				
			||||||
 | 
					import { ApplicationChart } from './ApplicationChart';
 | 
				
			||||||
const StyledTable = styled('table')(({ theme }) => ({
 | 
					import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
 | 
				
			||||||
    fontSize: theme.fontSizes.smallerBody,
 | 
					import { Badge } from '../common/Badge/Badge';
 | 
				
			||||||
    marginTop: theme.spacing(2),
 | 
					import { useNavigate } from 'react-router-dom';
 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyledCell = styled('td')(({ theme }) => ({
 | 
					 | 
				
			||||||
    verticalAlign: 'top',
 | 
					 | 
				
			||||||
    paddingLeft: 0,
 | 
					 | 
				
			||||||
    paddingRight: theme.spacing(1),
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyleApplicationContainer = styled(Box)(({ theme }) => ({
 | 
					 | 
				
			||||||
    marginBottom: theme.spacing(18),
 | 
					 | 
				
			||||||
    display: 'flex',
 | 
					 | 
				
			||||||
    justifyContent: 'center',
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyledApplicationBox = styled(Box)<{
 | 
					 | 
				
			||||||
    mode: 'success' | 'warning';
 | 
					 | 
				
			||||||
}>(({ theme, mode }) => ({
 | 
					 | 
				
			||||||
    borderRadius: theme.shape.borderRadiusMedium,
 | 
					 | 
				
			||||||
    border: '1px solid',
 | 
					 | 
				
			||||||
    borderColor: theme.palette[mode].border,
 | 
					 | 
				
			||||||
    backgroundColor: theme.palette[mode].light,
 | 
					 | 
				
			||||||
    display: 'flex',
 | 
					 | 
				
			||||||
    flexDirection: 'column',
 | 
					 | 
				
			||||||
    alignItems: 'center',
 | 
					 | 
				
			||||||
    padding: theme.spacing(1.5, 3, 2, 3),
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyledStatus = styled(Typography)<{
 | 
					 | 
				
			||||||
    mode: 'success' | 'warning';
 | 
					 | 
				
			||||||
}>(({ theme, mode }) => ({
 | 
					 | 
				
			||||||
    gap: theme.spacing(1),
 | 
					 | 
				
			||||||
    fontSize: theme.fontSizes.smallBody,
 | 
					 | 
				
			||||||
    color: theme.palette[mode].dark,
 | 
					 | 
				
			||||||
    display: 'flex',
 | 
					 | 
				
			||||||
    alignItems: 'center',
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const StyledEnvironmentBox = styled(Box)<{
 | 
					 | 
				
			||||||
    mode: 'success' | 'warning';
 | 
					 | 
				
			||||||
}>(({ theme, mode }) => ({
 | 
					 | 
				
			||||||
    borderRadius: theme.shape.borderRadiusMedium,
 | 
					 | 
				
			||||||
    border: '1px solid',
 | 
					 | 
				
			||||||
    borderColor:
 | 
					 | 
				
			||||||
        theme.palette[mode === 'success' ? 'secondary' : 'warning'].border,
 | 
					 | 
				
			||||||
    backgroundColor:
 | 
					 | 
				
			||||||
        theme.palette[mode === 'success' ? 'secondary' : 'warning'].light,
 | 
					 | 
				
			||||||
    display: 'inline-block',
 | 
					 | 
				
			||||||
    padding: theme.spacing(1.5, 1.5, 1.5, 1.5),
 | 
					 | 
				
			||||||
}));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
					const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
				
			||||||
    marginTop: theme.spacing(2),
 | 
					    marginTop: theme.spacing(2),
 | 
				
			||||||
@ -75,203 +15,54 @@ const StyledDivider = styled(Divider)(({ theme }) => ({
 | 
				
			|||||||
    width: '100%',
 | 
					    width: '100%',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledEnvironmentsContainer = styled(Box)({
 | 
					const ApplicationContainer = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    justifyContent: 'start',
 | 
					    padding: theme.spacing(1),
 | 
				
			||||||
    gap: '20px',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
});
 | 
					    alignItems: 'center',
 | 
				
			||||||
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
const EnvironmentHeader = styled(Typography)(({ theme }) => ({
 | 
					    alignSelf: 'stretch',
 | 
				
			||||||
    fontSize: theme.fontSizes.smallerBody,
 | 
					 | 
				
			||||||
    fontWeight: theme.fontWeight.bold,
 | 
					 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SuccessStatus = () => (
 | 
					const ProjectContainer = styled(Box)(({ theme }) => ({
 | 
				
			||||||
    <StyledStatus mode='success'>
 | 
					    display: 'flex',
 | 
				
			||||||
        <WarningAmberRounded
 | 
					    alignItems: 'center',
 | 
				
			||||||
            sx={(theme) => ({
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
                color: theme.palette.success.main,
 | 
					    alignSelf: 'stretch',
 | 
				
			||||||
            })}
 | 
					}));
 | 
				
			||||||
        />{' '}
 | 
					 | 
				
			||||||
        Everything looks good!
 | 
					 | 
				
			||||||
    </StyledStatus>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const WarningStatus: FC = ({ children }) => (
 | 
					const ApplicationOverview = () => {
 | 
				
			||||||
    <StyledStatus mode='warning'>
 | 
					 | 
				
			||||||
        <WarningAmberRounded
 | 
					 | 
				
			||||||
            sx={(theme) => ({
 | 
					 | 
				
			||||||
                color: theme.palette.warning.main,
 | 
					 | 
				
			||||||
            })}
 | 
					 | 
				
			||||||
        />{' '}
 | 
					 | 
				
			||||||
        {children}
 | 
					 | 
				
			||||||
    </StyledStatus>
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const useElementWidth = () => {
 | 
					 | 
				
			||||||
    const elementRef = useRef<HTMLDivElement>(null);
 | 
					 | 
				
			||||||
    const [width, setWidth] = useState('100%');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useLayoutEffect(() => {
 | 
					 | 
				
			||||||
        setWidth(`${elementRef.current?.scrollWidth}px`);
 | 
					 | 
				
			||||||
    }, [elementRef, setWidth]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        elementRef,
 | 
					 | 
				
			||||||
        width,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const ApplicationOverview = () => {
 | 
					 | 
				
			||||||
    usePageTitle('Applications - Overview');
 | 
					    usePageTitle('Applications - Overview');
 | 
				
			||||||
    const applicationName = useRequiredPathParam('name');
 | 
					    const applicationName = useRequiredPathParam('name');
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
    const theme = useTheme();
 | 
					 | 
				
			||||||
    const { data, loading } = useApplicationOverview(applicationName);
 | 
					    const { data, loading } = useApplicationOverview(applicationName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @ts-ignore
 | 
					 | 
				
			||||||
    window.navigateToInstances = (environment: string) => {
 | 
					 | 
				
			||||||
        navigate(
 | 
					 | 
				
			||||||
            `/applications/${applicationName}/instances?environment=${environment}`,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { elementRef, width } = useElementWidth();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const mode: 'success' | 'warning' =
 | 
					 | 
				
			||||||
        data.issues.length === 0 ? 'success' : 'warning';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ConditionallyRender
 | 
					        <ConditionallyRender
 | 
				
			||||||
            condition={!loading && data.environments.length === 0}
 | 
					            condition={!loading && data.environments.length === 0}
 | 
				
			||||||
            show={<Alert severity='warning'>No data available.</Alert>}
 | 
					            show={<Alert severity='warning'>No data available.</Alert>}
 | 
				
			||||||
            elseShow={
 | 
					            elseShow={
 | 
				
			||||||
                <>
 | 
					                <ApplicationContainer>
 | 
				
			||||||
 | 
					                    <ProjectContainer>
 | 
				
			||||||
 | 
					                        Projects using this application
 | 
				
			||||||
 | 
					                        {data.projects.map((project) => (
 | 
				
			||||||
 | 
					                            <Badge
 | 
				
			||||||
 | 
					                                sx={{ cursor: 'pointer' }}
 | 
				
			||||||
 | 
					                                onClick={(e) => {
 | 
				
			||||||
 | 
					                                    e.preventDefault();
 | 
				
			||||||
 | 
					                                    navigate(`/projects/${project}`);
 | 
				
			||||||
 | 
					                                }}
 | 
				
			||||||
 | 
					                                color='secondary'
 | 
				
			||||||
 | 
					                                icon={<TopicOutlinedIcon />}
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                {project}
 | 
				
			||||||
 | 
					                            </Badge>
 | 
				
			||||||
 | 
					                        ))}
 | 
				
			||||||
 | 
					                    </ProjectContainer>
 | 
				
			||||||
 | 
					                    <StyledDivider />
 | 
				
			||||||
                    <ApplicationIssues issues={data.issues} />
 | 
					                    <ApplicationIssues issues={data.issues} />
 | 
				
			||||||
                    <Box sx={{ width }}>
 | 
					                    <ApplicationChart data={data} />
 | 
				
			||||||
                        <ArcherContainer
 | 
					                </ApplicationContainer>
 | 
				
			||||||
                            strokeColor={theme.palette.secondary.border}
 | 
					 | 
				
			||||||
                            endMarker={false}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                            <StyleApplicationContainer>
 | 
					 | 
				
			||||||
                                <ArcherElement
 | 
					 | 
				
			||||||
                                    id='application'
 | 
					 | 
				
			||||||
                                    relations={data.environments.map(
 | 
					 | 
				
			||||||
                                        (environment) => ({
 | 
					 | 
				
			||||||
                                            targetId: environment.name,
 | 
					 | 
				
			||||||
                                            targetAnchor: 'top',
 | 
					 | 
				
			||||||
                                            sourceAnchor: 'bottom',
 | 
					 | 
				
			||||||
                                            style: {
 | 
					 | 
				
			||||||
                                                strokeColor:
 | 
					 | 
				
			||||||
                                                    mode === 'success'
 | 
					 | 
				
			||||||
                                                        ? theme.palette
 | 
					 | 
				
			||||||
                                                              .secondary.border
 | 
					 | 
				
			||||||
                                                        : theme.palette.warning
 | 
					 | 
				
			||||||
                                                              .border,
 | 
					 | 
				
			||||||
                                            },
 | 
					 | 
				
			||||||
                                        }),
 | 
					 | 
				
			||||||
                                    )}
 | 
					 | 
				
			||||||
                                >
 | 
					 | 
				
			||||||
                                    <StyledApplicationBox mode={mode}>
 | 
					 | 
				
			||||||
                                        <Typography
 | 
					 | 
				
			||||||
                                            sx={(theme) => ({
 | 
					 | 
				
			||||||
                                                fontSize:
 | 
					 | 
				
			||||||
                                                    theme.fontSizes.smallerBody,
 | 
					 | 
				
			||||||
                                            })}
 | 
					 | 
				
			||||||
                                            color='text.secondary'
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                            Application
 | 
					 | 
				
			||||||
                                        </Typography>
 | 
					 | 
				
			||||||
                                        <Typography
 | 
					 | 
				
			||||||
                                            sx={(theme) => ({
 | 
					 | 
				
			||||||
                                                fontSize:
 | 
					 | 
				
			||||||
                                                    theme.fontSizes.bodySize,
 | 
					 | 
				
			||||||
                                                fontWeight:
 | 
					 | 
				
			||||||
                                                    theme.fontWeight.bold,
 | 
					 | 
				
			||||||
                                            })}
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                            {applicationName}
 | 
					 | 
				
			||||||
                                        </Typography>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                        <StyledDivider />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                        <ConditionallyRender
 | 
					 | 
				
			||||||
                                            condition={mode === 'success'}
 | 
					 | 
				
			||||||
                                            show={<SuccessStatus />}
 | 
					 | 
				
			||||||
                                            elseShow={
 | 
					 | 
				
			||||||
                                                <WarningStatus>
 | 
					 | 
				
			||||||
                                                    {data.issues.length} issues
 | 
					 | 
				
			||||||
                                                    detected
 | 
					 | 
				
			||||||
                                                </WarningStatus>
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                        />
 | 
					 | 
				
			||||||
                                    </StyledApplicationBox>
 | 
					 | 
				
			||||||
                                </ArcherElement>
 | 
					 | 
				
			||||||
                            </StyleApplicationContainer>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <StyledEnvironmentsContainer ref={elementRef}>
 | 
					 | 
				
			||||||
                                {data.environments.map((environment) => (
 | 
					 | 
				
			||||||
                                    <ArcherElement
 | 
					 | 
				
			||||||
                                        id={environment.name}
 | 
					 | 
				
			||||||
                                        key={environment.name}
 | 
					 | 
				
			||||||
                                    >
 | 
					 | 
				
			||||||
                                        <StyledEnvironmentBox
 | 
					 | 
				
			||||||
                                            mode={mode}
 | 
					 | 
				
			||||||
                                            key={environment.name}
 | 
					 | 
				
			||||||
                                        >
 | 
					 | 
				
			||||||
                                            <EnvironmentHeader>
 | 
					 | 
				
			||||||
                                                {environment.name} environment
 | 
					 | 
				
			||||||
                                            </EnvironmentHeader>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            <StyledTable>
 | 
					 | 
				
			||||||
                                                <tbody>
 | 
					 | 
				
			||||||
                                                    <tr>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            Instances:
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            {
 | 
					 | 
				
			||||||
                                                                environment.instanceCount
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                    </tr>
 | 
					 | 
				
			||||||
                                                    <tr>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            SDK:
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            {environment.sdks.map(
 | 
					 | 
				
			||||||
                                                                (sdk) => (
 | 
					 | 
				
			||||||
                                                                    <div
 | 
					 | 
				
			||||||
                                                                        key={
 | 
					 | 
				
			||||||
                                                                            sdk
 | 
					 | 
				
			||||||
                                                                        }
 | 
					 | 
				
			||||||
                                                                    >
 | 
					 | 
				
			||||||
                                                                        {sdk}
 | 
					 | 
				
			||||||
                                                                    </div>
 | 
					 | 
				
			||||||
                                                                ),
 | 
					 | 
				
			||||||
                                                            )}
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                    </tr>
 | 
					 | 
				
			||||||
                                                    <tr>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            Last seen:
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                        <StyledCell>
 | 
					 | 
				
			||||||
                                                            {
 | 
					 | 
				
			||||||
                                                                environment.lastSeen
 | 
					 | 
				
			||||||
                                                            }
 | 
					 | 
				
			||||||
                                                        </StyledCell>
 | 
					 | 
				
			||||||
                                                    </tr>
 | 
					 | 
				
			||||||
                                                </tbody>
 | 
					 | 
				
			||||||
                                            </StyledTable>
 | 
					 | 
				
			||||||
                                        </StyledEnvironmentBox>
 | 
					 | 
				
			||||||
                                    </ArcherElement>
 | 
					 | 
				
			||||||
                                ))}
 | 
					 | 
				
			||||||
                            </StyledEnvironmentsContainer>
 | 
					 | 
				
			||||||
                        </ArcherContainer>
 | 
					 | 
				
			||||||
                    </Box>
 | 
					 | 
				
			||||||
                </>
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user