chore: change yaml rendering to be an option and enable for kubernetes plugin FE components
Signed-off-by: Chris Langhout <clanghout@bol.com>
This commit is contained in:
@@ -322,6 +322,8 @@ catalog:
|
||||
# Backstage example templates
|
||||
- type: file
|
||||
target: ../../plugins/scaffolder-backend/sample-templates/all-templates.yaml
|
||||
- type: file
|
||||
target: ../../plugins/scaffolder-backend/sample-templates/big-review-step.yaml
|
||||
rules:
|
||||
- allow: [Template]
|
||||
scaffolder:
|
||||
|
||||
+112
-22
@@ -14,50 +14,138 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import React, { Fragment, ReactElement } from 'react';
|
||||
import startCase from 'lodash/startCase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import { MetadataTable, MetadataTableItem } from './MetadataTable';
|
||||
import {
|
||||
MetadataList,
|
||||
MetadataListItem,
|
||||
MetadataTable,
|
||||
MetadataTableItem,
|
||||
} from './MetadataTable';
|
||||
import { CodeSnippet } from '../CodeSnippet';
|
||||
import jsyaml from 'js-yaml';
|
||||
import {
|
||||
Theme,
|
||||
createStyles,
|
||||
WithStyles,
|
||||
withStyles,
|
||||
} from '@material-ui/core/styles';
|
||||
|
||||
export type StructuredMetadataTableListClassKey = 'root';
|
||||
|
||||
export type StructuredMetadataTableNestedListClassKey = 'root';
|
||||
const listStyle = createStyles({
|
||||
root: {
|
||||
margin: '0 0',
|
||||
listStyleType: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
function toValue(value: object | Array<any> | boolean | string) {
|
||||
export type StructuredMetadataTableNestedListClassKey = 'root';
|
||||
const nestedListStyle = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
...listStyle.root,
|
||||
paddingLeft: theme.spacing(1),
|
||||
},
|
||||
});
|
||||
|
||||
interface StyleProps extends WithStyles {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
// Sub Components
|
||||
const StyledList = withStyles(listStyle, {
|
||||
name: 'BackstageStructuredMetadataTableList',
|
||||
})(({ classes, children }: StyleProps) => (
|
||||
<MetadataList classes={classes}>{children}</MetadataList>
|
||||
));
|
||||
const StyledNestedList = withStyles(nestedListStyle, {
|
||||
name: 'BackstageStructuredMetadataTableNestedList',
|
||||
})(({ classes, children }: StyleProps) => (
|
||||
<MetadataList classes={classes}>{children}</MetadataList>
|
||||
));
|
||||
|
||||
function renderList(list: Array<any>, options: Options, nested: boolean) {
|
||||
const values = list.map((item: any, index: number) => (
|
||||
<MetadataListItem key={index}>
|
||||
{toValue(item, options, nested)}
|
||||
</MetadataListItem>
|
||||
));
|
||||
return nested ? (
|
||||
<StyledNestedList>{values}</StyledNestedList>
|
||||
) : (
|
||||
<StyledList>{values}</StyledList>
|
||||
);
|
||||
}
|
||||
|
||||
function renderMap(
|
||||
map: { [key: string]: any },
|
||||
options: Options,
|
||||
nested: boolean,
|
||||
) {
|
||||
const values = Object.keys(map).map(key => {
|
||||
const value = toValue(map[key], options, true);
|
||||
return (
|
||||
<MetadataListItem key={key}>
|
||||
<Typography variant="body2" component="span">
|
||||
{`${options.titleFormat(key)}: `}
|
||||
</Typography>
|
||||
{value}
|
||||
</MetadataListItem>
|
||||
);
|
||||
});
|
||||
|
||||
return nested ? (
|
||||
<StyledNestedList>{values}</StyledNestedList>
|
||||
) : (
|
||||
<StyledList>{values}</StyledList>
|
||||
);
|
||||
}
|
||||
|
||||
function toValue(
|
||||
value: ReactElement | object | Array<any> | boolean,
|
||||
options: Options,
|
||||
nested: boolean,
|
||||
) {
|
||||
if (React.isValidElement(value)) {
|
||||
return <Fragment>{value}</Fragment>;
|
||||
}
|
||||
|
||||
if (value !== null && typeof value === 'object') {
|
||||
return (
|
||||
<CodeSnippet
|
||||
language="yaml"
|
||||
text={jsyaml.dump(value)}
|
||||
customStyle={{
|
||||
background: 'transparent',
|
||||
lineHeight: '1.4',
|
||||
padding: '0',
|
||||
margin: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
if (options.nestedValuesAsYaml) {
|
||||
return (
|
||||
<CodeSnippet
|
||||
language="yaml"
|
||||
text={jsyaml.dump(value)}
|
||||
customStyle={{
|
||||
background: 'transparent',
|
||||
lineHeight: '1.4',
|
||||
padding: '0',
|
||||
margin: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (!Array.isArray(value)) {
|
||||
return renderMap(value, options, nested);
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return renderList(value, options, nested);
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return <Fragment>{value ? '✅' : '❌'}</Fragment>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography variant="body2" component="span">
|
||||
{value}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
const ItemValue = ({ value }: { value: any }) => (
|
||||
<Fragment>{toValue(value)}</Fragment>
|
||||
const ItemValue = ({ value, options }: { value: any; options: Options }) => (
|
||||
<Fragment>{toValue(value, options, false)}</Fragment>
|
||||
);
|
||||
|
||||
const TableItem = ({
|
||||
@@ -71,7 +159,7 @@ const TableItem = ({
|
||||
}) => {
|
||||
return (
|
||||
<MetadataTableItem title={options.titleFormat(title)}>
|
||||
<ItemValue value={value} />
|
||||
<ItemValue value={value} options={options} />
|
||||
</MetadataTableItem>
|
||||
);
|
||||
};
|
||||
@@ -94,6 +182,7 @@ export interface StructuredMetadataTableProps {
|
||||
* @returns Formatted key
|
||||
*/
|
||||
titleFormat?: (key: string) => string;
|
||||
nestedValuesAsYaml?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,9 +190,10 @@ type Options = Required<NonNullable<StructuredMetadataTableProps['options']>>;
|
||||
|
||||
/** @public */
|
||||
export function StructuredMetadataTable(props: StructuredMetadataTableProps) {
|
||||
const { metadata, dense = true, options = {} } = props;
|
||||
const { metadata, dense = true, options } = props;
|
||||
const metadataItems = mapToItems(metadata, {
|
||||
titleFormat: startCase,
|
||||
nestedValuesAsYaml: options?.nestedValuesAsYaml ?? false,
|
||||
...options,
|
||||
});
|
||||
return <MetadataTable dense={dense}>{metadataItems}</MetadataTable>;
|
||||
|
||||
@@ -58,6 +58,7 @@ export const ClusterOverview = () => {
|
||||
'OIDC Token Provider': value.oidcTokenProvider ?? 'N/A',
|
||||
'Dashboard Link': value.dashboardUrl ?? 'N/A',
|
||||
}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</InfoCard>
|
||||
|
||||
@@ -50,7 +50,10 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Node Info</Typography>
|
||||
<StructuredMetadataTable metadata={node.status?.nodeInfo ?? {}} />
|
||||
<StructuredMetadataTable
|
||||
metadata={node.status?.nodeInfo ?? {}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Addresses</Typography>
|
||||
@@ -61,6 +64,7 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
return accum;
|
||||
}, {} as any) ?? {}
|
||||
}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -72,6 +76,7 @@ const defaultColumns: TableColumn<INode>[] = [
|
||||
return accum;
|
||||
}, {} as any) ?? {}
|
||||
}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -84,7 +84,10 @@ const DefaultCustomResourceAccordion = ({
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{Object.prototype.hasOwnProperty.call(customResource, 'status') && (
|
||||
<StructuredMetadataTable metadata={customResource.status} />
|
||||
<StructuredMetadataTable
|
||||
metadata={customResource.status}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
@@ -65,6 +65,9 @@ const IngressCard = ({ ingress }: IngressCardProps) => {
|
||||
metadata={{
|
||||
...ingress.spec,
|
||||
}}
|
||||
options={{
|
||||
nestedValuesAsYaml: true,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+1
@@ -237,6 +237,7 @@ const KubernetesStructuredMetadataTableDrawerContent = <
|
||||
{!isYaml && (
|
||||
<StructuredMetadataTable
|
||||
metadata={renderObject(replaceNullsWithUndefined(object))}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -176,6 +176,7 @@ export const ContainerCard: React.FC<ContainerCardProps> = ({
|
||||
containerSpec,
|
||||
containerStatus,
|
||||
)}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
</Grid>
|
||||
{containerMetrics && (
|
||||
|
||||
@@ -77,6 +77,7 @@ const ServiceCard = ({ service }: ServiceCardProps) => {
|
||||
ports: service.spec?.ports,
|
||||
...metadata,
|
||||
}}
|
||||
options={{ nestedValuesAsYaml: true }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user