Skip to content

Commit

Permalink
feat: visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
Raymond Ottun committed Sep 26, 2021
1 parent f7b83ac commit 0e5826f
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 51 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<h1 align="center">Deputy</h1>
<p align="center">
<img src="ui/src/logo.svg" width="150">
</p>
<p align="center">
The easiest and quickest way to mock HTTP endpoints for development and testing purposes
</p>
Expand All @@ -11,8 +14,9 @@ The easiest and quickest way to mock HTTP endpoints for development and testing
<a href="https://sayjava.github.io/deputy/api">API »</a>
</p>
<p align="center">
<img src="https://github.com/sayjava/deputy/workflows/CI/badge.svg" />
<img src="https://github.com/sayjava/deputy/workflows/Build/badge.svg" />
<img src="https://github.com/sayjava/deputy/workflows/Docs/badge.svg" />
<img src="https://github.com/sayjava/deputy/workflows/Release/badge.svg" />
</p>

# What is Deputy?
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"build": "tsc",
"watch": "nodemon",
"dev": "ts-node src/deputy.ts",
"test": "jest"
"test": "jest",
"fill": "NODE_TLS_REJECT_UNAUTHORIZED=0 node random.js"
},
"devDependencies": {
"@types/express": "^4.17.9",
Expand Down
File renamed without changes.
3 changes: 1 addition & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
"start": "react-scripts start",
"build": "NODE_ENV=production react-scripts build",
"test": "echo 'Testing coming soon'",
"eject": "react-scripts eject",
"fill": "NODE_TLS_REJECT_UNAUTHORIZED=0 node fill.js"
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
Expand Down
8 changes: 7 additions & 1 deletion ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { MocksView } from './components/mocks/Mocks';
import { ServerControls } from './components/ServerControls';
import { Visualise } from './components/Visualise';
import { Header } from 'antd/lib/layout/layout';
import { ReactComponent as Logo } from './logo.svg';

const { Footer, Content } = Layout;

const App = () => {
Expand All @@ -21,7 +23,11 @@ const App = () => {
<Layout className="layout" style={{ minHeight: '100vh' }}>
<Header className="header">
<Row justify="space-between">
<h4 style={{ color: 'white' }}>Deputy Server</h4>
<Row align="middle">
<Logo width="30" />
<span style={{ color: 'white', paddingLeft: '10px' }}>Deputy</span>
</Row>

<Typography.Link href="https://sayjava.github.io/behave/" target="_blank">
Docs
</Typography.Link>
Expand Down
111 changes: 66 additions & 45 deletions ui/src/components/Visualise.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Modal, Space } from 'antd';
import { Alert, Button, Col, Modal, Row, Space } from 'antd';
import Checkbox from 'antd/lib/checkbox/Checkbox';
import mermaid from 'mermaid';
import { useEffect, useState } from 'react';
Expand All @@ -25,70 +25,85 @@ const getDestinationHost = (request, splitByURL) => {
interface VisualiseState {
byUrl: boolean;
open: boolean;
diagram: string;
code: string;
withProxy: boolean;
}

const Diagram = ({ code }) => {
const [state, setState] = useState({ svg: null, error: null, href: '' });

console.log('reading new code', code);

useEffect(() => {
try {
mermaid.parse(code);
mermaid.initialize({ startOnLoad: false });
mermaid.render('Requests', code, (svg) => {
const blob = new Blob([svg]);
const href = URL.createObjectURL(blob);
setState({ svg, error: null, href });
});
} catch (error) {
setState({ svg: null, error, href: '' });
console.error(error);
}
}, [code]);

return (
<div>
{state.error && <Alert message="SVG Error" description={state.error.toString()} />}
{state.svg && <div dangerouslySetInnerHTML={{ __html: state.svg }}></div>}
<Row justify="end">
<Button href={state.href} type="primary" download="sequence.svg">
Save Diagram
</Button>
</Row>
</div>
);
};

export const Visualise = () => {
const {
state: { records },
} = useServerState();

const [state, setState] = useState<VisualiseState>({ byUrl: false, open: false, diagram: '' });

const createDiagram = (code: string) => {
return new Promise((resolve, reject) => {
try {
mermaid.parse(code);
mermaid.initialize({ startOnLoad: false });
mermaid.render('Requests', code, resolve);
} catch (error) {
reject(error);
}
});
};
const [state, setState] = useState<VisualiseState>({ byUrl: false, open: false, code: null, withProxy: true });

const createSequenceGraph = async (newState: VisualiseState) => {
console.log(newState);
if (records.length === 0) {
return setState(Object.assign({}, state, newState, { code: null }));
}

const seqs = ['sequenceDiagram'];
records.forEach((rec) => {
const { request, response, proxyRequest } = rec;
seqs.push(`App->>Server: ${request.method} ${request.path}`);

seqs.push(`App->>Proxy: ${request.method} ${request.path}`);
const destRequest = proxyRequest || request;
const destination = getDestinationHost(request, newState.byUrl);

if (destination) {
seqs.push(`Server->>${destination}: ${destRequest.method} ${destRequest.path}`);
seqs.push(`${destination}-->>Server: ${response.statusCode}`);
seqs.push(`Proxy->>${destination}: ${destRequest.method} ${destRequest.path}`);
seqs.push(`${destination}-->>Proxy: ${response.statusCode}`);
} else {
console.info('no destination');
}

seqs.push(`Server->>App: ${response.statusCode}`);
});

try {
const sequence = seqs.join('\n');
console.info(sequence);
const newDiagram = await createDiagram(sequence);
setState(Object.assign({}, state, newState, { diagram: newDiagram }));
} catch (error) {
console.error(error);
}
const code = seqs.join('\n');
return setState(Object.assign({}, state, newState, { code }));
};

const onCancel = () => createSequenceGraph({ byUrl: null, open: false, diagram: '' });
const onSwitch = () => createSequenceGraph({ byUrl: !state.byUrl, open: true, diagram: state.diagram });

const blob = new Blob(state.diagram ? [state.diagram] : []);
const href = URL.createObjectURL(blob);
const onCancel = () => createSequenceGraph(Object.assign(state, { open: false }));
const switchByUrl = () => createSequenceGraph(Object.assign(state, { byUrl: !state.byUrl }));
const switchProxy = () => createSequenceGraph(Object.assign(state, { withProxy: !state.withProxy }));

return (
<div>
<Button
type="dashed"
color="blue"
onClick={() => createSequenceGraph({ byUrl: state.byUrl, open: true, diagram: '' })}
onClick={() => createSequenceGraph(Object.assign(state, { open: true }))}
>
Visualize
</Button>
Expand All @@ -98,17 +113,23 @@ export const Visualise = () => {
closable={true}
onCancel={onCancel}
title="Visualizations"
footer={[
<Button key="save" download="behave.svg" href={href}>
Save
</Button>,
]}
footer={[]}
>
<Space direction="vertical">
<Checkbox onChange={onSwitch} checked={state.byUrl}>
Split services by URL
</Checkbox>
<div dangerouslySetInnerHTML={{ __html: state.diagram }}></div>
<Space direction="vertical" style={{ width: '100%' }}>
<Row justify="center" style={{ width: '100%' }}>
<Col>
<Checkbox onChange={switchByUrl} checked={state.byUrl}>
Path based services
</Checkbox>
</Col>
<Col>
<Checkbox onChange={switchProxy} checked={state.withProxy} style={{ display: 'none' }}>
Show proxy
</Checkbox>
</Col>
</Row>

{state.code && <Diagram code={state.code} />}
</Space>
</Modal>
</div>
Expand Down
50 changes: 49 additions & 1 deletion ui/src/logo.svg
100644 → 100755
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0e5826f

Please sign in to comment.