Fix rendering of boolean values in CRDs (#1087)

* Fix rendering of boolean values in CRDs

- add optional special casing for boolean values in DrawerItems and
  TableRows since React (imo annoying fashion) does not render boolean
  values by default.
- add a spinner on the sidebar for when the CRD menu is expeanded but
  the entries have not been loaded yet.
- Add ability to double click a Badge to expand, also make it so that
  Badges highligh all text on first click.

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2020-11-10 10:10:19 -05:00
1 parent dd90dcb7f0
commit a78bbb5f6c
15 files changed
+167 -101

No files matched your search

@@ -12,67 +12,83 @@ import { KubeObjectDetailsProps } from "../kube-object";
import { crdStore } from "./crd.store";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { Input } from "../input";
import { CustomResourceDefinition } from "../../api/endpoints/crd.api";
import { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api";
interface Props extends KubeObjectDetailsProps<CustomResourceDefinition> {
}
function CrdColumnValue({ value }: { value: any[] | {} | string }) {
function convertSpecValue(value: any): any {
if (Array.isArray(value)) {
return <>{value.map((item, index) => <CrdColumnValue key={index} value={item} />)}</>
return value.map(convertSpecValue)
}
if (typeof(value) === 'object') return (
<Input
readOnly
multiLine
theme="round-black"
className="box grow"
value={JSON.stringify(value, null, 2)}
/>
);
return <span>{value}</span>;
if (typeof value === "object") {
return (
<Input
readOnly
multiLine
theme="round-black"
className="box grow"
value={JSON.stringify(value, null, 2)}
/>
)
}
return value
}
@observer
export class CrdResourceDetails extends React.Component<Props> {
@computed get crd() {
return crdStore.getByObject(this.props.object);
}
renderAdditionalColumns(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) {
return columns.map(({ name, jsonPath: jp }) => (
<DrawerItem key={name} name={name} renderBoolean>
{convertSpecValue(jsonPath.value(crd, jp.slice(1)))}
</DrawerItem>
))
}
renderStatus(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) {
const showStatus = !columns.find(column => column.name == "Status") && crd.status?.conditions;
if (!showStatus) {
return null
}
const conditions = crd.status.conditions
.filter(({ type, reason }) => type || reason)
.map(({ type, reason, message, status }) => ({ kind: type || reason, message, status }))
.map(({ kind, message, status }, index) => (
<Badge
key={kind + index} label={kind}
className={cssNames({ disabled: status === "False" }, kind.toLowerCase())}
tooltip={message}
/>
))
return (
<DrawerItem name={<Trans>Status</Trans>} className="status" labelsOnly>
{conditions}
</DrawerItem>
)
}
render() {
const { object } = this.props;
const { crd } = this;
if (!object || !crd) return null;
const { props: { object }, crd } = this;
if (!object || !crd) {
return null;
}
const className = cssNames("CrdResourceDetails", crd.getResourceKind());
const extraColumns = crd.getPrinterColumns();
const showStatus = !extraColumns.find(column => column.name == "Status") && object.status?.conditions;
return (
<div className={className}>
<KubeObjectMeta object={object}/>
{extraColumns.map(column => {
const { name } = column;
const value = jsonPath.query(object, (column.jsonPath).slice(1));
return (
<DrawerItem key={name} name={name}>
<CrdColumnValue value={value} />
</DrawerItem>
)
})}
{showStatus && (
<DrawerItem name={<Trans>Status</Trans>} className="status" labelsOnly>
{object.status.conditions.map((condition, index) => {
const { type, reason, message, status } = condition;
const kind = type || reason;
if (!kind) return null;
return (
<Badge
key={kind + index} label={kind}
className={cssNames({ disabled: status === "False" }, kind.toLowerCase())}
tooltip={message}
/>
);
})}
</DrawerItem>
)}
<KubeObjectMeta object={object} />
{this.renderAdditionalColumns(object, extraColumns)}
{this.renderStatus(object, extraColumns)}
</div>
)
}
@@ -56,11 +56,11 @@ export class CrdResources extends React.Component<Props> {
[sortBy.age]: (item: KubeObject) => item.metadata.creationTimestamp,
}
extraColumns.forEach(column => {
sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.query(item, column.jsonPath.slice(1))
sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1))
})
const ListView = KubeObjectListLayout;
return (
<ListView
<KubeObjectListLayout
className="CrdResources"
isClusterScoped={!isNamespaced}
store={store}
@@ -85,9 +85,10 @@ export class CrdResources extends React.Component<Props> {
renderTableContents={(crdInstance: KubeObject) => [
crdInstance.getName(),
isNamespaced && crdInstance.getNs(),
...extraColumns.map(column => {
return jsonPath.query(crdInstance, (column.jsonPath).slice(1))
}),
...extraColumns.map(column => ({
renderBoolean: true,
children: jsonPath.value(crdInstance, column.jsonPath.slice(1)),
})),
crdInstance.getAge(),
]}
/>