Status card
This commit is contained in:
@ -11,7 +11,7 @@ interface EnvironmentListProps {
|
|||||||
export default function EnvironmentList({ environments }: EnvironmentListProps) {
|
export default function EnvironmentList({ environments }: EnvironmentListProps) {
|
||||||
const envItems = environments.map((env) => {
|
const envItems = environments.map((env) => {
|
||||||
return (
|
return (
|
||||||
<Box className="environment" sx={{ marginBottom: "2rem" }}>
|
<Box className="environment" key={env.name} sx={{ marginBottom: "2rem" }}>
|
||||||
<Typography variant={"h2"} key={env.name} className="title">
|
<Typography variant={"h2"} key={env.name} className="title">
|
||||||
<Typography component="span" variant={"h5"} key={env.name} sx={{ marginRight: "1rem" }}>
|
<Typography component="span" variant={"h5"} key={env.name} sx={{ marginRight: "1rem" }}>
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import Stack from "@mui/material/Stack";
|
|||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import LaunchIcon from "@mui/icons-material/Launch";
|
import LaunchIcon from "@mui/icons-material/Launch";
|
||||||
import Tooltip from "@mui/material/Tooltip";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
import Chip from "@mui/material/Chip";
|
||||||
import Grid from "@mui/material/Unstable_Grid2";
|
import Grid from "@mui/material/Unstable_Grid2";
|
||||||
|
|
||||||
interface ServiceCardProps {
|
interface ServiceCardProps {
|
||||||
@ -26,22 +27,50 @@ interface ServiceNodePropps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ServiceNode({ node }: ServiceNodePropps) {
|
function ServiceNode({ node }: ServiceNodePropps) {
|
||||||
|
const nodeName = node.health_check_status?.status_ok ? (
|
||||||
|
<Tooltip title={`Node ${node.name} is healthy`}>
|
||||||
|
<Chip label={node.name} color="success" className="node-name" />
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<Tooltip title={node.health_check_status?.message}>
|
||||||
|
<Chip label={node.name} color="error" className="node-name" />
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
|
||||||
|
let tenantsHealth: boolean[] = [];
|
||||||
|
if (node.health_check_status?.status_per_tenant) {
|
||||||
|
tenantsHealth = Object.values(node.health_check_status?.status_per_tenant);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tenantsStatus = null;
|
||||||
|
if (tenantsHealth.length > 0) {
|
||||||
|
const okValues = tenantsHealth.filter((t) => t === true);
|
||||||
|
|
||||||
|
switch (okValues.length) {
|
||||||
|
case 0:
|
||||||
|
tenantsStatus = <Chip label="tenants" color="error" className="node-name" />;
|
||||||
|
break;
|
||||||
|
case tenantsHealth.length:
|
||||||
|
tenantsStatus = <Chip label="tenants" color="success" className="node-name" />;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tenantsStatus = <Chip label="tenants" color="warning" className="node-name" />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={2} className="service-node" sx={{ alignItems: "center" }}>
|
<Grid container spacing={2} className="service-node" sx={{ alignItems: "center" }}>
|
||||||
<Grid xs={1}>
|
<Grid xs={2}>{nodeName}</Grid>
|
||||||
<Typography variant="h6" className="name">
|
|
||||||
{node.name}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid xs={6}>
|
<Grid xs={6}>
|
||||||
<Typography className="version">{node.app_details?.app_version || "no version"}</Typography>
|
<Typography className="version">{node.app_details?.app_version || "no version"}</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid xs={1}>
|
<Grid xs={4} sx={{ textAlign: "right" }} className="status">
|
||||||
<Tooltip title={node.url}>
|
<Tooltip title={node.url}>
|
||||||
<IconButton aria-label="delete" target="_blank" href={node.url}>
|
<IconButton target="_blank" href={node.url} className="docs-url">
|
||||||
<LaunchIcon />
|
<LaunchIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{tenantsStatus}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
@ -49,19 +78,19 @@ function ServiceNode({ node }: ServiceNodePropps) {
|
|||||||
|
|
||||||
export default function ServiceCard({ service }: ServiceCardProps) {
|
export default function ServiceCard({ service }: ServiceCardProps) {
|
||||||
const nodes = service.nodes.map((node) => {
|
const nodes = service.nodes.map((node) => {
|
||||||
return (
|
return <ServiceNode node={node} key={node.name} />;
|
||||||
<>
|
|
||||||
<ServiceNode node={node} key={node.name} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="service-card" sx={{ width: "400px" }}>
|
<Card className="service-card ok">
|
||||||
<CardContent>
|
<Stack direction="row" className="service-title-container">
|
||||||
<Typography variant="h5" component="div">
|
<Typography variant="h5" component="div" className="service-title">
|
||||||
{normalizeServiceName(service.name)}
|
{normalizeServiceName(service.name)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{/* <CircleIcon className="indicator" /> */}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<CardContent>
|
||||||
<Stack spacing={2}>{nodes}</Stack>
|
<Stack spacing={2}>{nodes}</Stack>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@ -8,11 +8,11 @@ interface TenantListProps {
|
|||||||
tenants: Tenant[];
|
tenants: Tenant[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TenantList({ tenants: tenants }: TenantListProps) {
|
export default function TenantList({ tenants }: TenantListProps) {
|
||||||
const tenantItems = tenants.map((tenant) => {
|
const tenantItems = tenants.map((tenant) => {
|
||||||
const tenantName = tenant.name !== "default" ? `Tenant: ${tenant.name}` : "Multitenant";
|
const tenantName = tenant.name !== "default" ? `Tenant: ${tenant.name}` : "Multitenant";
|
||||||
return (
|
return (
|
||||||
<Box className="tenant">
|
<Box key={tenant.name} className="tenant">
|
||||||
<Typography variant={"h3"} key={tenant.name} className="tenant-name" sx={{ marginBottom: "1rem" }}>
|
<Typography variant={"h3"} key={tenant.name} className="tenant-name" sx={{ marginBottom: "1rem" }}>
|
||||||
{tenantName}
|
{tenantName}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
46
src/scss/_service-card.scss
Normal file
46
src/scss/_service-card.scss
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
$color-ok: #27cb30;
|
||||||
|
$color-warning: #ed6c02;
|
||||||
|
$color-danger: #d32f2f;
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
width: 400px;
|
||||||
|
.service-title-container {
|
||||||
|
color: white;
|
||||||
|
background-color: #15232d;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ok {
|
||||||
|
.indicator {
|
||||||
|
color: $color-ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
.indicator {
|
||||||
|
color: $color-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.danger {
|
||||||
|
.indicator {
|
||||||
|
color: $color-danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-node {
|
||||||
|
.node-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.docs-url {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.status-icon {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
@import "common";
|
@import "common";
|
||||||
@import "app-header";
|
@import "app-header";
|
||||||
@import "linear-progress";
|
@import "linear-progress";
|
||||||
|
@import "service-card";
|
||||||
|
|||||||
Reference in New Issue
Block a user