mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
add no-unused and react/recommended to eslint (#1523)
* add no-unused-vars and no-unused-imports * added quotes: double, and remove ignore pattern * move itif and describeif into utils Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
10eb082854
commit
7451869c25
199 files changed
+1178
-807
No files matched your search
@@ -14,7 +14,7 @@ export class ApiManager {
|
||||
return this.apis.get(pathOrCallback) || this.apis.get(KubeApi.parseApi(pathOrCallback).apiBase);
|
||||
}
|
||||
|
||||
return Array.from(this.apis.values()).find(pathOrCallback ?? ((api: KubeApi) => true));
|
||||
return Array.from(this.apis.values()).find(pathOrCallback ?? (() => true));
|
||||
}
|
||||
|
||||
registerApi(apiBase: string, api: KubeApi) {
|
||||
|
||||
@@ -40,7 +40,7 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'content-type': 'application/strategic-merge-patch+json'
|
||||
"content-type": "application/strategic-merge-patch+json"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export const metricsApi = {
|
||||
|
||||
if (!start && !end) {
|
||||
const timeNow = Date.now() / 1000;
|
||||
const now = moment.unix(timeNow).startOf('minute').unix(); // round date to minutes
|
||||
const now = moment.unix(timeNow).startOf("minute").unix(); // round date to minutes
|
||||
start = now - range;
|
||||
end = now;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import { KubeApi } from "../kube-api";
|
||||
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
||||
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
|
||||
return metricsApi.getMetrics({
|
||||
diskUsage: { category: 'pvc', pvc: pvcName },
|
||||
diskCapacity: { category: 'pvc', pvc: pvcName }
|
||||
diskUsage: { category: "pvc", pvc: pvcName },
|
||||
diskCapacity: { category: "pvc", pvc: pvcName }
|
||||
}, {
|
||||
namespace
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface JsonApiConfig {
|
||||
export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
static reqInitDefault: RequestInit = {
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
"content-type": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -132,9 +132,9 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
||||
protected writeLog(log: JsonApiLog) {
|
||||
if (!this.config.debug) return;
|
||||
const { method, reqUrl, ...params } = log;
|
||||
let textStyle = 'font-weight: bold;';
|
||||
if (params.data) textStyle += 'background: green; color: white;';
|
||||
if (params.error) textStyle += 'background: red; color: white;';
|
||||
let textStyle = "font-weight: bold;";
|
||||
if (params.data) textStyle += "background: green; color: white;";
|
||||
if (params.error) textStyle += "background: red; color: white;";
|
||||
console.log(`%c${method} ${reqUrl}`, textStyle, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export function parseKubeApi(path: string): IKubeApiParsed {
|
||||
* 3. otherwise assume apiVersion <- left[0]
|
||||
* 4. always resource, name <- left[(0 or 1)+1..]
|
||||
*/
|
||||
if (left[0].includes('.') || left[1].match(/^v[0-9]/)) {
|
||||
if (left[0].includes(".") || left[1].match(/^v[0-9]/)) {
|
||||
[apiGroup, apiVersion] = left;
|
||||
resource = left.slice(2).join("/");
|
||||
} else {
|
||||
|
||||
@@ -142,7 +142,7 @@ export class KubeWatchApi {
|
||||
|
||||
protected writeLog(...data: any[]) {
|
||||
if (isDevelopment) {
|
||||
console.log('%cKUBE-WATCH-API:', `font-weight: bold`, ...data);
|
||||
console.log("%cKUBE-WATCH-API:", `font-weight: bold`, ...data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ export class TerminalApi extends WebSocketApi {
|
||||
}
|
||||
|
||||
reconnect() {
|
||||
const { reconnectDelaySeconds } = this.params;
|
||||
super.reconnect();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ export class WebSocketApi {
|
||||
reconnect() {
|
||||
const { reconnectDelaySeconds } = this.params;
|
||||
if (!reconnectDelaySeconds) return;
|
||||
this.writeLog('reconnect after', reconnectDelaySeconds + "ms");
|
||||
this.writeLog("reconnect after", reconnectDelaySeconds + "ms");
|
||||
this.reconnectTimer = setTimeout(() => this.connect(), reconnectDelaySeconds * 1000);
|
||||
this.readyState = WebSocketApiState.RECONNECTING;
|
||||
}
|
||||
@@ -136,17 +136,17 @@ export class WebSocketApi {
|
||||
this.onOpen.emit();
|
||||
if (this.params.flushOnOpen) this.flush();
|
||||
this.readyState = WebSocketApiState.OPEN;
|
||||
this.writeLog('%cOPEN', 'color:green;font-weight:bold;', evt);
|
||||
this.writeLog("%cOPEN", "color:green;font-weight:bold;", evt);
|
||||
}
|
||||
|
||||
protected _onMessage(evt: MessageEvent) {
|
||||
const data = this.parseMessage(evt.data);
|
||||
this.onData.emit(data);
|
||||
this.writeLog('%cMESSAGE', 'color:black;font-weight:bold;', data);
|
||||
this.writeLog("%cMESSAGE", "color:black;font-weight:bold;", data);
|
||||
}
|
||||
|
||||
protected _onError(evt: Event) {
|
||||
this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt);
|
||||
this.writeLog("%cERROR", "color:red;font-weight:bold;", evt);
|
||||
}
|
||||
|
||||
protected _onClose(evt: CloseEvent) {
|
||||
@@ -158,7 +158,7 @@ export class WebSocketApi {
|
||||
this.readyState = WebSocketApiState.CLOSED;
|
||||
this.onClose.emit();
|
||||
}
|
||||
this.writeLog('%cCLOSE', `color:${error ? "red" : "black"};font-weight:bold;`, evt);
|
||||
this.writeLog("%cCLOSE", `color:${error ? "red" : "black"};font-weight:bold;`, evt);
|
||||
}
|
||||
|
||||
protected writeLog(...data: any[]) {
|
||||
|
||||
@@ -66,7 +66,7 @@ export class AddCluster extends React.Component {
|
||||
userStore.kubeConfigPath = filePath; // save to store
|
||||
} catch (err) {
|
||||
Notifications.error(
|
||||
<div>Can't setup <code>{filePath}</code> as kubeconfig: {String(err)}</div>
|
||||
<div>Can't setup <code>{filePath}</code> as kubeconfig: {String(err)}</div>
|
||||
);
|
||||
if (throwError) {
|
||||
throw err;
|
||||
@@ -196,9 +196,9 @@ export class AddCluster extends React.Component {
|
||||
return (
|
||||
<p>
|
||||
Add clusters by clicking the <span className="text-primary">Add Cluster</span> button.
|
||||
You'll need to obtain a working kubeconfig for the cluster you want to add.
|
||||
You'll need to obtain a working kubeconfig for the cluster you want to add.
|
||||
You can either browse it from the file system or paste it as a text from the clipboard.
|
||||
Read more about adding clusters <a href={`${docsUrl}/latest/clusters/adding-clusters/`} target="_blank">here</a>.
|
||||
Read more about adding clusters <a href={`${docsUrl}/latest/clusters/adding-clusters/`} rel="noreferrer" target="_blank">here</a>.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -300,7 +300,7 @@ export class AddCluster extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
onKubeConfigInputBlur = (evt: React.FocusEvent<HTMLInputElement>) => {
|
||||
onKubeConfigInputBlur = () => {
|
||||
const isChanged = this.kubeConfigPath !== userStore.kubeConfigPath;
|
||||
if (isChanged) {
|
||||
this.kubeConfigPath = this.kubeConfigPath.replace("~", os.homedir());
|
||||
@@ -354,7 +354,7 @@ export class AddCluster extends React.Component {
|
||||
theme="round-black"
|
||||
/>
|
||||
<small className="hint">
|
||||
{'A HTTP proxy server URL (format: http://<address>:<port>).'}
|
||||
{"A HTTP proxy server URL (format: http://<address>:<port>)."}
|
||||
</small>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -93,11 +93,11 @@ export class HelmChartDetails extends Component<Props> {
|
||||
/>
|
||||
</DrawerItem>
|
||||
<DrawerItem name={_i18n._(t`Home`)}>
|
||||
<a href={selectedChart.getHome()} target="_blank">{selectedChart.getHome()}</a>
|
||||
<a href={selectedChart.getHome()} target="_blank" rel="noreferrer">{selectedChart.getHome()}</a>
|
||||
</DrawerItem>
|
||||
<DrawerItem name={_i18n._(t`Maintainers`)} className="maintainers">
|
||||
{selectedChart.getMaintainers().map(({ name, email, url }) =>
|
||||
<a key={name} href={url || `mailto:${email}`} target="_blank">{name}</a>
|
||||
<a key={name} href={url || `mailto:${email}`} target="_blank" rel="noreferrer">{name}</a>
|
||||
)}
|
||||
</DrawerItem>
|
||||
{selectedChart.getKeywords().length > 0 && (
|
||||
|
||||
@@ -84,7 +84,7 @@ export class HelmCharts extends Component<Props> {
|
||||
|
||||
]}
|
||||
renderTableContents={(chart: HelmChart) => [
|
||||
<figure>
|
||||
<figure key="image">
|
||||
<img
|
||||
src={chart.getIcon() || require("./helm-placeholder.svg")}
|
||||
onLoad={evt => evt.currentTarget.classList.add("visible")}
|
||||
|
||||
@@ -56,8 +56,9 @@ export class HelmReleaseMenu extends React.Component<Props> {
|
||||
{...menuProps}
|
||||
className={cssNames("HelmReleaseMenu", className)}
|
||||
removeAction={this.remove}
|
||||
children={this.renderContent()}
|
||||
/>
|
||||
>
|
||||
{this.renderContent()}
|
||||
</MenuActions>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export class HelmReleases extends Component<Props> {
|
||||
<div>
|
||||
<Trans>Remove <b>{releaseNames}</b>?</Trans>
|
||||
<p className="warning">
|
||||
<Trans>Note: StatefulSet Volumes won't be deleted automatically</Trans>
|
||||
<Trans>Note: StatefulSet Volumes won't be deleted automatically</Trans>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -146,4 +146,4 @@ export class HelmReleases extends Component<Props> {
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ export class ClusterAccessibleNamespaces extends React.Component<Props> {
|
||||
return (
|
||||
<>
|
||||
<SubTitle title="Accessible Namespaces" />
|
||||
<p><Trans>This setting is useful for manually specifying which namespaces you have access to. This is useful when you don't have permissions to list namespaces.</Trans></p>
|
||||
<p><Trans>This setting is useful for manually specifying which namespaces you have access to. This is useful when you don't have permissions to list namespaces.</Trans></p>
|
||||
<EditableList
|
||||
placeholder={_i18n._("Add new namespace...")}
|
||||
add={(newNamespace) => {
|
||||
|
||||
@@ -28,7 +28,7 @@ export class ClusterIconSetting extends React.Component<Props> {
|
||||
try {
|
||||
if (file) {
|
||||
const buf = Buffer.from(await file.arrayBuffer());
|
||||
cluster.preferences.icon = `data:${file.type};base64,${buf.toString('base64')}`;
|
||||
cluster.preferences.icon = `data:${file.type};base64,${buf.toString("base64")}`;
|
||||
} else {
|
||||
// this has to be done as a seperate branch (and not always) because `cluster`
|
||||
// is observable and triggers an update loop.
|
||||
|
||||
@@ -78,7 +78,7 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
|
||||
<SubTitle title="Prometheus"/>
|
||||
<p>
|
||||
Use pre-installed Prometheus service for metrics. Please refer to the{" "}
|
||||
<a href="https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md" target="_blank">guide</a>{" "}
|
||||
<a href="https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md" target="_blank" rel="noreferrer">guide</a>{" "}
|
||||
for possible configuration changes.
|
||||
</p>
|
||||
<p>Prometheus installation method.</p>
|
||||
@@ -103,11 +103,11 @@ export class ClusterPrometheusSetting extends React.Component<Props> {
|
||||
/>
|
||||
<small className="hint">
|
||||
An address to an existing Prometheus installation{" "}
|
||||
({'<namespace>/<service>:<port>'}). Lens tries to auto-detect address if left empty.
|
||||
({"<namespace>/<service>:<port>"}). Lens tries to auto-detect address if left empty.
|
||||
</small>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,18 @@ export class Features extends React.Component<Props> {
|
||||
return (
|
||||
<div>
|
||||
<h2>Features</h2>
|
||||
{ clusterFeatureRegistry.getItems().map((f) => {
|
||||
return (
|
||||
<InstallFeature cluster={cluster} feature={f.feature}>
|
||||
<>
|
||||
<SubTitle title={f.title}/>
|
||||
<p><f.components.Description /></p>
|
||||
</>
|
||||
</InstallFeature>
|
||||
);
|
||||
})}
|
||||
{
|
||||
clusterFeatureRegistry
|
||||
.getItems()
|
||||
.map((f) => (
|
||||
<InstallFeature key={f.title} cluster={cluster} feature={f.feature}>
|
||||
<>
|
||||
<SubTitle title={f.title} />
|
||||
<p><f.components.Description /></p>
|
||||
</>
|
||||
</InstallFeature>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export class HorizontalPodAutoscalers extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(hpa: HorizontalPodAutoscaler) => [
|
||||
hpa.getName(),
|
||||
<KubeObjectStatusIcon object={hpa} />,
|
||||
<KubeObjectStatusIcon key="icon" object={hpa} />,
|
||||
hpa.getNs(),
|
||||
this.getTargets(hpa),
|
||||
hpa.getMinPods(),
|
||||
@@ -85,4 +85,3 @@ export class HorizontalPodAutoscalers extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,9 @@ import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { configMapsStore } from "./config-maps.store";
|
||||
import { ConfigMap, configMapApi } from "../../api/endpoints/configmap.api";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { ConfigMap } from "../../api/endpoints/configmap.api";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { IConfigMapsRouteParams } from "./config-maps.route";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -48,7 +46,7 @@ export class ConfigMaps extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(configMap: ConfigMap) => [
|
||||
configMap.getName(),
|
||||
<KubeObjectStatusIcon object={configMap}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={configMap}/>,
|
||||
configMap.getNs(),
|
||||
configMap.getKeys().join(", "),
|
||||
configMap.getAge(),
|
||||
@@ -57,4 +55,3 @@ export class ConfigMaps extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-6
@@ -19,18 +19,17 @@ export class PodDisruptionBudgetDetails extends React.Component<Props> {
|
||||
render() {
|
||||
const { object: pdb } = this.props;
|
||||
if (!pdb) return null;
|
||||
const { status, spec } = pdb;
|
||||
const selectors = pdb.getSelectors();
|
||||
return (
|
||||
<div className="PdbDetails">
|
||||
<KubeObjectMeta object={pdb}/>
|
||||
|
||||
{selectors.length > 0 &&
|
||||
<DrawerItem name={<Trans>Selector</Trans>} labelsOnly>
|
||||
{
|
||||
selectors.map(label => <Badge key={label} label={label}/>)
|
||||
}
|
||||
</DrawerItem>
|
||||
<DrawerItem name={<Trans>Selector</Trans>} labelsOnly>
|
||||
{
|
||||
selectors.map(label => <Badge key={label} label={label}/>)
|
||||
}
|
||||
</DrawerItem>
|
||||
}
|
||||
|
||||
<DrawerItem name={<Trans>Min Available</Trans>}>
|
||||
|
||||
@@ -3,13 +3,9 @@ import "./pod-disruption-budgets.scss";
|
||||
import * as React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { podDisruptionBudgetsStore } from "./pod-disruption-budgets.store";
|
||||
import { PodDisruptionBudget, pdbApi } from "../../api/endpoints/poddisruptionbudget.api";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api";
|
||||
import { KubeObjectDetailsProps, KubeObjectListLayout } from "../kube-object";
|
||||
import { IPodDisruptionBudgetsRouteParams } from "./pod-disruption-budgets.route";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -58,7 +54,7 @@ export class PodDisruptionBudgets extends React.Component<Props> {
|
||||
renderTableContents={(pdb: PodDisruptionBudget) => {
|
||||
return [
|
||||
pdb.getName(),
|
||||
<KubeObjectStatusIcon object={pdb} />,
|
||||
<KubeObjectStatusIcon key="icon" object={pdb} />,
|
||||
pdb.getNs(),
|
||||
pdb.getMinAvailable(),
|
||||
pdb.getMaxUnavailable(),
|
||||
|
||||
@@ -63,7 +63,7 @@ export class AddQuotaDialog extends React.Component<Props> {
|
||||
|
||||
@computed get quotaEntries() {
|
||||
return Object.entries(this.quotas)
|
||||
.filter(([type, value]) => !!value.trim());
|
||||
.filter(([, value]) => !!value.trim());
|
||||
}
|
||||
|
||||
@computed get quotaOptions() {
|
||||
@@ -201,4 +201,4 @@ export class AddQuotaDialog extends React.Component<Props> {
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@ import { ReplicaSetDetails } from "../+workloads-replicasets";
|
||||
interface Props extends KubeObjectDetailsProps<ResourceQuota> {
|
||||
}
|
||||
|
||||
const onlyNumbers = /$[0-9]*^/g;
|
||||
|
||||
function transformUnit(name: string, value: string): number {
|
||||
if (name.includes("memory") || name.includes("storage")) {
|
||||
return unitsToBytes(value);
|
||||
|
||||
@@ -4,13 +4,11 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api";
|
||||
import { ResourceQuota } from "../../api/endpoints/resource-quota.api";
|
||||
import { AddQuotaDialog } from "./add-quota-dialog";
|
||||
import { resourceQuotaStore } from "./resource-quotas.store";
|
||||
import { IResourceQuotaRouteParams } from "./resource-quotas.route";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -47,7 +45,7 @@ export class ResourceQuotas extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(resourceQuota: ResourceQuota) => [
|
||||
resourceQuota.getName(),
|
||||
<KubeObjectStatusIcon object={resourceQuota}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={resourceQuota}/>,
|
||||
resourceQuota.getNs(),
|
||||
resourceQuota.getAge(),
|
||||
]}
|
||||
|
||||
@@ -4,14 +4,12 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { Secret, secretsApi } from "../../api/endpoints";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { Secret } from "../../api/endpoints";
|
||||
import { AddSecretDialog } from "./add-secret-dialog";
|
||||
import { ISecretsRouteParams } from "./secrets.route";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { Badge } from "../badge";
|
||||
import { secretsStore } from "./secrets.store";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -57,7 +55,7 @@ export class Secrets extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(secret: Secret) => [
|
||||
secret.getName(),
|
||||
<KubeObjectStatusIcon object={secret} />,
|
||||
<KubeObjectStatusIcon key="icon" object={secret} />,
|
||||
secret.getNs(),
|
||||
secret.getLabels().map(label => <Badge key={label} label={label}/>),
|
||||
secret.getKeys().join(", "),
|
||||
|
||||
@@ -4,8 +4,7 @@ import React from "react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { Link } from "react-router-dom";
|
||||
import { observer } from "mobx-react";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api";
|
||||
import { CustomResourceDefinition } from "../../api/endpoints/crd.api";
|
||||
import { cssNames } from "../../utils";
|
||||
import { AceEditor } from "../ace-editor";
|
||||
import { Badge } from "../badge";
|
||||
|
||||
@@ -90,19 +90,16 @@ export class CrdList extends React.Component {
|
||||
{ title: <Trans>Scope</Trans>, className: "scope", sortBy: sortBy.scope },
|
||||
{ title: <Trans>Age</Trans>, className: "age", sortBy: sortBy.age },
|
||||
]}
|
||||
renderTableContents={(crd: CustomResourceDefinition) => {
|
||||
return [
|
||||
<Link to={crd.getResourceUrl()} onClick={stopPropagation}>
|
||||
{crd.getResourceTitle()}
|
||||
</Link>,
|
||||
crd.getGroup(),
|
||||
crd.getVersion(),
|
||||
crd.getScope(),
|
||||
crd.getAge(),
|
||||
];
|
||||
}}
|
||||
renderTableContents={(crd: CustomResourceDefinition) => [
|
||||
<Link key="link" to={crd.getResourceUrl()} onClick={stopPropagation}>
|
||||
{crd.getResourceTitle()}
|
||||
</Link>,
|
||||
crd.getGroup(),
|
||||
crd.getVersion(),
|
||||
crd.getScope(),
|
||||
crd.getAge(),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export class Events extends React.Component<Props> {
|
||||
},
|
||||
event.getNs(),
|
||||
kind,
|
||||
<Link to={detailsUrl} title={name} onClick={stopPropagation}>{name}</Link>,
|
||||
<Link key="link" to={detailsUrl} title={name} onClick={stopPropagation}>{name}</Link>,
|
||||
event.getSource(),
|
||||
event.count,
|
||||
event.getAge(),
|
||||
|
||||
@@ -157,7 +157,7 @@ export class Extensions extends React.Component {
|
||||
};
|
||||
|
||||
installOnDrop = (files: File[]) => {
|
||||
logger.info('Install from D&D');
|
||||
logger.info("Install from D&D");
|
||||
return this.requestInstall(
|
||||
files.map(file => ({
|
||||
fileName: path.basename(file.path),
|
||||
@@ -405,7 +405,7 @@ export class Extensions extends React.Component {
|
||||
The features that Lens includes out-of-the-box are just the start.
|
||||
Lens extensions let you add new features to your installation to support your workflow.
|
||||
Rich extensibility model lets extension authors plug directly into the Lens UI and contribute functionality through the same APIs used by Lens itself.
|
||||
Check out documentation to <a href={`${docsUrl}/latest/extensions/usage/`} target="_blank">learn more</a>.
|
||||
Check out documentation to <a href={`${docsUrl}/latest/extensions/usage/`} target="_blank" rel="noreferrer">learn more</a>.
|
||||
</div>
|
||||
|
||||
<div className="install-extension flex column gaps">
|
||||
@@ -438,7 +438,7 @@ export class Extensions extends React.Component {
|
||||
onClick={this.installFromUrlOrPath}
|
||||
/>
|
||||
<small className="hint">
|
||||
<Trans><b>Pro-Tip</b>: you can drag & drop extension's tarball-file to install</Trans>
|
||||
<Trans><b>Pro-Tip</b>: you can drag & drop extension's tarball-file to install</Trans>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export class Namespaces extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(item: Namespace) => [
|
||||
item.getName(),
|
||||
<KubeObjectStatusIcon object={item} />,
|
||||
<KubeObjectStatusIcon key="icon" object={item} />,
|
||||
item.getLabels().map(label => <Badge key={label} label={label}/>),
|
||||
item.getAge(),
|
||||
{ title: item.getStatus(), className: item.getStatus().toLowerCase() },
|
||||
|
||||
@@ -7,7 +7,6 @@ import { DrawerTitle } from "../drawer";
|
||||
import { KubeEventDetails } from "../+events/kube-event-details";
|
||||
import { KubeObjectDetailsProps } from "../kube-object";
|
||||
import { Endpoint } from "../../api/endpoints";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
|
||||
import { EndpointSubsetList } from "./endpoint-subset-list";
|
||||
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
|
||||
@@ -25,11 +24,9 @@ export class EndpointDetails extends React.Component<Props> {
|
||||
<KubeObjectMeta object={endpoint}/>
|
||||
<DrawerTitle title={<Trans>Subsets</Trans>}/>
|
||||
{
|
||||
endpoint.getEndpointSubsets().map((subset) => {
|
||||
return(
|
||||
<EndpointSubsetList subset={subset} endpoint={endpoint}/>
|
||||
);
|
||||
})
|
||||
endpoint.getEndpointSubsets().map((subset) => (
|
||||
<EndpointSubsetList key={subset.toString()} subset={subset} endpoint={endpoint} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,8 +3,6 @@ import "./endpoint-subset-list.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
||||
import { autobind } from "../../utils";
|
||||
|
||||
@@ -43,7 +43,7 @@ export class Endpoints extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(endpoint: Endpoint) => [
|
||||
endpoint.getName(),
|
||||
<KubeObjectStatusIcon object={endpoint} />,
|
||||
<KubeObjectStatusIcon key="icon" object={endpoint} />,
|
||||
endpoint.getNs(),
|
||||
endpoint.toString(),
|
||||
endpoint.getAge(),
|
||||
|
||||
@@ -100,12 +100,12 @@ export class IngressDetails extends React.Component<Props> {
|
||||
const ingressPoints = status?.loadBalancer?.ingress;
|
||||
const { metrics } = ingressStore;
|
||||
const metricTabs = [
|
||||
<Trans>Network</Trans>,
|
||||
<Trans>Duration</Trans>,
|
||||
<Trans key="network">Network</Trans>,
|
||||
<Trans key="network">Duration</Trans>,
|
||||
];
|
||||
|
||||
const { serviceName, servicePort } = ingress.getServiceNamePort();
|
||||
|
||||
|
||||
return (
|
||||
<div className="IngressDetails">
|
||||
<ResourceMetrics
|
||||
|
||||
@@ -45,7 +45,7 @@ export class Ingresses extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(ingress: Ingress) => [
|
||||
ingress.getName(),
|
||||
<KubeObjectStatusIcon object={ingress} />,
|
||||
<KubeObjectStatusIcon key="icon" object={ingress} />,
|
||||
ingress.getNs(),
|
||||
ingress.getLoadBalancers().map(lb => <p key={lb}>{lb}</p>),
|
||||
ingress.getRoutes().map(route => <p key={route}>{route}</p>),
|
||||
|
||||
@@ -43,7 +43,7 @@ export class NetworkPolicies extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(item: NetworkPolicy) => [
|
||||
item.getName(),
|
||||
<KubeObjectStatusIcon object={item} />,
|
||||
<KubeObjectStatusIcon key="icon" object={item} />,
|
||||
item.getNs(),
|
||||
item.getTypes().join(", "),
|
||||
item.getAge(),
|
||||
|
||||
@@ -61,7 +61,7 @@ export class Services extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(service: Service) => [
|
||||
service.getName(),
|
||||
<KubeObjectStatusIcon object={service} />,
|
||||
<KubeObjectStatusIcon key="icon" object={service} />,
|
||||
service.getNs(),
|
||||
service.getType(),
|
||||
service.getClusterIp(),
|
||||
|
||||
@@ -26,11 +26,9 @@ export const NodeCharts = observer(() => {
|
||||
const [
|
||||
memoryUsage,
|
||||
memoryRequests,
|
||||
memoryLimits,
|
||||
memoryCapacity,
|
||||
cpuUsage,
|
||||
cpuRequests,
|
||||
cpuLimits,
|
||||
cpuCapacity,
|
||||
podUsage,
|
||||
podCapacity,
|
||||
@@ -151,4 +149,4 @@ export const NodeCharts = observer(() => {
|
||||
data={{ datasets: datasets[tabId] }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -49,10 +49,10 @@ export class NodeDetails extends React.Component<Props> {
|
||||
const childPods = podsStore.getPodsByNode(node.getName());
|
||||
const metrics = nodesStore.nodeMetrics;
|
||||
const metricTabs = [
|
||||
<Trans>CPU</Trans>,
|
||||
<Trans>Memory</Trans>,
|
||||
<Trans>Disk</Trans>,
|
||||
<Trans>Pods</Trans>,
|
||||
<Trans key="cpu">CPU</Trans>,
|
||||
<Trans key="memory">Memory</Trans>,
|
||||
<Trans key="disk">Disk</Trans>,
|
||||
<Trans key="pods">Pods</Trans>,
|
||||
];
|
||||
return (
|
||||
<div className="NodeDetails">
|
||||
|
||||
@@ -163,7 +163,7 @@ export class Nodes extends React.Component<Props> {
|
||||
const tooltipId = `node-taints-${node.getId()}`;
|
||||
return [
|
||||
node.getName(),
|
||||
<KubeObjectStatusIcon object={node} />,
|
||||
<KubeObjectStatusIcon key="icon" object={node} />,
|
||||
this.renderCpuUsage(node),
|
||||
this.renderMemoryUsage(node),
|
||||
this.renderDiskUsage(node),
|
||||
|
||||
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { podSecurityPoliciesStore } from "./pod-security-policies.store";
|
||||
import { PodSecurityPolicy, pspApi } from "../../api/endpoints";
|
||||
import { PodSecurityPolicy } from "../../api/endpoints";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -45,7 +45,7 @@ export class PodSecurityPolicies extends React.Component {
|
||||
renderTableContents={(item: PodSecurityPolicy) => {
|
||||
return [
|
||||
item.getName(),
|
||||
<KubeObjectStatusIcon object={item} />,
|
||||
<KubeObjectStatusIcon key="icon" object={item} />,
|
||||
item.isPrivileged() ? <Trans>Yes</Trans> : <Trans>No</Trans>,
|
||||
item.getVolumes().join(", "),
|
||||
item.getAge(),
|
||||
|
||||
@@ -48,9 +48,9 @@ export class PodSecurityPolicyDetails extends React.Component<Props> {
|
||||
}
|
||||
const {
|
||||
allowedHostPaths, allowedCapabilities, allowedCSIDrivers, allowedFlexVolumes, allowedProcMountTypes,
|
||||
allowedUnsafeSysctls, allowPrivilegeEscalation, defaultAddCapabilities, defaultAllowPrivilegeEscalation,
|
||||
forbiddenSysctls, fsGroup, hostIPC, hostNetwork, hostPID, hostPorts, privileged, readOnlyRootFilesystem,
|
||||
requiredDropCapabilities, runAsGroup, runAsUser, runtimeClass, seLinux, supplementalGroups, volumes
|
||||
allowedUnsafeSysctls, allowPrivilegeEscalation, defaultAddCapabilities, forbiddenSysctls, fsGroup,
|
||||
hostIPC, hostNetwork, hostPID, hostPorts, privileged, readOnlyRootFilesystem, requiredDropCapabilities,
|
||||
runAsGroup, runAsUser, runtimeClass, seLinux, supplementalGroups, volumes,
|
||||
} = psp.spec;
|
||||
return (
|
||||
<div className="PodSecurityPolicyDetails">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { Checkbox } from '../checkbox';
|
||||
import { Input, InputValidators } from '../input';
|
||||
import { SubTitle } from '../layout/sub-title';
|
||||
import { UserPreferences, userStore } from '../../../common/user-store';
|
||||
import { observer } from 'mobx-react';
|
||||
import { bundledKubectlPath } from '../../../main/kubectl';
|
||||
import { SelectOption, Select } from '../select';
|
||||
import React, { useState } from "react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { Checkbox } from "../checkbox";
|
||||
import { Input, InputValidators } from "../input";
|
||||
import { SubTitle } from "../layout/sub-title";
|
||||
import { UserPreferences, userStore } from "../../../common/user-store";
|
||||
import { observer } from "mobx-react";
|
||||
import { bundledKubectlPath } from "../../../main/kubectl";
|
||||
import { SelectOption, Select } from "../select";
|
||||
|
||||
export const KubectlBinaries = observer(({ preferences }: { preferences: UserPreferences }) => {
|
||||
const [downloadPath, setDownloadPath] = useState(preferences.downloadBinariesPath || "");
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from "react";
|
||||
import { RouteComponentProps } from "react-router-dom";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { StorageClass, storageClassApi } from "../../api/endpoints/storage-class.api";
|
||||
import { StorageClass } from "../../api/endpoints/storage-class.api";
|
||||
import { KubeObjectListLayout } from "../kube-object";
|
||||
import { IStorageClassesRouteParams } from "./storage-classes.route";
|
||||
import { storageClassStore } from "./storage-class.store";
|
||||
@@ -48,7 +48,7 @@ export class StorageClasses extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(storageClass: StorageClass) => [
|
||||
storageClass.getName(),
|
||||
<KubeObjectStatusIcon object={storageClass} />,
|
||||
<KubeObjectStatusIcon key="icon" object={storageClass} />,
|
||||
storageClass.provisioner,
|
||||
storageClass.getReclaimPolicy(),
|
||||
storageClass.isDefault() ? <Trans>Yes</Trans> : null,
|
||||
|
||||
@@ -42,7 +42,7 @@ export class PersistentVolumeClaimDetails extends React.Component<Props> {
|
||||
const { metrics } = volumeClaimStore;
|
||||
const pods = volumeClaim.getPods(podsStore.items);
|
||||
const metricTabs = [
|
||||
<Trans>Disk</Trans>
|
||||
<Trans key="disk">Disk</Trans>
|
||||
];
|
||||
return (
|
||||
<div className="PersistentVolumeClaimDetails">
|
||||
|
||||
@@ -68,9 +68,9 @@ export class PersistentVolumeClaims extends React.Component<Props> {
|
||||
}));
|
||||
return [
|
||||
pvc.getName(),
|
||||
<KubeObjectStatusIcon object={pvc} />,
|
||||
<KubeObjectStatusIcon key="icon" object={pvc} />,
|
||||
pvc.getNs(),
|
||||
<Link to={storageClassDetailsUrl} onClick={stopPropagation}>
|
||||
<Link key="link" to={storageClassDetailsUrl} onClick={stopPropagation}>
|
||||
{storageClassName}
|
||||
</Link>,
|
||||
pvc.getStorage(),
|
||||
|
||||
@@ -59,8 +59,8 @@ export class PersistentVolumes extends React.Component<Props> {
|
||||
}));
|
||||
return [
|
||||
volume.getName(),
|
||||
<KubeObjectStatusIcon object={volume} />,
|
||||
<Link to={storageClassDetailsUrl} onClick={stopPropagation}>
|
||||
<KubeObjectStatusIcon key="icon" object={volume} />,
|
||||
<Link key="link" to={storageClassDetailsUrl} onClick={stopPropagation}>
|
||||
{storageClassName}
|
||||
</Link>,
|
||||
volume.getCapacity(),
|
||||
|
||||
@@ -23,7 +23,7 @@ export class Storage extends React.Component {
|
||||
routePath: volumeClaimsRoute.path.toString(),
|
||||
});
|
||||
|
||||
if (isAllowedResource('persistentvolumes')) {
|
||||
if (isAllowedResource("persistentvolumes")) {
|
||||
tabRoutes.push({
|
||||
title: <Trans>Persistent Volumes</Trans>,
|
||||
component: PersistentVolumes,
|
||||
@@ -32,7 +32,7 @@ export class Storage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
if (isAllowedResource('storageclasses')) {
|
||||
if (isAllowedResource("storageclasses")) {
|
||||
tabRoutes.push({
|
||||
title: <Trans>Storage Classes</Trans>,
|
||||
component: StorageClasses,
|
||||
|
||||
@@ -27,7 +27,7 @@ export class RoleBindingDetails extends React.Component<Props> {
|
||||
|
||||
async componentDidMount() {
|
||||
disposeOnUnmount(this, [
|
||||
reaction(() => this.props.object, (obj) => {
|
||||
reaction(() => this.props.object, () => {
|
||||
this.selectedSubjects.clear();
|
||||
})
|
||||
]);
|
||||
|
||||
@@ -48,7 +48,7 @@ export class RoleBindings extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(binding: RoleBinding) => [
|
||||
binding.getName(),
|
||||
<KubeObjectStatusIcon object={binding} />,
|
||||
<KubeObjectStatusIcon key="icon" object={binding} />,
|
||||
binding.getSubjectNames(),
|
||||
binding.getNs() || "-",
|
||||
binding.getAge(),
|
||||
|
||||
@@ -45,7 +45,7 @@ export class Roles extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(role: Role) => [
|
||||
role.getName(),
|
||||
<KubeObjectStatusIcon object={role} />,
|
||||
<KubeObjectStatusIcon key="icon" object={role} />,
|
||||
role.getNs() || "-",
|
||||
role.getAge(),
|
||||
]}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ export class ServiceAccountsDetails extends React.Component<Props> {
|
||||
});
|
||||
this.secrets = await Promise.all(secrets);
|
||||
const imagePullSecrets = serviceAccount.getImagePullSecrets().map(async({ name }) => {
|
||||
return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name); });
|
||||
return secretsStore.load({ name, namespace }).catch(() => this.generateDummySecretObject(name));
|
||||
});
|
||||
this.imagePullSecrets = await Promise.all(imagePullSecrets);
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ export class ServiceAccounts extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(account: ServiceAccount) => [
|
||||
account.getName(),
|
||||
<KubeObjectStatusIcon object={account} />,
|
||||
<KubeObjectStatusIcon key="icon" object={account} />,
|
||||
account.getNs(),
|
||||
account.getAge(),
|
||||
]}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { Dialog, DialogProps } from "../dialog";
|
||||
import { Wizard, WizardStep } from "../wizard";
|
||||
import { CronJob, cronJobApi, jobApi, Job } from "../../api/endpoints";
|
||||
import { CronJob, cronJobApi, jobApi } from "../../api/endpoints";
|
||||
import { Notifications } from "../notifications";
|
||||
import { cssNames } from "../../utils";
|
||||
import { Input } from "../input";
|
||||
|
||||
@@ -62,7 +62,7 @@ export class CronJobs extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(cronJob: CronJob) => [
|
||||
cronJob.getName(),
|
||||
<KubeObjectStatusIcon object={cronJob} />,
|
||||
<KubeObjectStatusIcon key="icon" object={cronJob} />,
|
||||
cronJob.getNs(),
|
||||
cronJob.isNeverRun() ? <Trans>never</Trans> : cronJob.getSchedule(),
|
||||
cronJob.getSuspendFlag(),
|
||||
|
||||
@@ -64,7 +64,7 @@ export class DaemonSets extends React.Component<Props> {
|
||||
daemonSet.getName(),
|
||||
daemonSet.getNs(),
|
||||
this.getPodsLength(daemonSet),
|
||||
<KubeObjectStatusIcon object={daemonSet}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={daemonSet}/>,
|
||||
this.renderNodeSelector(daemonSet),
|
||||
daemonSet.getAge(),
|
||||
]}
|
||||
@@ -72,4 +72,3 @@ export class DaemonSets extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { DrawerItem } from "../drawer";
|
||||
import { Badge } from "../badge";
|
||||
import { Deployment, deploymentApi } from "../../api/endpoints";
|
||||
import { Deployment } from "../../api/endpoints";
|
||||
import { cssNames } from "../../utils";
|
||||
import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations";
|
||||
import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities";
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import React from 'react';
|
||||
import { render, waitFor, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import React from "react";
|
||||
import { render, waitFor, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
|
||||
import { DeploymentScaleDialog } from "./deployment-scale-dialog";
|
||||
jest.mock("../../api/endpoints");
|
||||
import { deploymentApi } from "../../api/endpoints";
|
||||
|
||||
const dummyDeployment = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'dummy',
|
||||
apiVersion: "v1",
|
||||
kind: "dummy",
|
||||
metadata: {
|
||||
uid: 'dummy',
|
||||
name: 'dummy',
|
||||
creationTimestamp: 'dummy',
|
||||
resourceVersion: 'dummy',
|
||||
selfLink: 'link',
|
||||
uid: "dummy",
|
||||
name: "dummy",
|
||||
creationTimestamp: "dummy",
|
||||
resourceVersion: "dummy",
|
||||
selfLink: "link",
|
||||
},
|
||||
selfLink: 'link',
|
||||
selfLink: "link",
|
||||
spec: {
|
||||
replicas: 1,
|
||||
selector: { matchLabels: { dummy: 'label' } },
|
||||
selector: { matchLabels: { dummy: "label" } },
|
||||
template: {
|
||||
metadata: {
|
||||
labels: { dummy: 'label' },
|
||||
labels: { dummy: "label" },
|
||||
},
|
||||
spec: {
|
||||
containers: [{
|
||||
name: 'dummy',
|
||||
image: 'dummy',
|
||||
name: "dummy",
|
||||
image: "dummy",
|
||||
resources: {
|
||||
requests: {
|
||||
cpu: '1',
|
||||
memory: '10Mi',
|
||||
cpu: "1",
|
||||
memory: "10Mi",
|
||||
},
|
||||
},
|
||||
terminationMessagePath: 'dummy',
|
||||
terminationMessagePolicy: 'dummy',
|
||||
imagePullPolicy: 'dummy',
|
||||
terminationMessagePath: "dummy",
|
||||
terminationMessagePolicy: "dummy",
|
||||
imagePullPolicy: "dummy",
|
||||
}],
|
||||
restartPolicy: 'dummy',
|
||||
restartPolicy: "dummy",
|
||||
terminationGracePeriodSeconds: 10,
|
||||
dnsPolicy: 'dummy',
|
||||
serviceAccountName: 'dummy',
|
||||
serviceAccount: 'dummy',
|
||||
dnsPolicy: "dummy",
|
||||
serviceAccountName: "dummy",
|
||||
serviceAccount: "dummy",
|
||||
securityContext: {},
|
||||
schedulerName: 'dummy',
|
||||
schedulerName: "dummy",
|
||||
},
|
||||
},
|
||||
strategy: {
|
||||
type: 'dummy',
|
||||
type: "dummy",
|
||||
rollingUpdate: {
|
||||
maxUnavailable: 1,
|
||||
maxSurge: 10,
|
||||
@@ -61,12 +61,12 @@ const dummyDeployment = {
|
||||
updatedReplicas: 1,
|
||||
readyReplicas: 1,
|
||||
conditions: [{
|
||||
type: 'dummy',
|
||||
status: 'dummy',
|
||||
lastUpdateTime: 'dummy',
|
||||
lastTransitionTime: 'dummy',
|
||||
reason: 'dummy',
|
||||
message: 'dummy',
|
||||
type: "dummy",
|
||||
status: "dummy",
|
||||
lastUpdateTime: "dummy",
|
||||
lastTransitionTime: "dummy",
|
||||
reason: "dummy",
|
||||
message: "dummy",
|
||||
}],
|
||||
},
|
||||
getConditions: jest.fn(),
|
||||
@@ -93,14 +93,14 @@ const dummyDeployment = {
|
||||
delete: jest.fn(),
|
||||
};
|
||||
|
||||
describe('<DeploymentScaleDialog />', () => {
|
||||
describe("<DeploymentScaleDialog />", () => {
|
||||
|
||||
it('renders w/o errors', () => {
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<DeploymentScaleDialog />);
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it('inits with a dummy deployment with mocked current/desired scale', async () => {
|
||||
it("inits with a dummy deployment with mocked current/desired scale", async () => {
|
||||
// mock deploymentApi.getReplicas() which will be called
|
||||
// when <DeploymentScaleDialog /> rendered.
|
||||
const initReplicas = 3;
|
||||
@@ -111,8 +111,8 @@ describe('<DeploymentScaleDialog />', () => {
|
||||
// because there is an <Animate /> in <Dialog /> which renders null at start.
|
||||
await waitFor(async () => {
|
||||
const [currentScale, desiredScale] = await Promise.all([
|
||||
getByTestId('current-scale'),
|
||||
getByTestId('desired-scale'),
|
||||
getByTestId("current-scale"),
|
||||
getByTestId("desired-scale"),
|
||||
]);
|
||||
expect(currentScale).toHaveTextContent(`${initReplicas}`);
|
||||
expect(desiredScale).toHaveTextContent(`${initReplicas}`);
|
||||
@@ -120,31 +120,31 @@ describe('<DeploymentScaleDialog />', () => {
|
||||
|
||||
});
|
||||
|
||||
it('changes the desired scale when clicking the icon buttons +/-', async () => {
|
||||
it("changes the desired scale when clicking the icon buttons +/-", async () => {
|
||||
const initReplicas = 1;
|
||||
deploymentApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas);
|
||||
const { getByTestId } = render(<DeploymentScaleDialog />);
|
||||
DeploymentScaleDialog.open(dummyDeployment);
|
||||
await waitFor(async () => {
|
||||
const desiredScale = await getByTestId('desired-scale');
|
||||
const desiredScale = await getByTestId("desired-scale");
|
||||
expect(desiredScale).toHaveTextContent(`${initReplicas}`);
|
||||
});
|
||||
const up = await getByTestId('desired-replicas-up');
|
||||
const down = await getByTestId('desired-replicas-down');
|
||||
const up = await getByTestId("desired-replicas-up");
|
||||
const down = await getByTestId("desired-replicas-down");
|
||||
fireEvent.click(up);
|
||||
expect(await getByTestId('desired-scale')).toHaveTextContent(`${initReplicas + 1}`);
|
||||
expect(await getByTestId("desired-scale")).toHaveTextContent(`${initReplicas + 1}`);
|
||||
fireEvent.click(down);
|
||||
expect(await getByTestId('desired-scale')).toHaveTextContent('1');
|
||||
expect(await getByTestId("desired-scale")).toHaveTextContent("1");
|
||||
// edge case, desiredScale must > 0
|
||||
fireEvent.click(down);
|
||||
fireEvent.click(down);
|
||||
expect(await getByTestId('desired-scale')).toHaveTextContent('1');
|
||||
expect(await getByTestId("desired-scale")).toHaveTextContent("1");
|
||||
const times = 120;
|
||||
// edge case, desiredScale must < scaleMax (100)
|
||||
for (let i = 0; i < times; i++) {
|
||||
fireEvent.click(up);
|
||||
}
|
||||
expect(await getByTestId('desired-scale')).toHaveTextContent('100');
|
||||
expect(await getByTestId("desired-scale")).toHaveTextContent("100");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -80,7 +80,7 @@ export class Deployments extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(deployment: Deployment) => [
|
||||
deployment.getName(),
|
||||
<KubeObjectStatusIcon object={deployment}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={deployment}/>,
|
||||
deployment.getNs(),
|
||||
this.renderPods(deployment),
|
||||
deployment.getReplicas(),
|
||||
|
||||
@@ -54,7 +54,7 @@ export class Jobs extends React.Component<Props> {
|
||||
job.getName(),
|
||||
job.getNs(),
|
||||
`${job.getCompletions()} / ${job.getDesiredCompletions()}`,
|
||||
<KubeObjectStatusIcon object={job}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={job}/>,
|
||||
job.getAge(),
|
||||
condition && {
|
||||
title: condition.type,
|
||||
|
||||
@@ -12,7 +12,6 @@ import { NamespaceSelectFilter } from "../+namespaces/namespace-select";
|
||||
import { isAllowedResource, KubeResource } from "../../../common/rbac";
|
||||
import { ResourceNames } from "../../../renderer/utils/rbac";
|
||||
import { autobind } from "../../utils";
|
||||
import { _i18n } from "../../i18n";
|
||||
|
||||
const resources: KubeResource[] = [
|
||||
"pods",
|
||||
|
||||
@@ -2,14 +2,18 @@ import "./overview-workload-status.scss";
|
||||
|
||||
import React from "react";
|
||||
import capitalize from "lodash/capitalize";
|
||||
import { findDOMNode } from 'react-dom';
|
||||
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 { ChartData, ChartDataSets } from "chart.js";
|
||||
import { themeStore } from "../../theme.store";
|
||||
|
||||
interface SimpleChartDataSets extends ChartDataSets {
|
||||
backgroundColor?: string[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
status: {
|
||||
[key: string]: number;
|
||||
@@ -21,6 +25,7 @@ export class OverviewWorkloadStatus extends React.Component<Props> {
|
||||
@observable elem: HTMLElement;
|
||||
|
||||
componentDidMount() {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
this.elem = findDOMNode(this) as HTMLElement;
|
||||
}
|
||||
|
||||
@@ -40,8 +45,8 @@ export class OverviewWorkloadStatus extends React.Component<Props> {
|
||||
label: "Empty"
|
||||
}]
|
||||
};
|
||||
if (statuses.some(([key, val]) => val > 0)) {
|
||||
const dataset: any = {
|
||||
if (statuses.some(([, val]) => val > 0)) {
|
||||
const dataset: SimpleChartDataSets = {
|
||||
data: [],
|
||||
backgroundColor: [],
|
||||
label: "Status",
|
||||
|
||||
@@ -11,10 +11,10 @@ import { WorkloadKubeObject } from "../../api/workload-kube-object";
|
||||
import { themeStore } from "../../theme.store";
|
||||
|
||||
export const podMetricTabs = [
|
||||
<Trans>CPU</Trans>,
|
||||
<Trans>Memory</Trans>,
|
||||
<Trans>Network</Trans>,
|
||||
<Trans>Filesystem</Trans>,
|
||||
<Trans key="cpu">CPU</Trans>,
|
||||
<Trans key="memory">Memory</Trans>,
|
||||
<Trans key="network">Network</Trans>,
|
||||
<Trans key="filesystem">Filesystem</Trans>,
|
||||
];
|
||||
|
||||
type IContext = IResourceMetricsValue<WorkloadKubeObject, { metrics: IPodMetrics }>;
|
||||
@@ -128,4 +128,4 @@ export const PodCharts = observer(() => {
|
||||
data={{ datasets: datasets[tabId] }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ export const ContainerEnvironment = observer((props: Props) => {
|
||||
);
|
||||
|
||||
const renderEnv = () => {
|
||||
const orderedEnv = _.sortBy(env, 'name');
|
||||
const orderedEnv = _.sortBy(env, "name");
|
||||
|
||||
return orderedEnv.map(variable => {
|
||||
const { name, value, valueFrom } = variable;
|
||||
|
||||
@@ -3,7 +3,7 @@ import "./pod-container-port.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { t } from "@lingui/macro";
|
||||
import { Pod, IPodContainer } from "../../api/endpoints";
|
||||
import { Pod } from "../../api/endpoints";
|
||||
import { _i18n } from "../../i18n";
|
||||
import { apiBase } from "../../api";
|
||||
import { observable } from "mobx";
|
||||
@@ -39,7 +39,7 @@ export class PodContainerPort extends React.Component<Props> {
|
||||
render() {
|
||||
const { port } = this.props;
|
||||
const { name, containerPort, protocol } = port;
|
||||
const text = (name ? name + ': ' : '')+`${containerPort}/${protocol}`;
|
||||
const text = (name ? name + ": " : "")+`${containerPort}/${protocol}`;
|
||||
return (
|
||||
<div className={cssNames("PodContainerPort", { waiting: this.waiting })}>
|
||||
<span title={_i18n._(t`Open in a browser`)} onClick={() => this.portForward() }>
|
||||
|
||||
@@ -21,27 +21,27 @@ interface Props {
|
||||
}
|
||||
|
||||
export class PodDetailsContainer extends React.Component<Props> {
|
||||
|
||||
|
||||
renderStatus(state: string, status: IPodContainerStatus) {
|
||||
const ready = status ? status.ready : "";
|
||||
return (
|
||||
<span className={cssNames("status", state)}>
|
||||
{state}{ready ? `, ${_i18n._(t`ready`)}` : ""}
|
||||
{state === 'terminated' ? ` - ${status.state.terminated.reason} (${_i18n._(t`exit code`)}: ${status.state.terminated.exitCode})` : ''}
|
||||
</span>
|
||||
{state === "terminated" ? ` - ${status.state.terminated.reason} (${_i18n._(t`exit code`)}: ${status.state.terminated.exitCode})` : ""}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderLastState(lastState: string, status: IPodContainerStatus) {
|
||||
if (lastState === 'terminated') {
|
||||
if (lastState === "terminated") {
|
||||
return (
|
||||
<span>
|
||||
{lastState}<br/>
|
||||
{_i18n._(t`Reason`)}: {status.lastState.terminated.reason} - {_i18n._(t`exit code`)}: {status.lastState.terminated.exitCode}<br/>
|
||||
{_i18n._(t`Started at`)}: {status.lastState.terminated.startedAt}<br/>
|
||||
{_i18n._(t`Finished at`)}: {status.lastState.terminated.finishedAt}<br/>
|
||||
{lastState}<br/>
|
||||
{_i18n._(t`Reason`)}: {status.lastState.terminated.reason} - {_i18n._(t`exit code`)}: {status.lastState.terminated.exitCode}<br/>
|
||||
{_i18n._(t`Started at`)}: {status.lastState.terminated.startedAt}<br/>
|
||||
{_i18n._(t`Finished at`)}: {status.lastState.terminated.finishedAt}<br/>
|
||||
</span>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ export class PodDetailsContainer extends React.Component<Props> {
|
||||
const readiness = pod.getReadinessProbe(container);
|
||||
const isInitContainer = !!pod.getInitContainers().find(c => c.name == name);
|
||||
const metricTabs = [
|
||||
<Trans>CPU</Trans>,
|
||||
<Trans>Memory</Trans>,
|
||||
<Trans>Filesystem</Trans>,
|
||||
<Trans key="cpu">CPU</Trans>,
|
||||
<Trans key="memory">Memory</Trans>,
|
||||
<Trans key="filesystem">Filesystem</Trans>,
|
||||
];
|
||||
return (
|
||||
<div className="PodDetailsContainer">
|
||||
@@ -110,7 +110,7 @@ export class PodDetailsContainer extends React.Component<Props> {
|
||||
return (
|
||||
<React.Fragment key={name + mountPath}>
|
||||
<span className="mount-path">{mountPath}</span>
|
||||
<span className="mount-from">from {name} ({readOnly ? 'ro' : 'rw'})</span>
|
||||
<span className="mount-from">from {name} ({readOnly ? "ro" : "rw"})</span>
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
@@ -137,16 +137,16 @@ export class PodDetailsContainer extends React.Component<Props> {
|
||||
}
|
||||
{command &&
|
||||
<DrawerItem name={<Trans>Command</Trans>}>
|
||||
{command.join(' ')}
|
||||
{command.join(" ")}
|
||||
</DrawerItem>
|
||||
}
|
||||
|
||||
{args &&
|
||||
<DrawerItem name={<Trans>Arguments</Trans>}>
|
||||
{args.join(' ')}
|
||||
{args.join(" ")}
|
||||
</DrawerItem>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ export class PodDetailsList extends React.Component<Props> {
|
||||
onClick={prevDefault(() => showDetails(pod.selfLink, false))}
|
||||
>
|
||||
<TableCell className="name">{pod.getName()}</TableCell>
|
||||
<TableCell className="warning"><KubeObjectStatusIcon object={pod}/></TableCell>
|
||||
<TableCell className="warning"><KubeObjectStatusIcon key="icon" object={pod}/></TableCell>
|
||||
<TableCell className="namespace">{pod.getNs()}</TableCell>
|
||||
<TableCell className="cpu">{this.renderCpuUsage(`cpu-${pod.getId()}`, metrics.cpu)}</TableCell>
|
||||
<TableCell className="memory">{this.renderMemoryUsage(`memory-${pod.getId()}`, metrics.memory)}</TableCell>
|
||||
|
||||
@@ -102,7 +102,7 @@ export class Pods extends React.Component<Props> {
|
||||
]}
|
||||
renderTableContents={(pod: Pod) => [
|
||||
pod.getName(),
|
||||
<KubeObjectStatusIcon object={pod} />,
|
||||
<KubeObjectStatusIcon key="icon" object={pod} />,
|
||||
pod.getNs(),
|
||||
this.renderContainersStatus(pod),
|
||||
pod.getRestartsCount(),
|
||||
|
||||
@@ -3,7 +3,7 @@ import "./replicasets.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { ReplicaSet, replicaSetApi } from "../../api/endpoints";
|
||||
import { ReplicaSet } from "../../api/endpoints";
|
||||
import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu";
|
||||
import { replicaSetStore } from "./replicasets.store";
|
||||
import { Spinner } from "../spinner";
|
||||
@@ -11,7 +11,6 @@ import { prevDefault, stopPropagation } from "../../utils";
|
||||
import { DrawerTitle } from "../drawer";
|
||||
import { Table, TableCell, TableHead, TableRow } from "../table";
|
||||
import { showDetails } from "../../navigation";
|
||||
import { apiManager } from "../../api/api-manager";
|
||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||
|
||||
enum sortBy {
|
||||
@@ -73,7 +72,7 @@ export class ReplicaSets extends React.Component<Props> {
|
||||
onClick={prevDefault(() => showDetails(replica.selfLink, false))}
|
||||
>
|
||||
<TableCell className="name">{replica.getName()}</TableCell>
|
||||
<TableCell className="warning"><KubeObjectStatusIcon object={replica}/></TableCell>
|
||||
<TableCell className="warning"><KubeObjectStatusIcon key="icon" object={replica}/></TableCell>
|
||||
<TableCell className="namespace">{replica.getNs()}</TableCell>
|
||||
<TableCell className="pods">{this.getPodsLength(replica)}</TableCell>
|
||||
<TableCell className="age">{replica.getAge()}</TableCell>
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
|
||||
jest.mock("../../api/endpoints");
|
||||
import { statefulSetApi } from "../../api/endpoints";
|
||||
import { StatefulSetScaleDialog } from "./statefulset-scale-dialog";
|
||||
import { render, waitFor, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { render, waitFor, fireEvent } from "@testing-library/react";
|
||||
import React from "react";
|
||||
|
||||
const dummyStatefulSet = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'dummy',
|
||||
apiVersion: "v1",
|
||||
kind: "dummy",
|
||||
metadata: {
|
||||
uid: 'dummy',
|
||||
name: 'dummy',
|
||||
creationTimestamp: 'dummy',
|
||||
resourceVersion: 'dummy',
|
||||
selfLink: 'link',
|
||||
uid: "dummy",
|
||||
name: "dummy",
|
||||
creationTimestamp: "dummy",
|
||||
resourceVersion: "dummy",
|
||||
selfLink: "link",
|
||||
},
|
||||
selfLink: 'link',
|
||||
selfLink: "link",
|
||||
|
||||
spec: {
|
||||
serviceName: 'dummy',
|
||||
serviceName: "dummy",
|
||||
replicas: 1,
|
||||
selector: {
|
||||
matchLabels: { 'label': 'label' }
|
||||
matchLabels: { "label": "label" }
|
||||
},
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: 'app',
|
||||
app: "app",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [{
|
||||
name: 'dummy',
|
||||
image: 'dummy',
|
||||
name: "dummy",
|
||||
image: "dummy",
|
||||
ports: [{
|
||||
containerPort: 1234,
|
||||
name: 'dummy',
|
||||
name: "dummy",
|
||||
}],
|
||||
volumeMounts: [{
|
||||
name: 'dummy',
|
||||
mountPath: 'dummy',
|
||||
name: "dummy",
|
||||
mountPath: "dummy",
|
||||
}],
|
||||
}],
|
||||
tolerations: [{
|
||||
key: 'dummy',
|
||||
operator: 'dummy',
|
||||
effect: 'dummy',
|
||||
key: "dummy",
|
||||
operator: "dummy",
|
||||
effect: "dummy",
|
||||
tolerationSeconds: 1,
|
||||
}],
|
||||
},
|
||||
},
|
||||
volumeClaimTemplates: [{
|
||||
metadata: {
|
||||
name: 'dummy',
|
||||
name: "dummy",
|
||||
},
|
||||
spec: {
|
||||
accessModes: ['dummy'],
|
||||
accessModes: ["dummy"],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: 'dummy',
|
||||
storage: "dummy",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -70,8 +70,8 @@ const dummyStatefulSet = {
|
||||
replicas: 1,
|
||||
currentReplicas: 1,
|
||||
readyReplicas: 1,
|
||||
currentRevision: 'dummy',
|
||||
updateRevision: 'dummy',
|
||||
currentRevision: "dummy",
|
||||
updateRevision: "dummy",
|
||||
collisionCount: 1,
|
||||
},
|
||||
|
||||
@@ -98,13 +98,13 @@ const dummyStatefulSet = {
|
||||
delete: jest.fn(),
|
||||
};
|
||||
|
||||
describe('<StatefulSetScaleDialog />', () => {
|
||||
it('renders w/o errors', () => {
|
||||
describe("<StatefulSetScaleDialog />", () => {
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<StatefulSetScaleDialog/>);
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it('init with a dummy stateful set and mocked current/desired scale', async () => {
|
||||
it("init with a dummy stateful set and mocked current/desired scale", async () => {
|
||||
// mock statefulSetApi.getReplicas() which will be called
|
||||
// when <StatefulSetScaleDialog /> rendered.
|
||||
const initReplicas = 1;
|
||||
@@ -115,53 +115,53 @@ describe('<StatefulSetScaleDialog />', () => {
|
||||
// because there is an <Animate /> in <Dialog /> which renders null at start.
|
||||
await waitFor(async () => {
|
||||
const [currentScale, desiredScale] = await Promise.all([
|
||||
getByTestId('current-scale'),
|
||||
getByTestId('desired-scale'),
|
||||
getByTestId("current-scale"),
|
||||
getByTestId("desired-scale"),
|
||||
]);
|
||||
expect(currentScale).toHaveTextContent(`${initReplicas}`);
|
||||
expect(desiredScale).toHaveTextContent(`${initReplicas}`);
|
||||
});
|
||||
});
|
||||
|
||||
it('changes the desired scale when clicking the icon buttons +/-', async () => {
|
||||
it("changes the desired scale when clicking the icon buttons +/-", async () => {
|
||||
const initReplicas = 1;
|
||||
statefulSetApi.getReplicas = jest.fn().mockImplementationOnce(async () => initReplicas);
|
||||
const component = render(<StatefulSetScaleDialog/>);
|
||||
StatefulSetScaleDialog.open(dummyStatefulSet);
|
||||
await waitFor(async () => {
|
||||
expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas}`);
|
||||
expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas}`);
|
||||
expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas}`);
|
||||
expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas}`);
|
||||
});
|
||||
|
||||
const up = await component.findByTestId('desired-replicas-up');
|
||||
const down = await component.findByTestId('desired-replicas-down');
|
||||
const up = await component.findByTestId("desired-replicas-up");
|
||||
const down = await component.findByTestId("desired-replicas-down");
|
||||
fireEvent.click(up);
|
||||
expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas + 1}`);
|
||||
expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas + 1}`);
|
||||
expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas + 1}`);
|
||||
expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas + 1}`);
|
||||
|
||||
fireEvent.click(down);
|
||||
expect(await component.findByTestId('desired-scale')).toHaveTextContent(`${initReplicas}`);
|
||||
expect(await component.findByTestId('current-scale')).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector('input').value)).toBe(`${initReplicas}`);
|
||||
expect(await component.findByTestId("desired-scale")).toHaveTextContent(`${initReplicas}`);
|
||||
expect(await component.findByTestId("current-scale")).toHaveTextContent(`${initReplicas}`);
|
||||
expect((await component.baseElement.querySelector("input").value)).toBe(`${initReplicas}`);
|
||||
|
||||
// edge case, desiredScale must >= 0
|
||||
let times = 10;
|
||||
for (let i = 0; i < times; i++) {
|
||||
fireEvent.click(down);
|
||||
}
|
||||
expect(await component.findByTestId('desired-scale')).toHaveTextContent('0');
|
||||
expect((await component.baseElement.querySelector('input').value)).toBe('0');
|
||||
expect(await component.findByTestId("desired-scale")).toHaveTextContent("0");
|
||||
expect((await component.baseElement.querySelector("input").value)).toBe("0");
|
||||
|
||||
// edge case, desiredScale must <= scaleMax (100)
|
||||
times = 120;
|
||||
for (let i = 0; i < times; i++) {
|
||||
fireEvent.click(up);
|
||||
}
|
||||
expect(await component.findByTestId('desired-scale')).toHaveTextContent('100');
|
||||
expect((component.baseElement.querySelector("input").value)).toBe('100');
|
||||
expect(await component.findByTestId('warning'))
|
||||
.toHaveTextContent('High number of replicas may cause cluster performance issues');
|
||||
expect(await component.findByTestId("desired-scale")).toHaveTextContent("100");
|
||||
expect((component.baseElement.querySelector("input").value)).toBe("100");
|
||||
expect(await component.findByTestId("warning"))
|
||||
.toHaveTextContent("High number of replicas may cause cluster performance issues");
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { RouteComponentProps } from "react-router";
|
||||
import { t, Trans } from "@lingui/macro";
|
||||
import { StatefulSet, statefulSetApi } from "../../api/endpoints";
|
||||
import { StatefulSet } from "../../api/endpoints";
|
||||
import { podsStore } from "../+workloads-pods/pods.store";
|
||||
import { statefulSetStore } from "./statefulset.store";
|
||||
import { nodesStore } from "../+nodes/nodes.store";
|
||||
@@ -64,7 +64,7 @@ export class StatefulSets extends React.Component<Props> {
|
||||
statefulSet.getNs(),
|
||||
this.renderPods(statefulSet),
|
||||
statefulSet.getReplicas(),
|
||||
<KubeObjectStatusIcon object={statefulSet}/>,
|
||||
<KubeObjectStatusIcon key="icon" object={statefulSet}/>,
|
||||
statefulSet.getAge(),
|
||||
]}
|
||||
renderItemMenu={(item: StatefulSet) => {
|
||||
|
||||
@@ -107,7 +107,7 @@ export class Workspaces extends React.Component {
|
||||
};
|
||||
|
||||
onInputKeypress = (evt: React.KeyboardEvent<any>, workspaceId: WorkspaceId) => {
|
||||
if (evt.key == 'Enter') {
|
||||
if (evt.key == "Enter") {
|
||||
// Trigget input validation
|
||||
evt.currentTarget.blur();
|
||||
evt.currentTarget.focus();
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './animate';
|
||||
export * from "./animate";
|
||||
@@ -34,11 +34,11 @@ import { Terminal } from "./dock/terminal";
|
||||
import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store";
|
||||
import logger from "../../main/logger";
|
||||
import { webFrame } from "electron";
|
||||
import { clusterPageRegistry, getExtensionPageUrl, PageRegistration, RegisteredPage } from "../../extensions/registries/page-registry";
|
||||
import { clusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry";
|
||||
import { extensionLoader } from "../../extensions/extension-loader";
|
||||
import { appEventBus } from "../../common/event-bus";
|
||||
import { broadcastMessage, requestMain } from "../../common/ipc";
|
||||
import whatInput from 'what-input';
|
||||
import whatInput from "what-input";
|
||||
import { clusterSetFrameIdHandler } from "../../common/cluster-ipc";
|
||||
import { ClusterPageMenuRegistration, clusterPageMenuRegistry } from "../../extensions/registries";
|
||||
import { TabLayoutRoute, TabLayout } from "./layout/tab-layout";
|
||||
|
||||
@@ -28,7 +28,7 @@ export class Button extends React.PureComponent<ButtonProps, {}> {
|
||||
const btnProps = props as Partial<ButtonProps>;
|
||||
if (hidden) return null;
|
||||
|
||||
btnProps.className = cssNames('Button', className, {
|
||||
btnProps.className = cssNames("Button", className, {
|
||||
waiting, primary, accent, plain, active, big, round, outlined
|
||||
});
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './button';
|
||||
export * from "./button";
|
||||
@@ -1,7 +1,7 @@
|
||||
import "./chart.scss";
|
||||
import React from "react";
|
||||
import ChartJS from "chart.js";
|
||||
import { isEqual, remove } from "lodash";
|
||||
import { remove } from "lodash";
|
||||
import { cssNames } from "../../utils";
|
||||
import { StatusBrick } from "../status-brick";
|
||||
import { Badge } from "../badge";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import './checkbox.scss';
|
||||
import React from 'react';
|
||||
import "./checkbox.scss";
|
||||
import React from "react";
|
||||
import { autobind, cssNames } from "../../utils";
|
||||
|
||||
export interface CheckboxProps<T = boolean> {
|
||||
@@ -29,7 +29,7 @@ export class Checkbox extends React.PureComponent<CheckboxProps> {
|
||||
|
||||
render() {
|
||||
const { label, inline, className, value, theme, children, ...inputProps } = this.props;
|
||||
const componentClass = cssNames('Checkbox flex', className, {
|
||||
const componentClass = cssNames("Checkbox flex", className, {
|
||||
inline,
|
||||
checked: value,
|
||||
disabled: this.props.disabled,
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './checkbox';
|
||||
export * from "./checkbox";
|
||||
@@ -25,6 +25,7 @@ export class Clipboard extends React.Component<CopyToClipboardProps> {
|
||||
static defaultProps = defaultProps as object;
|
||||
|
||||
get rootElem(): HTMLElement {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
return findDOMNode(this) as HTMLElement;
|
||||
}
|
||||
|
||||
@@ -59,4 +60,4 @@ export class Clipboard extends React.Component<CopyToClipboardProps> {
|
||||
return this.rootReactElem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,8 @@ import { Cluster } from "../../../main/cluster";
|
||||
import { cssNames, IClassName } from "../../utils";
|
||||
import { Badge } from "../badge";
|
||||
import { Tooltip } from "../tooltip";
|
||||
import { eventStore } from "../+events/event.store";
|
||||
import { forCluster } from "../../api/kube-api";
|
||||
import { subscribeToBroadcast, unsubscribeAllFromBroadcast } from "../../../common/ipc";
|
||||
import { observable, when } from "mobx";
|
||||
import { subscribeToBroadcast } from "../../../common/ipc";
|
||||
import { observable } from "mobx";
|
||||
|
||||
interface Props extends DOMAttributes<HTMLElement> {
|
||||
cluster: Cluster;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './confirm-dialog';
|
||||
export * from "./confirm-dialog";
|
||||
@@ -49,6 +49,7 @@ export class Dialog extends React.PureComponent<DialogProps, DialogState> {
|
||||
};
|
||||
|
||||
get elem() {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
return findDOMNode(this) as HTMLElement;
|
||||
}
|
||||
|
||||
@@ -91,17 +92,17 @@ export class Dialog extends React.PureComponent<DialogProps, DialogState> {
|
||||
onOpen = () => {
|
||||
this.props.onOpen();
|
||||
if (!this.props.pinned) {
|
||||
if (this.elem) this.elem.addEventListener('click', this.onClickOutside);
|
||||
if (this.elem) this.elem.addEventListener("click", this.onClickOutside);
|
||||
// Using document.body target to handle keydown event before Drawer does
|
||||
document.body.addEventListener('keydown', this.onEscapeKey);
|
||||
document.body.addEventListener("keydown", this.onEscapeKey);
|
||||
}
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
this.props.onClose();
|
||||
if (!this.props.pinned) {
|
||||
if (this.elem) this.elem.removeEventListener('click', this.onClickOutside);
|
||||
document.body.removeEventListener('keydown', this.onEscapeKey);
|
||||
if (this.elem) this.elem.removeEventListener("click", this.onClickOutside);
|
||||
document.body.removeEventListener("keydown", this.onEscapeKey);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './dialog';
|
||||
export * from "./dialog";
|
||||
@@ -106,8 +106,9 @@ export class Dock extends React.Component<Props> {
|
||||
autoFocus={isOpen}
|
||||
className="dock-tabs"
|
||||
value={selectedTab} onChange={this.onChangeTab}
|
||||
children={tabs.map(tab => <Fragment key={tab.id}>{this.renderTab(tab)}</Fragment>)}
|
||||
/>
|
||||
>
|
||||
{tabs.map(tab => <Fragment key={tab.id}>{this.renderTab(tab)}</Fragment>)}
|
||||
</Tabs>
|
||||
<div className="toolbar flex gaps align-center box grow">
|
||||
<div className="dock-menu box grow">
|
||||
<MenuActions usePortal triggerIcon={{ material: "add", className: "new-dock-tab", tooltip: <Trans>New tab</Trans> }} closeOnScroll={false}>
|
||||
|
||||
@@ -47,7 +47,7 @@ export class EditResourceStore extends DockTabStore<KubeEditResource> {
|
||||
}
|
||||
|
||||
getTabByResource(object: KubeObject): IDockTab {
|
||||
const [tabId] = Array.from(this.data).find(([tabId, { resource }]) => {
|
||||
const [tabId] = Array.from(this.data).find(([, { resource }]) => {
|
||||
return object.selfLink === resource;
|
||||
}) || [];
|
||||
return dockStore.getTabById(tabId);
|
||||
@@ -87,4 +87,4 @@ export function editResourceTab(object: KubeObject, tabParams: Partial<IDockTab>
|
||||
|
||||
export function isEditResourceTab(tab: IDockTab) {
|
||||
return tab && tab.kind === TabKind.EDIT_RESOURCE;
|
||||
}
|
||||
}
|
||||
@@ -60,17 +60,15 @@ export class InstallChartStore extends DockTabStore<IChartInstallData> {
|
||||
}
|
||||
|
||||
@action
|
||||
async loadValues(tabId: TabId) {
|
||||
async loadValues(tabId: TabId, attempt = 0): Promise<void> {
|
||||
const data = this.getData(tabId);
|
||||
const { repo, name, version } = data;
|
||||
|
||||
// This loop is for "retrying" the "getValues" call
|
||||
for (const _ of Array(3)) {
|
||||
const values = await helmChartsApi.getValues(repo, name, version);
|
||||
if (values) {
|
||||
this.setData(tabId, { ...data, values });
|
||||
return;
|
||||
}
|
||||
const values = await helmChartsApi.getValues(repo, name, version);
|
||||
if (values) {
|
||||
this.setData(tabId, { ...data, values });
|
||||
} else if (attempt < 4) {
|
||||
return this.loadValues(tabId, attempt + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export class PodLogs extends React.Component<Props> {
|
||||
* @param query {string} A text from search field
|
||||
*/
|
||||
@autobind()
|
||||
onSearch(query: string) {
|
||||
onSearch() {
|
||||
this.toOverlay();
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ export class Drawer extends React.Component<DrawerProps> {
|
||||
return;
|
||||
}
|
||||
const clickedElem = evt.target as HTMLElement;
|
||||
const isOutsideAnyDrawer = !clickedElem.closest('.Drawer');
|
||||
const isOutsideAnyDrawer = !clickedElem.closest(".Drawer");
|
||||
if (isOutsideAnyDrawer) {
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ export class ErrorBoundary extends React.Component<Props, State> {
|
||||
render() {
|
||||
const { error, errorInfo } = this.state;
|
||||
if (error) {
|
||||
const slackLink = <a href={slackUrl} target="_blank">Slack</a>;
|
||||
const githubLink = <a href={issuesTrackerUrl} target="_blank">Github</a>;
|
||||
const slackLink = <a href={slackUrl} rel="noreferrer" target="_blank">Slack</a>;
|
||||
const githubLink = <a href={issuesTrackerUrl} rel="noreferrer" target="_blank">Github</a>;
|
||||
const pageUrl = location.href;
|
||||
return (
|
||||
<div className="ErrorBoundary flex column gaps">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import './icon.scss';
|
||||
import "./icon.scss";
|
||||
|
||||
import React, { ReactNode } from "react";
|
||||
import { findDOMNode } from "react-dom";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { LocationDescriptor } from 'history';
|
||||
import { LocationDescriptor } from "history";
|
||||
import { autobind, cssNames } from "../../utils";
|
||||
import { TooltipDecoratorProps, withTooltip } from "../tooltip";
|
||||
import isNumber from "lodash/isNumber";
|
||||
@@ -49,11 +49,13 @@ export class Icon extends React.PureComponent<IconProps> {
|
||||
onKeyDown(evt: React.KeyboardEvent<any>) {
|
||||
switch (evt.nativeEvent.code) {
|
||||
case "Space":
|
||||
case "Enter":
|
||||
case "Enter": {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
const icon = findDOMNode(this) as HTMLElement;
|
||||
setTimeout(() => icon.click());
|
||||
evt.preventDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(evt);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export * from './input';
|
||||
export * from './search-input';
|
||||
export * from './search-input-url';
|
||||
export * from './file-input';
|
||||
export * from './drop-file-input';
|
||||
export * from "./input";
|
||||
export * from "./search-input";
|
||||
export * from "./search-input-url";
|
||||
export * from "./file-input";
|
||||
export * from "./drop-file-input";
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { InputProps } from "./input";
|
||||
import { ReactNode } from "react";
|
||||
import { t } from "@lingui/macro";
|
||||
import { _i18n } from '../../i18n';
|
||||
import { _i18n } from "../../i18n";
|
||||
import fse from "fs-extra";
|
||||
|
||||
export interface InputValidator {
|
||||
|
||||
@@ -37,7 +37,7 @@ export class KubeObjectMeta extends React.Component<KubeObjectMetaProps> {
|
||||
{getAge(true, false)} <Trans>ago</Trans> ({creationTimestamp})
|
||||
</DrawerItem>
|
||||
<DrawerItem name={<Trans>Name</Trans>} hidden={this.isHidden("name")}>
|
||||
{getName()} <KubeObjectStatusIcon object={object} />
|
||||
{getName()} <KubeObjectStatusIcon key="icon" object={object} />
|
||||
</DrawerItem>
|
||||
<DrawerItem name={<Trans>Namespace</Trans>} hidden={this.isHidden("namespace") || !getNs()}>
|
||||
{getNs()}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class LoginLayout extends React.Component<Props> {
|
||||
render() {
|
||||
const { className, header, title, footer, children } = this.props;
|
||||
return (
|
||||
<section className={cssNames('LoginLayout flex', className)}>
|
||||
<section className={cssNames("LoginLayout flex", className)}>
|
||||
<div className="header">{header}</div>
|
||||
<div className="box main">
|
||||
<div className="title">
|
||||
|
||||
@@ -36,11 +36,11 @@ export class PageLayout extends React.Component<PageLayoutProps> {
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
window.addEventListener('keydown', this.onEscapeKey);
|
||||
window.addEventListener("keydown", this.onEscapeKey);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('keydown', this.onEscapeKey);
|
||||
window.removeEventListener("keydown", this.onEscapeKey);
|
||||
}
|
||||
|
||||
onEscapeKey = (evt: KeyboardEvent) => {
|
||||
|
||||
@@ -26,10 +26,10 @@ import { Network } from "../+network";
|
||||
import { crdStore } from "../+custom-resources/crd.store";
|
||||
import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resources";
|
||||
import { CustomResources } from "../+custom-resources/custom-resources";
|
||||
import { isActiveRoute, navigation } from "../../navigation";
|
||||
import { isActiveRoute } from "../../navigation";
|
||||
import { isAllowedResource } from "../../../common/rbac";
|
||||
import { Spinner } from "../spinner";
|
||||
import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl, RegisteredPage } from "../../../extensions/registries";
|
||||
import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries";
|
||||
|
||||
const SidebarContext = React.createContext<SidebarContextValue>({ pinned: false });
|
||||
type SidebarContextValue = {
|
||||
@@ -102,16 +102,13 @@ export class Sidebar extends React.Component<Props> {
|
||||
const registeredPage = clusterPageRegistry.getByPageMenuTarget(menuItem.target);
|
||||
const tabRoutes = this.getTabLayoutRoutes(menuItem);
|
||||
let pageUrl: string;
|
||||
let routePath: string;
|
||||
let isActive = false;
|
||||
if (registeredPage) {
|
||||
const { extensionId, id: pageId } = registeredPage;
|
||||
pageUrl = getExtensionPageUrl({ extensionId, pageId, params: menuItem.target.params });
|
||||
routePath = registeredPage.routePath;
|
||||
isActive = isActiveRoute(registeredPage.routePath);
|
||||
} else if (tabRoutes.length > 0) {
|
||||
pageUrl = tabRoutes[0].url;
|
||||
routePath = tabRoutes[0].routePath;
|
||||
isActive = isActiveRoute(tabRoutes.map((tab) => tab.routePath));
|
||||
} else {
|
||||
return;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './line-progress';
|
||||
export * from "./line-progress";
|
||||
@@ -7,10 +7,10 @@ import marked from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
import { cssNames } from "../../utils";
|
||||
|
||||
DOMPurify.addHook('afterSanitizeAttributes', function (node) {
|
||||
DOMPurify.addHook("afterSanitizeAttributes", function (node) {
|
||||
// Set all elements owning target to target=_blank
|
||||
if ('target' in node as any as HTMLElement) {
|
||||
node.setAttribute('target', '_blank');
|
||||
if ("target" in node as any as HTMLElement) {
|
||||
node.setAttribute("target", "_blank");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loaded 100 of 199 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user