mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into fix-1898/watch-api-streaming
# Conflicts: # src/renderer/api/kube-watch-api.ts # src/renderer/components/+namespaces/namespace.store.ts # src/renderer/components/+workloads-overview/overview.tsx # src/renderer/components/item-object-list/item-list-layout.tsx
This commit is contained in:
commit
7b4e060067
@ -46,6 +46,8 @@ module.exports = {
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true,
|
||||
}],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"eol-last": ["error", "always"],
|
||||
"semi": ["error", "always"],
|
||||
"object-shorthand": "error",
|
||||
"prefer-template": "error",
|
||||
@ -101,6 +103,8 @@ module.exports = {
|
||||
}],
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"eol-last": ["error", "always"],
|
||||
"object-shorthand": "error",
|
||||
"prefer-template": "error",
|
||||
"template-curly-spacing": "error",
|
||||
@ -162,6 +166,8 @@ module.exports = {
|
||||
}],
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"eol-last": ["error", "always"],
|
||||
"object-shorthand": "error",
|
||||
"prefer-template": "error",
|
||||
"template-curly-spacing": "error",
|
||||
|
||||
@ -219,7 +219,7 @@
|
||||
"request-promise-native": "^1.0.8",
|
||||
"semver": "^7.3.2",
|
||||
"serializr": "^2.0.3",
|
||||
"shell-env": "^3.0.0",
|
||||
"shell-env": "^3.0.1",
|
||||
"spdy": "^4.0.2",
|
||||
"tar": "^6.0.5",
|
||||
"tcp-port-used": "^1.0.1",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import get from "lodash/get";
|
||||
import { KubeObject } from "./kube-object";
|
||||
|
||||
interface IToleration {
|
||||
export interface IToleration {
|
||||
key?: string;
|
||||
operator?: string;
|
||||
effect?: string;
|
||||
|
||||
@ -23,11 +23,13 @@ interface IWarning extends ItemObject {
|
||||
kind: string;
|
||||
message: string;
|
||||
selfLink: string;
|
||||
age: string | number;
|
||||
}
|
||||
|
||||
enum sortBy {
|
||||
type = "type",
|
||||
object = "object"
|
||||
object = "object",
|
||||
age = "age",
|
||||
}
|
||||
|
||||
@observer
|
||||
@ -35,6 +37,7 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
private sortCallbacks = {
|
||||
[sortBy.type]: (warning: IWarning) => warning.kind,
|
||||
[sortBy.object]: (warning: IWarning) => warning.getName(),
|
||||
[sortBy.age]: (warning: IWarning) => warning.age || "",
|
||||
};
|
||||
|
||||
@computed get warnings() {
|
||||
@ -42,15 +45,16 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
|
||||
// Node bad conditions
|
||||
nodesStore.items.forEach(node => {
|
||||
const { kind, selfLink, getId, getName } = node;
|
||||
const { kind, selfLink, getId, getName, getAge } = node;
|
||||
|
||||
node.getWarningConditions().forEach(({ message }) => {
|
||||
warnings.push({
|
||||
kind,
|
||||
age: getAge(),
|
||||
getId,
|
||||
getName,
|
||||
selfLink,
|
||||
kind,
|
||||
message,
|
||||
selfLink,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -59,12 +63,13 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
const events = eventStore.getWarnings();
|
||||
|
||||
events.forEach(error => {
|
||||
const { message, involvedObject } = error;
|
||||
const { message, involvedObject, getAge } = error;
|
||||
const { uid, name, kind } = involvedObject;
|
||||
|
||||
warnings.push({
|
||||
getId: () => uid,
|
||||
getName: () => name,
|
||||
age: getAge(),
|
||||
message,
|
||||
kind,
|
||||
selfLink: lookupApiLink(involvedObject, error),
|
||||
@ -78,7 +83,7 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
getTableRow(uid: string) {
|
||||
const { warnings } = this;
|
||||
const warning = warnings.find(warn => warn.getId() == uid);
|
||||
const { getId, getName, message, kind, selfLink } = warning;
|
||||
const { getId, getName, message, kind, selfLink, age } = warning;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
@ -96,6 +101,9 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
<TableCell className="kind">
|
||||
{kind}
|
||||
</TableCell>
|
||||
<TableCell className="age">
|
||||
{age}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
@ -139,6 +147,7 @@ export class ClusterIssues extends React.Component<Props> {
|
||||
<TableCell className="message">Message</TableCell>
|
||||
<TableCell className="object" sortBy={sortBy.object}>Object</TableCell>
|
||||
<TableCell className="kind" sortBy={sortBy.type}>Type</TableCell>
|
||||
<TableCell className="timestamp" sortBy={sortBy.age}>Age</TableCell>
|
||||
</TableHead>
|
||||
</Table>
|
||||
</>
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import { IToleration } from "../../../api/workload-kube-object";
|
||||
import { PodTolerations } from "../pod-tolerations";
|
||||
|
||||
const tolerations: IToleration[] =[
|
||||
{
|
||||
key: "CriticalAddonsOnly",
|
||||
operator: "Exist",
|
||||
effect: "NoExecute",
|
||||
tolerationSeconds: 3600
|
||||
},
|
||||
{
|
||||
key: "node.kubernetes.io/not-ready",
|
||||
operator: "NoExist",
|
||||
effect: "NoSchedule",
|
||||
tolerationSeconds: 7200
|
||||
},
|
||||
];
|
||||
|
||||
describe("<PodTolerations />", () => {
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<PodTolerations tolerations={tolerations} />);
|
||||
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("shows all tolerations", () => {
|
||||
const { container } = render(<PodTolerations tolerations={tolerations} />);
|
||||
const rows = container.querySelectorAll(".TableRow");
|
||||
|
||||
expect(rows[0].querySelector(".key").textContent).toBe("CriticalAddonsOnly");
|
||||
expect(rows[0].querySelector(".operator").textContent).toBe("Exist");
|
||||
expect(rows[0].querySelector(".effect").textContent).toBe("NoExecute");
|
||||
expect(rows[0].querySelector(".seconds").textContent).toBe("3600");
|
||||
|
||||
expect(rows[1].querySelector(".key").textContent).toBe("node.kubernetes.io/not-ready");
|
||||
expect(rows[1].querySelector(".operator").textContent).toBe("NoExist");
|
||||
expect(rows[1].querySelector(".effect").textContent).toBe("NoSchedule");
|
||||
expect(rows[1].querySelector(".seconds").textContent).toBe("7200");
|
||||
});
|
||||
|
||||
it("sorts table properly", () => {
|
||||
const { container, getByText } = render(<PodTolerations tolerations={tolerations} />);
|
||||
const headCell = getByText("Key");
|
||||
|
||||
fireEvent.click(headCell);
|
||||
fireEvent.click(headCell);
|
||||
|
||||
const rows = container.querySelectorAll(".TableRow");
|
||||
|
||||
expect(rows[0].querySelector(".key").textContent).toBe("node.kubernetes.io/not-ready");
|
||||
});
|
||||
});
|
||||
@ -1,5 +1,23 @@
|
||||
.PodDetailsTolerations {
|
||||
.toleration {
|
||||
margin-bottom: $margin;
|
||||
grid-template-columns: auto;
|
||||
|
||||
.PodTolerations {
|
||||
margin-top: var(--margin);
|
||||
}
|
||||
|
||||
// Expanding value cell to cover 2 columns (whole Drawer width)
|
||||
|
||||
> .name {
|
||||
grid-row-start: 1;
|
||||
grid-column-start: 1;
|
||||
}
|
||||
|
||||
> .value {
|
||||
grid-row-start: 1;
|
||||
grid-column-start: 1;
|
||||
}
|
||||
|
||||
.DrawerParamToggler > .params {
|
||||
margin-left: var(--drawer-item-title-width);
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
import "./pod-details-tolerations.scss";
|
||||
import React from "react";
|
||||
import { Pod, Deployment, DaemonSet, StatefulSet, ReplicaSet, Job } from "../../api/endpoints";
|
||||
import { DrawerParamToggler, DrawerItem } from "../drawer";
|
||||
import { WorkloadKubeObject } from "../../api/workload-kube-object";
|
||||
import { PodTolerations } from "./pod-tolerations";
|
||||
|
||||
interface Props {
|
||||
workload: Pod | Deployment | DaemonSet | StatefulSet | ReplicaSet | Job;
|
||||
workload: WorkloadKubeObject;
|
||||
}
|
||||
|
||||
export class PodDetailsTolerations extends React.Component<Props> {
|
||||
@ -17,20 +18,7 @@ export class PodDetailsTolerations extends React.Component<Props> {
|
||||
return (
|
||||
<DrawerItem name="Tolerations" className="PodDetailsTolerations">
|
||||
<DrawerParamToggler label={tolerations.length}>
|
||||
{
|
||||
tolerations.map((toleration, index) => {
|
||||
const { key, operator, effect, tolerationSeconds } = toleration;
|
||||
|
||||
return (
|
||||
<div className="toleration" key={index}>
|
||||
<DrawerItem name="Key">{key}</DrawerItem>
|
||||
{operator && <DrawerItem name="Operator">{operator}</DrawerItem>}
|
||||
{effect && <DrawerItem name="Effect">{effect}</DrawerItem>}
|
||||
{!!tolerationSeconds && <DrawerItem name="Effect">{tolerationSeconds}</DrawerItem>}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
<PodTolerations tolerations={tolerations} />
|
||||
</DrawerParamToggler>
|
||||
</DrawerItem>
|
||||
);
|
||||
|
||||
14
src/renderer/components/+workloads-pods/pod-tolerations.scss
Normal file
14
src/renderer/components/+workloads-pods/pod-tolerations.scss
Normal file
@ -0,0 +1,14 @@
|
||||
.PodTolerations {
|
||||
.TableHead {
|
||||
background-color: var(--drawerSubtitleBackground);
|
||||
}
|
||||
|
||||
.TableCell {
|
||||
white-space: normal;
|
||||
word-break: normal;
|
||||
|
||||
&.key {
|
||||
flex-grow: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/renderer/components/+workloads-pods/pod-tolerations.tsx
Normal file
63
src/renderer/components/+workloads-pods/pod-tolerations.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import "./pod-tolerations.scss";
|
||||
import React from "react";
|
||||
import uniqueId from "lodash/uniqueId";
|
||||
|
||||
import { IToleration } from "../../api/workload-kube-object";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
||||
|
||||
interface Props {
|
||||
tolerations: IToleration[];
|
||||
}
|
||||
|
||||
enum sortBy {
|
||||
Key = "key",
|
||||
Operator = "operator",
|
||||
Effect = "effect",
|
||||
Seconds = "seconds",
|
||||
}
|
||||
|
||||
const sortingCallbacks = {
|
||||
[sortBy.Key]: (toleration: IToleration) => toleration.key,
|
||||
[sortBy.Operator]: (toleration: IToleration) => toleration.operator,
|
||||
[sortBy.Effect]: (toleration: IToleration) => toleration.effect,
|
||||
[sortBy.Seconds]: (toleration: IToleration) => toleration.tolerationSeconds,
|
||||
};
|
||||
|
||||
const getTableRow = (toleration: IToleration) => {
|
||||
const { key, operator, effect, tolerationSeconds } = toleration;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
key={uniqueId("toleration-")}
|
||||
sortItem={toleration}
|
||||
nowrap
|
||||
>
|
||||
<TableCell className="key">{key}</TableCell>
|
||||
<TableCell className="operator">{operator}</TableCell>
|
||||
<TableCell className="effect">{effect}</TableCell>
|
||||
<TableCell className="seconds">{tolerationSeconds}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
export function PodTolerations({ tolerations }: Props) {
|
||||
return (
|
||||
<Table
|
||||
selectable
|
||||
scrollable={false}
|
||||
sortable={sortingCallbacks}
|
||||
sortSyncWithUrl={false}
|
||||
className="PodTolerations"
|
||||
>
|
||||
<TableHead sticky={false}>
|
||||
<TableCell className="key" sortBy={sortBy.Key}>Key</TableCell>
|
||||
<TableCell className="operator" sortBy={sortBy.Operator}>Operator</TableCell>
|
||||
<TableCell className="effect" sortBy={sortBy.Effect}>Effect</TableCell>
|
||||
<TableCell className="seconds" sortBy={sortBy.Seconds}>Seconds</TableCell>
|
||||
</TableHead>
|
||||
{
|
||||
tolerations.map(getTableRow)
|
||||
}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
@ -1,12 +1,16 @@
|
||||
.InfoPanel {
|
||||
@include hidden-scrollbar;
|
||||
|
||||
background: $dockInfoBackground;
|
||||
padding: $padding $padding * 2;
|
||||
background: var(--dockInfoBackground);
|
||||
padding: var(--padding) calc(var(--padding) * 2);
|
||||
flex-shrink: 0;
|
||||
|
||||
.Spinner {
|
||||
margin-right: $padding;
|
||||
margin-right: var(--padding);
|
||||
}
|
||||
|
||||
.Badge {
|
||||
background-color: var(--dockBadgeBackground);
|
||||
}
|
||||
|
||||
> .controls {
|
||||
@ -15,8 +19,8 @@
|
||||
|
||||
&:not(:empty) + .info {
|
||||
min-height: 25px;
|
||||
padding-left: $padding;
|
||||
padding-right: $padding;
|
||||
padding-left: var(--padding);
|
||||
padding-right: var(--padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,12 @@ export const LogControls = observer((props: Props) => {
|
||||
return (
|
||||
<div className={cssNames("LogControls flex gaps align-center justify-space-between wrap")}>
|
||||
<div className="time-range">
|
||||
{since && `Logs from ${new Date(since[0]).toLocaleString()}`}
|
||||
{since && (
|
||||
<span>
|
||||
Logs from{" "}
|
||||
<b>{new Date(since[0]).toLocaleString()}</b>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gaps align-center">
|
||||
<Checkbox
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
.DrawerItem {
|
||||
--drawer-item-title-width: 30%;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: minmax(30%, min-content) auto;
|
||||
grid-template-columns: minmax(var(--drawer-item-title-width), min-content) auto;
|
||||
border-bottom: 1px solid $borderFaintColor;
|
||||
padding: $padding 0;
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export class DrawerParamToggler extends React.Component<DrawerParamTogglerProps,
|
||||
|
||||
return (
|
||||
<div className="DrawerParamToggler">
|
||||
<div className="flex gaps align-center">
|
||||
<div className="flex gaps align-center params">
|
||||
<div className="param-label">{label}</div>
|
||||
<div className="param-link" onClick={this.toggle}>
|
||||
<span className="param-link-text">{link}</span>
|
||||
|
||||
@ -69,7 +69,6 @@
|
||||
padding: var(--spacing);
|
||||
|
||||
.Table .TableHead {
|
||||
background-color: $contentColor;
|
||||
border-bottom: 1px solid $borderFaintColor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import "./item-list-layout.scss";
|
||||
import groupBy from "lodash/groupBy";
|
||||
|
||||
import React, { ReactNode } from "react";
|
||||
import { computed, observable, reaction, toJS } from "mobx";
|
||||
import { computed, IReactionDisposer, observable, reaction, toJS } from "mobx";
|
||||
import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ConfirmDialog, ConfirmDialogParams } from "../confirm-dialog";
|
||||
import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallback } from "../table";
|
||||
|
||||
@ -3,11 +3,9 @@
|
||||
|
||||
html {
|
||||
$menuBackgroundColor: $contentColor;
|
||||
$menuSelectedOptionBgc: $layoutBackground;
|
||||
|
||||
--select-menu-bgc: #{$menuBackgroundColor};
|
||||
--select-menu-border-color: #{$halfGray};
|
||||
--select-option-selected-bgc: #{$menuSelectedOptionBgc};
|
||||
--select-option-selected-color: #{$selectOptionHoveredColor};
|
||||
--select-option-focused-bgc: #{$colorInfo};
|
||||
--select-option-focused-color: #{$textColorAccent};
|
||||
@ -95,7 +93,7 @@ html {
|
||||
}
|
||||
|
||||
&--is-selected {
|
||||
background: var(--select-option-selected-bgc);
|
||||
background: var(--menuSelectedOptionBgc);
|
||||
color: var(--select-option-selected-color);
|
||||
}
|
||||
|
||||
@ -148,7 +146,6 @@ html {
|
||||
&.theme-light {
|
||||
--select-menu-bgc: white;
|
||||
--select-option-selected-color: $textColorSecondary;
|
||||
--select-option-selected-bgc: $textColorSecondary;
|
||||
|
||||
.Select {
|
||||
&__multi-value {
|
||||
|
||||
@ -65,6 +65,7 @@
|
||||
"dockEditorKeyword": "#ffffff",
|
||||
"dockEditorComment": "#808080",
|
||||
"dockEditorActiveLineBackground": "#3a3d41",
|
||||
"dockBadgeBackground": "#36393e",
|
||||
"logsBackground": "#000000",
|
||||
"logsForeground": "#ffffff",
|
||||
"logRowHoverBackground": "#35373a",
|
||||
@ -114,6 +115,7 @@
|
||||
"lineProgressBackground": "#414448",
|
||||
"radioActiveBackground": "#36393e",
|
||||
"menuActiveBackground": "#36393e",
|
||||
"menuSelectedOptionBgc": "#36393e",
|
||||
"scrollBarColor": "#5f6064"
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,13 +59,14 @@
|
||||
"colorVague": "#ededed",
|
||||
"colorTerminated": "#9dabb5",
|
||||
"dockHeadBackground": "#e8e8e8",
|
||||
"dockInfoBackground": "#e8e8e8",
|
||||
"dockInfoBackground": "#f3f3f3",
|
||||
"dockInfoBorderColor": "#c9cfd3",
|
||||
"dockEditorBackground": "#24292e",
|
||||
"dockEditorTag": "#8e97a3",
|
||||
"dockEditorKeyword": "#ffffff",
|
||||
"dockEditorComment": "#808080",
|
||||
"dockEditorActiveLineBackground": "#3a3d41",
|
||||
"dockBadgeBackground": "#dedede",
|
||||
"logsBackground": "#24292e",
|
||||
"logsForeground": "#ffffff",
|
||||
"logRowHoverBackground": "#35373a",
|
||||
@ -115,6 +116,7 @@
|
||||
"lineProgressBackground": "#e8e8e8",
|
||||
"radioActiveBackground": "#f1f1f1",
|
||||
"menuActiveBackground": "#e8e8e8",
|
||||
"menuSelectedOptionBgc": "#e8e8e8",
|
||||
"scrollBarColor": "#bbbbbb",
|
||||
"canvasBackground": "#24292e"
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ $helmDescriptionPreColor: var(--helmDescriptionPreColor);
|
||||
$dockHeadBackground: var(--dockHeadBackground);
|
||||
$dockInfoBackground: var(--dockInfoBackground);
|
||||
$dockInfoBorderColor: var(--dockInfoBorderColor);
|
||||
$dockBadgeBackground: var(--dockBadgeBackground);
|
||||
|
||||
// Terminal
|
||||
$terminalBackground: var(--terminalBackground);
|
||||
@ -130,3 +131,4 @@ $selectOptionHoveredColor: var(--selectOptionHoveredColor);
|
||||
$lineProgressBackground: var(--lineProgressBackground);
|
||||
$radioActiveBackground: var(--radioActiveBackground);
|
||||
$menuActiveBackground: var(--menuActiveBackground);
|
||||
$menuSelectedOptionBgc: var(--menuSelectedOptionBgc);
|
||||
@ -12141,10 +12141,10 @@ shebang-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
shell-env@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shell-env/-/shell-env-3.0.0.tgz#42484ebd0798ee321ba69f6151f2aeab13fde1d4"
|
||||
integrity sha512-zE0lGldowbCLnnorLnOUO6gLSwEoW4u+qWcEV1HH2qje5sIg0PvBd+8ro74EgSZv0MBEP2dROD6vSKhGDbUIMQ==
|
||||
shell-env@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/shell-env/-/shell-env-3.0.1.tgz#515a62f6cbd5e139365be2535745e8e53438ce77"
|
||||
integrity sha512-b09fpMipAQ9ObwvIeKoQFLDXcEcCpYUUZanlad4OYQscw2I49C/u97OPQg9jWYo36bRDn62fbe07oWYqovIvKA==
|
||||
dependencies:
|
||||
default-shell "^1.0.1"
|
||||
execa "^1.0.0"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user