1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: application graph (#6279)

Basic graph, that works with mock data.
Next steps, work on backend and try to put more content and **styling to
nodes**.

![image](https://github.com/Unleash/unleash/assets/964450/545d6527-ecd8-4010-a0fe-8001bc8c1456)
This commit is contained in:
Jaanus Sellin 2024-02-21 09:13:18 +02:00 committed by GitHub
parent f46d420b10
commit f3c01545f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 93 additions and 5 deletions

View File

@ -1,5 +1,5 @@
/* eslint react/no-multi-comp:off */ /* eslint react/no-multi-comp:off */
import React, { useContext, useState } from 'react'; import React, { lazy, useContext, useState } from 'react';
import { import {
Box, Box,
Avatar, Avatar,
@ -68,6 +68,8 @@ 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();
@ -230,7 +232,7 @@ export const Application = () => {
/> />
<Routes> <Routes>
<Route path='instances' element={<ConnectedInstances />} /> <Route path='instances' element={<ConnectedInstances />} />
<Route path='*' element={<p>This is a placeholder</p>} /> <Route path='*' element={<ApplicationOverview />} />
</Routes> </Routes>
</PageContent> </PageContent>
</> </>

View File

@ -14,7 +14,7 @@ import {
import { Link as LinkIcon } from '@mui/icons-material'; import { Link as LinkIcon } from '@mui/icons-material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { UPDATE_APPLICATION } from 'component/providers/AccessProvider/permissions'; import { UPDATE_APPLICATION } from 'component/providers/AccessProvider/permissions';
import { ApplicationView } from '../ApplicationView/ApplicationView'; import { ApplicationOverview } from '../ApplicationOverview';
import { ApplicationUpdate } from '../ApplicationUpdate/ApplicationUpdate'; import { ApplicationUpdate } from '../ApplicationUpdate/ApplicationUpdate';
import { Dialogue } from 'component/common/Dialogue/Dialogue'; import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { PageContent } from 'component/common/PageContent/PageContent'; import { PageContent } from 'component/common/PageContent/PageContent';
@ -76,7 +76,7 @@ export const ApplicationEdit = () => {
const tabData = [ const tabData = [
{ {
label: 'Application overview', label: 'Application overview',
component: <ApplicationView />, component: <ApplicationEdit />,
}, },
{ {
label: 'Edit application', label: 'Edit application',

View File

@ -0,0 +1,84 @@
import { usePageTitle } from 'hooks/usePageTitle';
import { Mermaid } from 'component/common/Mermaid/Mermaid';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Alert, styled } from '@mui/material';
import { useThemeMode } from 'hooks/useThemeMode';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useNavigate } from 'react-router-dom';
const StyledMermaid = styled(Mermaid)(({ theme }) => ({
'#mermaid .node rect': {
fill: theme.palette.secondary.light,
stroke: theme.palette.secondary.border,
},
'#mermaid .application-container': {
// display: 'flex',
// padding: theme.spacing(4,3,3,3),
// flexDirection: 'column',
// alignItems: 'center',
// gap: theme.spacing(3),
backgroundColor: theme.palette.secondary.light,
},
}));
export const ApplicationOverview = () => {
usePageTitle('Applications - Overview');
const applicationName = useRequiredPathParam('name');
const { themeMode } = useThemeMode();
const navigate = useNavigate();
const app = {
projects: ['default', 'dx'],
featureCount: 12,
environments: [
{
name: 'production',
instanceCount: 34,
sdks: ['unleash-client-node:5.4.0'],
lastSeen: '2021-10-01T12:00:00Z',
},
{
name: 'development',
instanceCount: 16,
sdks: ['unleash-client-java:5.4.0'],
lastSeen: '2021-10-01T12:00:00Z',
},
],
};
const applicationNode = `
${applicationName}[<span>${applicationName}</span>]
`;
// @ts-ignore
window.navigateToInstances = (environment: string) => {
navigate(
`/applications/${applicationName}/instances?environment=${environment}`,
);
};
const graph = `
graph TD
subgraph _[ ]
direction BT
${applicationNode}
${app.environments
.map(
({ name }, i) =>
`${name}("${name}") --- ${applicationName}
click ${name} navigateToInstances`,
)
.join('\n')}
end
`;
return (
<ConditionallyRender
condition={1 === 2 + 1}
show={<Alert severity='warning'>No data available.</Alert>}
elseShow={<StyledMermaid>{graph}</StyledMermaid>}
/>
);
};
export default ApplicationOverview;

View File

@ -30,6 +30,7 @@ const StyledMermaid = styled('div')(({ theme }) => ({
mermaid.initialize({ mermaid.initialize({
startOnLoad: false, startOnLoad: false,
theme: 'default', theme: 'default',
securityLevel: 'loose',
themeCSS: ` themeCSS: `
.clusters #_ rect { .clusters #_ rect {
fill: transparent; fill: transparent;
@ -46,9 +47,10 @@ export const Mermaid = ({ children, ...props }: IMermaidProps) => {
const mermaidRef = useRef<HTMLDivElement>(null); const mermaidRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
mermaid.render('mermaid', children, (svgCode) => { mermaid.render('mermaid', children, (svgCode, bindFunctions) => {
if (mermaidRef.current) { if (mermaidRef.current) {
mermaidRef.current.innerHTML = svgCode; mermaidRef.current.innerHTML = svgCode;
bindFunctions?.(mermaidRef.current);
} }
}); });
}, [children]); }, [children]);