Lens restructure (#540)

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman authored and GitHub committed 2020-06-30 14:35:16 +03:00
1 parent e810eab39f
commit b7974827d2
786 files changed
+14567 -24066

No files matched your search

@@ -0,0 +1,36 @@
.OverviewStatuses {
position: relative;
width: 100%;
min-width: $unit * 75;
background: $contentColor;
> .header {
position: relative;
padding: $padding * 2;
h5 {
color: $textColorPrimary;
}
}
.workloads {
display: grid;
grid-template-columns: repeat(auto-fit, 155px);
justify-content: space-evenly;
grid-gap: $margin;
padding: $padding * 2;
.workload {
margin-bottom: $margin * 2;
> .title {
text-align: center;
a {
color: $colorInfo;
}
}
}
}
}
@@ -0,0 +1,80 @@
import "./overview-statuses.scss"
import React from "react";
import { observer } from "mobx-react";
import { Trans } from "@lingui/macro";
import { OverviewWorkloadStatus } from "./overview-workload-status";
import { Link } from "react-router-dom";
import { cronJobsURL, daemonSetsURL, deploymentsURL, jobsURL, podsURL, statefulSetsURL } from "../+workloads";
import { podsStore } from "../+workloads-pods/pods.store";
import { deploymentStore } from "../+workloads-deployments/deployments.store";
import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store";
import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store";
import { jobStore } from "../+workloads-jobs/job.store";
import { cronJobStore } from "../+workloads-cronjobs/cronjob.store";
import { namespaceStore } from "../+namespaces/namespace.store";
import { PageFiltersList } from "../item-object-list/page-filters-list";
import { NamespaceSelectFilter } from "../+namespaces/namespace-select";
import { configStore } from "../../config.store";
import { isAllowedResource } from "../../api/rbac";
@observer
export class OverviewStatuses extends React.Component {
render() {
const { allowedResources } = configStore;
const { contextNs } = namespaceStore;
const pods = isAllowedResource("pods") ? podsStore.getAllByNs(contextNs) : [];
const deployments = isAllowedResource("deployments") ? deploymentStore.getAllByNs(contextNs) : [];
const statefulSets = isAllowedResource("statefulsets") ? statefulSetStore.getAllByNs(contextNs) : [];
const daemonSets = isAllowedResource("daemonsets") ? daemonSetStore.getAllByNs(contextNs) : [];
const jobs = isAllowedResource("jobs") ? jobStore.getAllByNs(contextNs) : [];
const cronJobs = isAllowedResource("cronjobs") ? cronJobStore.getAllByNs(contextNs) : [];
return (
<div className="OverviewStatuses">
<div className="header flex gaps align-center">
<h5 className="box grow"><Trans>Overview</Trans></h5>
<NamespaceSelectFilter/>
</div>
<PageFiltersList/>
<div className="workloads">
{ isAllowedResource("pods") &&
<div className="workload">
<div className="title"><Link to={podsURL()}><Trans>Pods</Trans> ({pods.length})</Link></div>
<OverviewWorkloadStatus status={podsStore.getStatuses(pods)}/>
</div>
}
{ isAllowedResource("deployments") &&
<div className="workload">
<div className="title"><Link to={deploymentsURL()}><Trans>Deployments</Trans> ({deployments.length})</Link></div>
<OverviewWorkloadStatus status={deploymentStore.getStatuses(deployments)}/>
</div>
}
{ isAllowedResource("statefulsets") &&
<div className="workload">
<div className="title"><Link to={statefulSetsURL()}><Trans>StatefulSets</Trans> ({statefulSets.length})</Link></div>
<OverviewWorkloadStatus status={statefulSetStore.getStatuses(statefulSets)}/>
</div>
}
{ isAllowedResource("daemonsets") &&
<div className="workload">
<div className="title"><Link to={daemonSetsURL()}><Trans>DaemonSets</Trans> ({daemonSets.length})</Link></div>
<OverviewWorkloadStatus status={daemonSetStore.getStatuses(daemonSets)}/>
</div>
}
{ isAllowedResource("jobs") &&
<div className="workload">
<div className="title"><Link to={jobsURL()}><Trans>Jobs</Trans> ({jobs.length})</Link></div>
<OverviewWorkloadStatus status={jobStore.getStatuses(jobs)}/>
</div>
}
{ isAllowedResource("cronjobs") &&
<div className="workload">
<div className="title"><Link to={cronJobsURL()}><Trans>CronJobs</Trans> ({cronJobs.length})</Link></div>
<OverviewWorkloadStatus status={cronJobStore.getStatuses(cronJobs)}/>
</div>
}
</div>
</div>
)
}
}
@@ -0,0 +1,15 @@
.OverviewWorkloadStatus {
--workload-status-running: #{$pod-status-running-color};
--workload-status-pending: #{$pod-status-pending-color};
--workload-status-evicted: #{$pod-status-evicted-color};
--workload-status-succeeded: #{$pod-status-succeeded-color};
--workload-status-failed: #{$pod-status-failed-color};
--workload-status-terminated: #{$pod-status-terminated-color};
--workload-status-unknown: #{$pod-status-unknown-color};
.PieChart {
.chart-container {
width: 110px
}
}
}
@@ -0,0 +1,79 @@
import "./overview-workload-status.scss";
import React from "react";
import capitalize from "lodash/capitalize";
import { findDOMNode } from 'react-dom';
import { observable } from "mobx";
import { observer } from "mobx-react";
import { PieChart } from "../chart";
import { cssVar } from "../../utils";
import { ChartData } from "chart.js";
import { themeStore } from "../../theme.store";
interface Props {
status: {
[key: string]: number;
};
}
@observer
export class OverviewWorkloadStatus extends React.Component<Props> {
@observable elem: HTMLElement
componentDidMount() {
this.elem = findDOMNode(this) as HTMLElement
}
getStatusColor(status: string) {
return cssVar(this.elem).get(`--workload-status-${status.toLowerCase()}`).toString();
}
renderChart() {
if (!this.elem) return null
const { status } = this.props
const statuses = Object.entries(status)
const chartData: Partial<ChartData> = {
labels: [] as string[],
datasets: [{
data: [1],
backgroundColor: [themeStore.activeTheme.colors.pieChartDefaultColor],
label: "Empty"
}]
}
if (statuses.some(([key, val]) => val > 0)) {
const dataset: any = {
data: [],
backgroundColor: [],
label: "Status",
}
statuses.forEach(([key, val]) => {
if (val !== 0) {
dataset.data.push(val)
dataset.backgroundColor.push(this.getStatusColor(key))
chartData.labels.push(capitalize(key) + ": " + val)
}
})
chartData.datasets[0] = dataset
}
const options = {
elements: {
arc: {
borderWidth: 0,
},
},
}
return (
<PieChart data={chartData} options={options}/>
)
}
render() {
return (
<div className="OverviewWorkloadStatus">
<div className="flex column align-center box grow">
{this.renderChart()}
</div>
</div>
)
}
}
@@ -0,0 +1,4 @@
.WorkloadsOverview {
--flex-gap: #{$padding * 2};
min-height: 100%;
}
@@ -0,0 +1,91 @@
import "./overview.scss"
import React from "react";
import { observable, when } from "mobx";
import { observer } from "mobx-react";
import { OverviewStatuses } from "./overview-statuses";
import { RouteComponentProps } from "react-router";
import { IWorkloadsOverviewRouteParams } from "../+workloads";
import { eventStore } from "../+events/event.store";
import { podsStore } from "../+workloads-pods/pods.store";
import { deploymentStore } from "../+workloads-deployments/deployments.store";
import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store";
import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store";
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
import { jobStore } from "../+workloads-jobs/job.store";
import { cronJobStore } from "../+workloads-cronjobs/cronjob.store";
import { Spinner } from "../spinner";
import { Events } from "../+events";
import { KubeObjectStore } from "../../kube-object.store";
import { isAllowedResource } from "../../api/rbac"
interface Props extends RouteComponentProps<IWorkloadsOverviewRouteParams> {
}
@observer
export class WorkloadsOverview extends React.Component<Props> {
@observable isReady = false;
@observable isUnmounting = false;
async componentDidMount() {
const stores: KubeObjectStore[] = [];
if (isAllowedResource("pods")) {
stores.push(podsStore);
}
if (isAllowedResource("deployments")) {
stores.push(deploymentStore);
}
if (isAllowedResource("daemonsets")) {
stores.push(daemonSetStore);
}
if (isAllowedResource("statefulsets")) {
stores.push(statefulSetStore);
}
if (isAllowedResource("replicasets")) {
stores.push(replicaSetStore);
}
if (isAllowedResource("jobs")) {
stores.push(jobStore);
}
if (isAllowedResource("cronjobs")) {
stores.push(cronJobStore);
}
if (isAllowedResource("events")) {
stores.push(eventStore);
}
this.isReady = stores.every(store => store.isLoaded);
await Promise.all(stores.map(store => store.loadAll()));
this.isReady = true;
const unsubscribeList = stores.map(store => store.subscribe());
await when(() => this.isUnmounting);
unsubscribeList.forEach(dispose => dispose());
}
componentWillUnmount() {
this.isUnmounting = true;
}
renderContents() {
if (!this.isReady) {
return <Spinner center/>
}
return (
<>
<OverviewStatuses/>
{ isAllowedResource("events") && <Events
compact
hideFilters
className="box grow"
/> }
</>
)
}
render() {
return (
<div className="WorkloadsOverview flex column gaps">
{this.renderContents()}
</div>
)
}
}