Many nice things

This commit is contained in:
Eden Kirin
2024-01-24 21:58:39 +01:00
parent 76b1a2d4e9
commit 490f2bdde6
20 changed files with 298 additions and 72 deletions

View File

@ -1,11 +1,60 @@
import React from "react";
import EnvTabsContainer from "./EnvTabsContainer";
import { EnvTab } from "../types";
import LoadingIndicator from "./LoadingIndicator";
import { DashboardLoadError, DashboardResponseContent, EnvTab, Environment } from "../types";
import { ENVIRONMENT_TABS } from "../const";
import { dashboardApi } from "../api";
import { AxiosError } from "axios";
import LoadingError from "./LoadingError";
import EnvironmentList from "./dashboard/EnvironmentList";
export default function Dashboard() {
const onSelectEnvTab = (tab: EnvTab): void => {
console.log("tab changed:", tab);
const defaultEnv = ENVIRONMENT_TABS[0];
const [selectedEnv, setSelectedEnv] = React.useState(defaultEnv);
const [loadingEnv, setLoadingEnv] = React.useState(false);
const [loadingErr, setLoadingErr] = React.useState<DashboardLoadError | null>(null);
const [activeEnvironments, setActiveEnvironments] = React.useState<Environment[] | null>(null);
React.useEffect(() => {
loadEnv(defaultEnv);
}, []);
const onSelectEnvTab = (envTab: EnvTab): void => {
loadEnv(envTab);
};
return <EnvTabsContainer onSelect={onSelectEnvTab} />;
const loadEnv = (envTab: EnvTab) => {
console.log("loading env:", envTab);
setLoadingErr(null);
setLoadingEnv(true);
dashboardApi
.getFake(envTab.dashboardEndpoint)
.then((response) => {
return response.data.content;
})
.then((data: DashboardResponseContent) => {
setActiveEnvironments(data.environments);
})
.catch((error: AxiosError) => {
console.error(error);
setLoadingErr({
message: error.message,
url: envTab.dashboardEndpoint,
});
})
.finally(() => {
setLoadingEnv(false);
});
};
return (
<>
<LoadingIndicator active={loadingEnv} />
<EnvTabsContainer selectedEnv={selectedEnv} onSelect={onSelectEnvTab} />
{loadingErr && <LoadingError error={loadingErr} />}
{activeEnvironments && <EnvironmentList environments={activeEnvironments} />}
</>
);
}

View File

@ -10,13 +10,12 @@ interface OnSelectTab {
}
interface EnvTabsContainerProps {
selectedEnv: EnvTab;
onSelect: OnSelectTab;
}
export default function EnvTabsContainer({ onSelect }: EnvTabsContainerProps) {
const defaultTab = ENVIRONMENT_TABS[0];
const [selected, setSelected] = React.useState(defaultTab);
export default function EnvTabsContainer({ selectedEnv, onSelect }: EnvTabsContainerProps) {
const [selected, setSelected] = React.useState(selectedEnv);
const handleChange = (event: React.SyntheticEvent, newValue: EnvTab) => {
setSelected(newValue);
@ -28,7 +27,7 @@ export default function EnvTabsContainer({ onSelect }: EnvTabsContainerProps) {
});
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ width: "100%", marginBottom: "2rem" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs value={selected} onChange={handleChange}>
{tabs}

View File

@ -0,0 +1,17 @@
import React from "react";
import { DashboardLoadError } from "../types";
import Alert from "@mui/material/Alert";
import AlertTitle from "@mui/material/AlertTitle";
interface LoadingErrorProps {
error: DashboardLoadError;
}
export default function LoadingError({ error }: LoadingErrorProps) {
return (
<Alert severity="error">
<AlertTitle>{error.message}</AlertTitle>
<p>URL: {error.url}</p>
</Alert>
);
}

View File

@ -0,0 +1,15 @@
import React from "react";
import Box from "@mui/material/Box";
import LinearProgress from "@mui/material/LinearProgress";
interface LoadingIndicatorProps {
active: boolean;
}
export default function LoadingIndicator({ active }: LoadingIndicatorProps) {
return (
<Box sx={{ width: "100%" }}>
{active ? <LinearProgress /> : <Box className="linear-progress-placeholder" />}
</Box>
);
}

View File

@ -0,0 +1,24 @@
import React from "react";
import { Environment } from "../../types";
import TenantList from "./TenantList";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
interface EnvironmentListProps {
environments: Environment[];
}
export default function EnvironmentList({ environments }: EnvironmentListProps) {
const envItems = environments.map((env) => {
return (
<Box className="environment">
<Typography component={"h1"} key={env.name} className="title">
{env.name}
</Typography>
<TenantList tenants={env.tenants} />
</Box>
);
});
return <Box className="environment-list">{envItems}</Box>;
}

View File

@ -0,0 +1,22 @@
import React from "react";
import { Service } from "../../types";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
interface ServiceListProps {
services: Service[];
}
export default function ServiceList({ services }: ServiceListProps) {
const serviceItems = services.map((service) => {
return (
<Box className="service-card">
<Typography component={"h1"} key={service.name} className="service-name">
{service.name}
</Typography>
</Box>
);
});
return <Box className="service-list">{serviceItems}</Box>;
}

View File

@ -0,0 +1,25 @@
import React from "react";
import { Tenant } from "../../types";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import ServiceList from "./ServiceList";
interface TenantListProps {
tenants: Tenant[];
}
export default function TenantList({ tenants: tenants }: TenantListProps) {
const tenantItems = tenants.map((tenant) => {
const tenantName = tenant.name !== "default" ? `Tenant: ${tenant.name}` : "Multitenant";
return (
<Box className="tenant">
<Typography component={"h1"} key={tenant.name} className="tenant-name">
{tenantName}
</Typography>
<ServiceList services={tenant.services} />
</Box>
);
});
return <Box className="tenant-list">{tenantItems}</Box>;
}