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:
Sebastian Malton authored and GitHub committed 2020-11-27 08:48:38 -05:00
1 parent 10eb082854
commit 7451869c25
199 files changed
+1178 -807

No files matched your search

@@ -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&apos;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&apos;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&apos;t be deleted automatically</Trans>
</p>
</div>
);
@@ -146,4 +146,4 @@ export class HelmReleases extends Component<Props> {
</>
);
}
}
}
@@ -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&apos;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> {
);
}
}
@@ -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(),
]}
/>
);
}
}
+1 -1
View File
@@ -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&apos;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">
+1 -1
View File
@@ -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(),
+2 -2
View File
@@ -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(),
]}
@@ -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
View File
@@ -1 +1 @@
export * from './animate';
export * from "./animate";
+2 -2
View File
@@ -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";
+1 -1
View File
@@ -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
View File
@@ -1 +1 @@
export * from './button';
export * from "./button";
+1 -1
View File
@@ -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
View File
@@ -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";
+5 -4
View File
@@ -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
View File
@@ -1 +1 @@
export * from './dialog';
export * from "./dialog";
+3 -2
View File
@@ -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);
}
}
}
+1 -1
View File
@@ -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();
}
+1 -1
View File
@@ -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">
+5 -3
View File
@@ -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);
+5 -5
View File
@@ -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) => {
+2 -5
View File
@@ -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");
}
});
+2 -2
View File
@@ -1,2 +1,2 @@
export * from './menu';
export * from './menu-actions';
export * from "./menu";
export * from "./menu-actions";
+16 -16
View File
@@ -1,4 +1,4 @@
import './menu.scss';
import "./menu.scss";
import React, { Fragment, ReactElement, ReactNode } from "react";
import { createPortal } from "react-dom";
@@ -64,30 +64,30 @@ export class Menu extends React.Component<MenuProps, State> {
if (!this.props.usePortal) {
const parent = this.elem.parentElement;
const position = window.getComputedStyle(parent).position;
if (position === 'static') parent.style.position = 'relative';
if (position === "static") parent.style.position = "relative";
} else if (this.isOpen) {
this.refreshPosition();
}
this.opener = document.getElementById(this.props.htmlFor); // might not exist in sub-menus
if (this.opener) {
this.opener.addEventListener('click', this.toggle);
this.opener.addEventListener('keydown', this.onKeyDown);
this.opener.addEventListener("click", this.toggle);
this.opener.addEventListener("keydown", this.onKeyDown);
}
this.elem.addEventListener('keydown', this.onKeyDown);
window.addEventListener('resize', this.onWindowResize);
window.addEventListener('click', this.onClickOutside, true);
window.addEventListener('scroll', this.onScrollOutside, true);
this.elem.addEventListener("keydown", this.onKeyDown);
window.addEventListener("resize", this.onWindowResize);
window.addEventListener("click", this.onClickOutside, true);
window.addEventListener("scroll", this.onScrollOutside, true);
}
componentWillUnmount() {
if (this.opener) {
this.opener.removeEventListener('click', this.toggle);
this.opener.removeEventListener('keydown', this.onKeyDown);
this.opener.removeEventListener("click", this.toggle);
this.opener.removeEventListener("keydown", this.onKeyDown);
}
this.elem.removeEventListener('keydown', this.onKeyDown);
window.removeEventListener('resize', this.onWindowResize);
window.removeEventListener('click', this.onClickOutside, true);
window.removeEventListener('scroll', this.onScrollOutside, true);
this.elem.removeEventListener("keydown", this.onKeyDown);
window.removeEventListener("resize", this.onWindowResize);
window.removeEventListener("click", this.onClickOutside, true);
window.removeEventListener("scroll", this.onScrollOutside, true);
}
protected get focusableItems() {
@@ -188,7 +188,7 @@ export class Menu extends React.Component<MenuProps, State> {
}
}
onWindowResize(evt: UIEvent) {
onWindowResize() {
if (!this.isOpen) return;
this.refreshPosition();
}
@@ -224,7 +224,7 @@ export class Menu extends React.Component<MenuProps, State> {
render() {
const { position, id } = this.props;
let { className, usePortal } = this.props;
className = cssNames('Menu', className, this.state.position || position, {
className = cssNames("Menu", className, this.state.position || position, {
portal: usePortal,
});
@@ -1,2 +1,2 @@
export * from './notifications';
export * from './notifications.store';
export * from "./notifications";
export * from "./notifications.store";
@@ -1,6 +1,6 @@
import './notifications.scss';
import "./notifications.scss";
import React from 'react';
import React from "react";
import { reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { JsonApiErrorParsed } from "../../api/json-api";
+1 -1
View File
@@ -65,7 +65,7 @@ export class Radio extends React.Component<RadioProps> {
render() {
const { className, label, checked, children, ...inputProps } = this.props;
const componentClass = cssNames('Radio flex align-center', className, {
const componentClass = cssNames("Radio flex align-center", className, {
checked,
disabled: this.props.disabled,
});
@@ -1 +1 @@
export * from './resizing-anchor';
export * from "./resizing-anchor";
@@ -2,7 +2,6 @@ import "./resizing-anchor.scss";
import React from "react";
import { action, observable } from "mobx";
import _ from "lodash";
import { findDOMNode } from "react-dom";
import { cssNames, noop } from "../../utils";
export enum ResizeDirection {
@@ -262,7 +261,7 @@ export class ResizingAnchor extends React.PureComponent<Props> {
}, 100);
@action
onDragEnd = (_event: MouseEvent) => {
onDragEnd = () => {
this.props.onEnd();
document.removeEventListener("mousemove", this.onDrag);
document.removeEventListener("mouseup", this.onDragEnd);
+1 -1
View File
@@ -1 +1 @@
export * from './select';
export * from "./select";
@@ -1,5 +1,5 @@
import './cube-spinner.scss';
import React from 'react';
import "./cube-spinner.scss";
import React from "react";
import { cssNames } from "../../utils";
export interface CubeSpinnerProps {
Loaded 100 of 199 files, more files were not shown because too many files have changed in this diff. Show more