Skip to content

Commit abe09c0

Browse files
committed
feat(visualization): Add application components and simple data mocks.
1 parent 07e3ac3 commit abe09c0

9 files changed

Lines changed: 195 additions & 1 deletion

File tree

visualization/ui/src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { MantineProvider } from "@mantine/core";
22
import "@mantine/core/styles.css";
33
import { Route, Routes } from "react-router";
44
import Home from "./home/Home";
5+
import theme from "./providers/theme";
56

67
function App() {
78
return (
8-
<MantineProvider>
9+
<MantineProvider theme={theme} defaultColorScheme="auto">
910
<Routes>
1011
<Route path="/" element={<Home />} />
1112
</Routes>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.application {
2+
transition: all 0.2s ease-out;
3+
&:hover {
4+
border-color: var(--mantine-color-cyan-5);
5+
transform: translate3d(0px, -8px, 13px);
6+
}
7+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Badge, Card, Group, Stack, Text } from "@mantine/core";
2+
import type { FC } from "react";
3+
import { TbCpu, TbCpuOff, TbInbox } from "react-icons/tb";
4+
import type { Hex } from "viem";
5+
import styles from "./Application.module.css";
6+
7+
type ApplicationState = "ENABLED" | "DISABLED" | "INOPERABLE";
8+
type ConsensusType = "PRT" | "QUORUM" | "AUTHORITY";
9+
10+
export interface Application {
11+
address: Hex;
12+
name?: string;
13+
consensusType: ConsensusType;
14+
state: ApplicationState;
15+
processedInputs: number;
16+
}
17+
18+
type Props = { application: Application };
19+
20+
const getStateColour = (state: ApplicationState) => {
21+
switch (state) {
22+
case "ENABLED":
23+
return "green";
24+
case "DISABLED":
25+
return "red";
26+
case "INOPERABLE":
27+
return "gray";
28+
default:
29+
return "black";
30+
}
31+
};
32+
33+
const iconSize = 24;
34+
35+
export const ApplicationCard: FC<Props> = ({ application }) => {
36+
const stateColour = getStateColour(application.state);
37+
38+
return (
39+
<Card shadow="md" withBorder className={styles.application}>
40+
<Stack gap="0">
41+
<Group justify="space-between">
42+
<Text size="xl">{application.name}</Text>
43+
<Badge size="md">{application.consensusType}</Badge>
44+
</Group>
45+
<Text c="dimmed" size="xs">
46+
{application.address}
47+
</Text>
48+
</Stack>
49+
50+
<Group pt="md" justify="space-between" align="center">
51+
<Group gap="3">
52+
{application.state === "ENABLED" ? (
53+
<TbCpu color={stateColour} size={iconSize} />
54+
) : (
55+
<TbCpuOff color={stateColour} size={iconSize} />
56+
)}
57+
<Badge color={stateColour}>{application.state}</Badge>
58+
</Group>
59+
<Group gap="3">
60+
<TbInbox size={iconSize} />
61+
<Text>Inputs Processed</Text>
62+
<Badge variant="dot" size="md">
63+
{application.processedInputs}
64+
</Badge>
65+
</Group>
66+
</Group>
67+
</Card>
68+
);
69+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Container, Stack } from "@mantine/core";
2+
import type { FC } from "react";
3+
import { ApplicationCard } from "./Application";
4+
import { applications } from "./application.mocks";
5+
6+
const ListApplications: FC = () => {
7+
return (
8+
<Container fluid miw="var(--mantine-breakpoint-xs)">
9+
<Stack gap={5}>
10+
{applications.map((app) => (
11+
<ApplicationCard key={app.address} application={app} />
12+
))}
13+
</Stack>
14+
</Container>
15+
);
16+
};
17+
18+
export default ListApplications;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { Application } from "./Application";
2+
3+
export const HoneypotDapp: Application = {
4+
address: "0x4c1E74EF88a75C24e49eddD9f70D82A94D19251c",
5+
name: "Honeypot",
6+
consensusType: "PRT",
7+
state: "ENABLED",
8+
processedInputs: 8,
9+
};
10+
11+
export const applications: Application[] = [
12+
{
13+
address: "0x4c1E74EF88a75C24e49eddD9f70D82A94D19251c",
14+
name: "Honeypot",
15+
consensusType: "PRT",
16+
state: "ENABLED",
17+
processedInputs: 8,
18+
},
19+
{
20+
address: "0x1590B6096A48A509286cdec2cb68E0DF292BFEf6",
21+
name: "Comet",
22+
consensusType: "AUTHORITY",
23+
state: "ENABLED",
24+
processedInputs: 100,
25+
},
26+
{
27+
address: "0x70ac08179605AF2D9e75782b8DEcDD3c22aA4D0C",
28+
name: "SunDapp",
29+
consensusType: "QUORUM",
30+
state: "DISABLED",
31+
processedInputs: 15,
32+
},
33+
{
34+
address: "0x70ac08179605AF2D9e75782b8DEcDD3c22aA4D0C",
35+
name: "BrokenDapp",
36+
consensusType: "PRT",
37+
state: "INOPERABLE",
38+
processedInputs: 45,
39+
},
40+
];
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { MantineProvider } from "@mantine/core";
2+
import type { FC, PropsWithChildren } from "react";
3+
import theme from "./theme";
4+
5+
export const StyleProvider: FC<PropsWithChildren> = ({ children }) => {
6+
return <MantineProvider theme={theme}>{children}</MantineProvider>;
7+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createTheme, DEFAULT_THEME, mergeMantineTheme } from "@mantine/core";
2+
3+
const theme = createTheme({
4+
fontFamily: "serif",
5+
primaryColor: "cyan",
6+
});
7+
8+
export default mergeMantineTheme(DEFAULT_THEME, theme);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Meta, StoryObj } from "@storybook/react-vite";
2+
import { ApplicationCard } from "../../features/application/Application";
3+
import { HoneypotDapp } from "../../features/application/application.mocks";
4+
5+
const meta = {
6+
title: "Components/Application",
7+
component: ApplicationCard,
8+
parameters: {
9+
layout: "centered",
10+
},
11+
} satisfies Meta<typeof ApplicationCard>;
12+
13+
export default meta;
14+
type Story = StoryObj<typeof meta>;
15+
16+
export const Enabled: Story = {
17+
args: { application: HoneypotDapp },
18+
};
19+
20+
export const Disabled: Story = {
21+
args: { application: { ...HoneypotDapp, state: "DISABLED" } },
22+
};
23+
24+
export const Inoperable: Story = {
25+
args: { application: { ...HoneypotDapp, state: "INOPERABLE" } },
26+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Meta, StoryObj } from "@storybook/react-vite";
2+
import ListApplications from "../../features/application/ListApplications";
3+
4+
const meta = {
5+
title: "Pages/ListApplications",
6+
component: ListApplications,
7+
parameters: {
8+
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
9+
layout: "centered",
10+
},
11+
} satisfies Meta<typeof ListApplications>;
12+
13+
export default meta;
14+
type Story = StoryObj<typeof meta>;
15+
16+
export const Default: Story = {
17+
args: {},
18+
};

0 commit comments

Comments
 (0)