1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fix parseApi not accepting versions that don't start with 'v' (#441)

* fix parseApi not accepting versions that don't start with 'v'

Signed-off-by: Sebastian Malton <smalton@mirantis.com>

Co-authored-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
Sebastian Malton 2020-06-11 13:19:01 -04:00 committed by GitHub
parent 5c5454166f
commit 00557c9940
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1956 additions and 2477 deletions

View File

@ -32,20 +32,31 @@ export interface IKubeApiLinkRef {
namespace?: string; namespace?: string;
} }
export class KubeApi<T extends KubeObject = any> { export interface IKubeApiLinkBase extends IKubeApiLinkRef {
static matcher = /(\/apis?.*?)\/(?:(.*?)\/)?(v.*?)(?:\/namespaces\/(.+?))?\/([^\/]+)(?:\/([^\/?]+))?.*$/ apiBase: string;
apiGroup: string;
apiVersionWithGroup: string;
}
static parseApi(apiPath = "") { export class KubeApi<T extends KubeObject = any> {
static matcher = /(\/apis?.*?)\/(?:(.*?)\/)?(.*?)(?:\/namespaces\/(.+?))?\/([^\/]+)(?:\/([^\/?]+))?.*$/
static parseApi(apiPath = ""): IKubeApiLinkBase {
apiPath = new URL(apiPath, location.origin).pathname; apiPath = new URL(apiPath, location.origin).pathname;
const [, apiPrefix, apiGroup = "", apiVersion, namespace, resource, name] = apiPath.match(KubeApi.matcher) || []; const [, apiPrefix, apiGroup = "", apiVersion, namespace, resource, name] = apiPath.match(KubeApi.matcher) || [];
const apiVersionWithGroup = [apiGroup, apiVersion].filter(v => v).join("/"); const apiVersionWithGroup = [apiGroup, apiVersion].filter(v => v).join("/");
const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/");
if (!apiBase) {
throw new Error(`invalid apiPath: ${apiPath}`)
}
return { return {
apiBase, apiBase,
apiPrefix, apiGroup, apiPrefix, apiGroup,
apiVersion, apiVersionWithGroup, apiVersion, apiVersionWithGroup,
namespace, resource, name, namespace, resource, name,
} };
} }
static createLink(ref: IKubeApiLinkRef): string { static createLink(ref: IKubeApiLinkRef): string {
@ -55,7 +66,7 @@ export class KubeApi<T extends KubeObject = any> {
namespace = `namespaces/${namespace}` namespace = `namespaces/${namespace}`
} }
return [apiPrefix, apiVersion, namespace, resource, name] return [apiPrefix, apiVersion, namespace, resource, name]
.filter(v => !!v) .filter(v => v)
.join("/") .join("/")
} }
@ -130,8 +141,9 @@ export class KubeApi<T extends KubeObject = any> {
if (KubeObject.isJsonApiData(data)) { if (KubeObject.isJsonApiData(data)) {
return new KubeObjectConstructor(data); return new KubeObjectConstructor(data);
} }
// process items list response // process items list response
else if (KubeObject.isJsonApiDataList(data)) { if (KubeObject.isJsonApiDataList(data)) {
const { apiVersion, items, metadata } = data; const { apiVersion, items, metadata } = data;
this.setResourceVersion(namespace, metadata.resourceVersion); this.setResourceVersion(namespace, metadata.resourceVersion);
this.setResourceVersion("", metadata.resourceVersion); this.setResourceVersion("", metadata.resourceVersion);
@ -141,10 +153,12 @@ export class KubeApi<T extends KubeObject = any> {
...item, ...item,
})) }))
} }
// custom apis might return array for list response, e.g. users, groups, etc. // custom apis might return array for list response, e.g. users, groups, etc.
else if (Array.isArray(data)) { if (Array.isArray(data)) {
return data.map(data => new KubeObjectConstructor(data)); return data.map(data => new KubeObjectConstructor(data));
} }
return data; return data;
} }
@ -162,16 +176,19 @@ export class KubeApi<T extends KubeObject = any> {
async create({ name = "", namespace = "default" } = {}, data?: Partial<T>): Promise<T> { async create({ name = "", namespace = "default" } = {}, data?: Partial<T>): Promise<T> {
const apiUrl = this.getUrl({ namespace }); const apiUrl = this.getUrl({ namespace });
return this.request.post(apiUrl, {
data: merge({ return this.request
kind: this.kind, .post(apiUrl, {
apiVersion: this.apiVersionWithGroup, data: merge({
metadata: { kind: this.kind,
name, apiVersion: this.apiVersionWithGroup,
namespace metadata: {
} name,
}, data) namespace
}).then(this.parseResponse); }
}, data)
})
.then(this.parseResponse);
} }
async update({ name = "", namespace = "default" } = {}, data?: Partial<T>): Promise<T> { async update({ name = "", namespace = "default" } = {}, data?: Partial<T>): Promise<T> {

View File

@ -96,7 +96,7 @@ export class DeploymentScaleDialog extends Component<Props> {
<Trans>Desired number of replicas</Trans>: {desiredReplicas} <Trans>Desired number of replicas</Trans>: {desiredReplicas}
</div> </div>
<div className="slider-container"> <div className="slider-container">
<Slider value={desiredReplicas} max={scaleMax} onChange={onChange}/> <Slider value={desiredReplicas} max={scaleMax} onChange={onChange as any /** see: https://github.com/mui-org/material-ui/issues/20191 */}/>
</div> </div>
</div> </div>
{warning && {warning &&

View File

@ -150,7 +150,7 @@ export function BarChart(props: Props) {
} }
}; };
const options = merge(barOptions, customOptions); const options = merge(barOptions, customOptions);
if (!chartData.datasets.length) { if (chartData.datasets.length == 0) {
return <NoMetrics/> return <NoMetrics/>
} }
return ( return (
@ -170,9 +170,17 @@ export const memoryOptions: ChartOptions = {
scales: { scales: {
yAxes: [{ yAxes: [{
ticks: { ticks: {
callback: value => { callback: (value: number | string): string => {
if (!value) return 0; if (typeof value == "string") {
return parseFloat(value) < 1 ? value.toFixed(3) : bytesToUnits(parseInt(value)); const float = parseFloat(value);
if (float < 1) {
return float.toFixed(3);
}
return bytesToUnits(parseInt(value));
}
return `${value}`;
}, },
stepSize: 1 stepSize: 1
} }
@ -194,11 +202,12 @@ export const cpuOptions: ChartOptions = {
scales: { scales: {
yAxes: [{ yAxes: [{
ticks: { ticks: {
callback: value => { callback: (value: number | string): string => {
if (value == 0) return 0; const float = parseFloat(`${value}`);
if (value < 10) return value.toFixed(3); if (float == 0) return "0";
if (value < 100) return value.toFixed(2); if (float < 10) return float.toFixed(3);
return value.toFixed(1); if (float < 100) return float.toFixed(2);
return float.toFixed(1);
} }
} }
}] }]

View File

@ -19,10 +19,7 @@ export interface ChartDataSet extends ChartDataSets {
} }
export interface ChartProps { export interface ChartProps {
data: { data: ChartData;
labels?: Array<string | string[]>;
datasets?: ChartDataSet[];
};
width?: number | string; width?: number | string;
height?: number | string; height?: number | string;
options?: ChartOptions; // Passed to ChartJS instance options?: ChartOptions; // Passed to ChartJS instance

View File

@ -7,7 +7,6 @@ import { cssNames } from "../../utils";
import { themeStore } from "../../theme.store"; import { themeStore } from "../../theme.store";
interface Props extends ChartProps { interface Props extends ChartProps {
data: ChartData;
title?: string; title?: string;
} }

View File

@ -10,7 +10,7 @@ import ReactSelect, { components as ReactSelectComponents } from "react-select"
import { Props as ReactSelectProps } from "react-select/base" import { Props as ReactSelectProps } from "react-select/base"
import Creatable, { CreatableProps } from "react-select/creatable" import Creatable, { CreatableProps } from "react-select/creatable"
import { StylesConfig } from "react-select/src/styles" import { StylesConfig } from "react-select/src/styles"
import { ActionMeta } from "react-select/src/types" import { ActionMeta, OptionTypeBase } from "react-select/src/types"
import { themeStore } from "../../theme.store"; import { themeStore } from "../../theme.store";
export { ReactSelectComponents } export { ReactSelectComponents }
@ -31,7 +31,7 @@ export interface SelectProps<T = any> extends ReactSelectProps<T>, CreatableProp
menuClass?: string; menuClass?: string;
isCreatable?: boolean; isCreatable?: boolean;
autoConvertOptions?: boolean; // to internal format (i.e. {value: T, label: string}[]), not working with groups autoConvertOptions?: boolean; // to internal format (i.e. {value: T, label: string}[]), not working with groups
onChange?(option: T, meta?: ActionMeta): void; onChange?(option: T, meta?: ActionMeta<OptionTypeBase>): void;
} }
@observer @observer
@ -76,7 +76,7 @@ export class Select extends React.Component<SelectProps> {
} }
@autobind() @autobind()
onChange(value: SelectOption, meta: ActionMeta) { onChange(value: SelectOption, meta: ActionMeta<OptionTypeBase>) {
if (this.props.onChange) { if (this.props.onChange) {
this.props.onChange(value, meta); this.props.onChange(value, meta);
} }

View File

@ -31,7 +31,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.8.3", "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.6.2", "@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "=7.9.0", "@babel/preset-env": "^7.10.1",
"@babel/preset-react": "^7.7.0", "@babel/preset-react": "^7.7.0",
"@babel/preset-typescript": "^7.8.3", "@babel/preset-typescript": "^7.8.3",
"@babel/runtime": "^7.7.2", "@babel/runtime": "^7.7.2",

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ export class PrometheusLens implements PrometheusProvider {
port: service.spec.ports[0].port port: service.spec.ports[0].port
} }
} catch(error) { } catch(error) {
logger.warn(`PrometheusLens: failed to list services: ${error.toString()}`) logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`)
} }
} }