From 5c63bc44abbd7f0aa7ed439393f29d7cd67b5196 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 5 Apr 2021 21:16:20 +0200 Subject: [PATCH] config-schema: initial propper schema viewer Signed-off-by: Patrik Oldsberg --- .../components/SchemaViewer/SchemaViewer.tsx | 261 +++++++++++++++++- 1 file changed, 259 insertions(+), 2 deletions(-) diff --git a/plugins/config-schema/src/components/SchemaViewer/SchemaViewer.tsx b/plugins/config-schema/src/components/SchemaViewer/SchemaViewer.tsx index 3f4c11fc31..db29e5acbe 100644 --- a/plugins/config-schema/src/components/SchemaViewer/SchemaViewer.tsx +++ b/plugins/config-schema/src/components/SchemaViewer/SchemaViewer.tsx @@ -14,13 +14,270 @@ * limitations under the License. */ import React from 'react'; -import { CodeSnippet } from '@backstage/core'; import { Schema } from 'jsonschema'; +import { + Box, + Chip, + Divider, + Paper, + Table, + TableBody, + TableCell, + TableRow, + Typography, +} from '@material-ui/core'; +import { JsonValue } from '@backstage/config'; + +interface SchemaViewProps { + path: string; + depth: number; + schema: Schema; +} + +export interface MetadataViewRowProps { + label: string; + text?: string; + data?: JsonValue; +} + +export function MetadataViewRow({ label, text, data }: MetadataViewRowProps) { + if (text === undefined && data === undefined) { + return null; + } + return ( + + + + {label} + + + + + {data ? JSON.stringify(data) : text} + + + + ); +} + +export function MetadataView({ schema }: { schema: Schema }) { + return ( + + + + + + + + + + + + + + + + + + + + +
+
+ ); +} + +export function ScalarView({ schema }: SchemaViewProps) { + return ( + <> + {schema.description && ( + + {schema.description} + + )} + + + ); +} + +function isRequired(name: string, required?: boolean | string[]) { + if (required === true) { + return true; + } + if (Array.isArray(required)) { + return required.includes(name); + } + return false; +} + +function titleVariant(depth: number) { + if (depth <= 1) { + return 'h2'; + } else if (depth === 2) { + return 'h3'; + } else if (depth === 3) { + return 'h4'; + } else if (depth === 4) { + return 'h5'; + } + return 'h6'; +} + +export function VisibilityView({ schema }: { schema: Schema }) { + const { visibility } = schema as { visibility?: string }; + if (visibility === 'frontend') { + return ( + } + /> + ); + } else if (visibility === 'secret') { + return ( + } + /> + ); + } + return null; +} + +export function ArrayView({ path, depth, schema }: SchemaViewProps) { + const itemDepth = depth + 1; + const itemPath = path ? `${path}[]` : '[]'; + const itemSchema = schema.items; + + return ( + <> + + {schema.description && ( + + {schema.description} + + )} + + + Items + + + + + + {itemPath} + + + {itemSchema && ( + + )} + + + + ); +} + +export function ObjectView({ path, depth, schema }: SchemaViewProps) { + const properties = Object.entries(schema.properties ?? {}); + return ( + <> + {depth > 0 && ( + + {schema.description && ( + + {schema.description} + + )} + + + )} + {properties.length > 0 && ( + <> + {depth > 0 && Properties} + {properties.map(([name, propSchema], index) => { + const propDepth = depth + 1; + const propPath = path ? `${path}.${name}` : name; + + return ( + + + + + + {propPath} + + {isRequired(name, schema.required) && ( + + + required + + + )} + + + + + + ); + })} + + )} + + ); +} + +export function SchemaView(props: SchemaViewProps) { + // TODO(Rugvip): allOf, anyOf, oneOf + switch (props.schema.type) { + case 'array': + return ; + case 'object': + case undefined: + return ; + default: + return ; + } +} export interface SchemaViewerProps { schema: Schema; } export const SchemaViewer = ({ schema }: SchemaViewerProps) => { - return ; + return ; };