Lens app source code (#119)

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2020-03-15 09:52:02 +02:00
1 parent 936cbd53d4
commit 1d0815abd2
797 files changed
+73714 -215

No files matched your search

@@ -0,0 +1,35 @@
.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-between;
grid-gap: $margin;
padding: $padding * 2;
.workload {
margin-bottom: $margin * 2;
> .title {
text-align: center;
a {
color: $colorInfo;
}
}
}
}
}
@@ -0,0 +1,65 @@
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";
@observer
export class OverviewStatuses extends React.Component {
render() {
const { contextNs } = namespaceStore;
const pods = podsStore.getAllByNs(contextNs);
const deployments = deploymentStore.getAllByNs(contextNs);
const statefulSets = statefulSetStore.getAllByNs(contextNs);
const daemonSets = daemonSetStore.getAllByNs(contextNs);
const jobs = jobStore.getAllByNs(contextNs);
const 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">
<div className="workload">
<div className="title"><Link to={podsURL()}><Trans>Pods</Trans> ({pods.length})</Link></div>
<OverviewWorkloadStatus status={podsStore.getStatuses(pods)}/>
</div>
<div className="workload">
<div className="title"><Link to={deploymentsURL()}><Trans>Deployments</Trans> ({deployments.length})</Link></div>
<OverviewWorkloadStatus status={deploymentStore.getStatuses(deployments)}/>
</div>
<div className="workload">
<div className="title"><Link to={statefulSetsURL()}><Trans>StatefulSets</Trans> ({statefulSets.length})</Link></div>
<OverviewWorkloadStatus status={statefulSetStore.getStatuses(statefulSets)}/>
</div>
<div className="workload">
<div className="title"><Link to={daemonSetsURL()}><Trans>DaemonSets</Trans> ({daemonSets.length})</Link></div>
<OverviewWorkloadStatus status={daemonSetStore.getStatuses(daemonSets)}/>
</div>
<div className="workload">
<div className="title"><Link to={jobsURL()}><Trans>Jobs</Trans> ({jobs.length})</Link></div>
<OverviewWorkloadStatus status={jobStore.getStatuses(jobs)}/>
</div>
<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,74 @@
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";
interface Props extends RouteComponentProps<IWorkloadsOverviewRouteParams> {
}
@observer
export class WorkloadsOverview extends React.Component<Props> {
@observable isReady = false;
@observable isUnmounting = false;
async componentDidMount() {
const stores = [
podsStore,
deploymentStore,
daemonSetStore,
statefulSetStore,
replicaSetStore,
jobStore,
cronJobStore,
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/>
<Events
compact
hideFilters
className="box grow"
/>
</>
)
}
render() {
return (
<div className="WorkloadsOverview flex column gaps">
{this.renderContents()}
</div>
)
}
}