From 2e811af7e52182c55dedffce9f472062af244380 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Mon, 6 May 2024 11:13:21 -0300 Subject: [PATCH 01/13] add URL download and render templated mdx --- docs/docs/explanations/nebari-yaml-schema.mdx | 8 ++ docs/package.json | 5 +- docs/sidebars.js | 1 + .../components/NebariSchemaLoader/index.tsx | 136 ++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 docs/docs/explanations/nebari-yaml-schema.mdx create mode 100644 docs/src/components/NebariSchemaLoader/index.tsx diff --git a/docs/docs/explanations/nebari-yaml-schema.mdx b/docs/docs/explanations/nebari-yaml-schema.mdx new file mode 100644 index 000000000..40e241c5f --- /dev/null +++ b/docs/docs/explanations/nebari-yaml-schema.mdx @@ -0,0 +1,8 @@ +--- +title: 'Configuring nebari-config.yaml' +id: nebari-yaml-schema +--- + +import NebariSchemaLoader from '@site/src/components/NebariSchemaLoader'; + + diff --git a/docs/package.json b/docs/package.json index 8ed73d111..452cc056a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -43,13 +43,16 @@ "@docusaurus/core": "2.0.0-beta.20", "@docusaurus/preset-classic": "2.0.0-beta.20", "@mdx-js/react": "^1.6.22", + "@stoplight/json-ref-resolver": "^3.1.6", "clsx": "^1.1.1", "docusaurus-lunr-search": "^2.1.15", "docusaurus-plugin-sass": "^0.2.2", "prism-react-renderer": "^1.3.5", "react": "^17.0.2", "react-dom": "^17.0.2", - "sass": "^1.52.1" + "sass": "^1.52.1", + "react-markdown": "^8.0.3", + "remark-gfm": "^4.0.0" }, "devDependencies": { "@babel/eslint-parser": "^7.18.2", diff --git a/docs/sidebars.js b/docs/sidebars.js index ab0ff9d00..8e3cdb613 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -94,6 +94,7 @@ module.exports = { "explanations/custom-overrides-configuration", "explanations/config-best-practices", "explanations/infrastructure-architecture", + "explanations/nebari-yaml-schema", ], }, { diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx new file mode 100644 index 000000000..3b7fee55c --- /dev/null +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -0,0 +1,136 @@ +import React, { useState, useEffect } from "react"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; +import { Resolver } from "@stoplight/json-ref-resolver"; + +import Details from "@theme/Details"; +import Admonition from "@theme/Admonition"; +import Heading from "@theme/Heading"; + +// Schema Initial Data +const NebariSchema = { + title: "Nebari Configuration Schema", + description: "The Nebari configuration schema.", + type: "object", + properties: { + name: { + type: "string", + description: "The name of the package.", + examples: ["nebari"], + }, + description: { + type: "string", + description: "The description of the package.", + examples: ["A package manager for conda packages."], + }, + }, +}; + +// Main Component +export default function NebariJsonSchema({ toc = null }) { + const schemaURL = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; + const [schema, setSchema] = useState(NebariSchema); + const [resolved, setResolved] = useState(false); + + useEffect(() => { + const fetchSchema = async () => { + try { + const response = await fetch(schemaURL, { headers: { Accept: "application/json" } }); + const rawSchema = await response.json(); + const resolver = new Resolver(); + const resolvedSchema = await resolver.resolve(rawSchema); + setSchema(resolvedSchema.result); + setResolved(true); + } catch (error) { + console.error('Failed to fetch and resolve schema', error); + } + }; + fetchSchema(); + }, []); + + return ( + <> + + This documentation is autogenerated from{" "} + + Nebari config yaml's JSON Schema + . + + + {schema.description} +

+ {schema.properties && Object.entries(schema.properties).sort().map(([key, value]) => ( + + ))} + + ); +} + +// Sub-Components +function SchemaToc({ schema }) { + return ( + + ); +} + +function Setting({ name, value, withTypes = true, toc = null }) { + if (toc) { + toc.push({ value: name, id: name.replace(/_/g, "-"), level: 3 }); + } + + return ( + <> + + {value.deprecated ? {name} : name} + {value.deprecated && ( +

+ + Deprecated + +

+ )} + {value.description && {value.description.trim()}} + {withTypes && } + {value.examples && ( +
+ {value.examples.join(", ")} +
+ )} + + ); +} + +function Type({ value }) { + const types = []; + const customTypes = { options: [] }; + + value.anyOf?.forEach(v => { + if (v.type) { + types.push({v.type}); + if (v.enum) { + customTypes.options.push(...v.enum.map(e => {e})); + } + } + }); + + return ( + <> + {types.length > 0 && Type: {types.reduce((prev, curr) => [prev, ', ', curr])}} + {value.default !== undefined && Default: {JSON.stringify(value.default)}} + {customTypes.options.length > 0 && ( + <> +
+ Options: {customTypes.options} + + )} + + ); +} From 574e539061408b625c958cc6ccc1856901510791 Mon Sep 17 00:00:00 2001 From: viniciusdc Date: Mon, 6 May 2024 17:52:01 -0300 Subject: [PATCH 02/13] update component logic --- docs/docs/explanations/nebari-yaml-schema.mdx | 8 +- docs/package.json | 2 +- .../components/NebariSchemaLoader/index.tsx | 171 ++++++++---------- 3 files changed, 86 insertions(+), 95 deletions(-) diff --git a/docs/docs/explanations/nebari-yaml-schema.mdx b/docs/docs/explanations/nebari-yaml-schema.mdx index 40e241c5f..bb160df06 100644 --- a/docs/docs/explanations/nebari-yaml-schema.mdx +++ b/docs/docs/explanations/nebari-yaml-schema.mdx @@ -3,6 +3,10 @@ title: 'Configuring nebari-config.yaml' id: nebari-yaml-schema --- -import NebariSchemaLoader from '@site/src/components/NebariSchemaLoader'; +# Configuration Schema - +This section includes the Nebari configuration schema loaded dynamically below: + +import NebariConfig from '@site/src/components/NebariSchemaLoader'; + + diff --git a/docs/package.json b/docs/package.json index 452cc056a..bf029c3b0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -51,7 +51,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "sass": "^1.52.1", - "react-markdown": "^8.0.3", + "react-markdown": "^8.0.7", "remark-gfm": "^4.0.0" }, "devDependencies": { diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 3b7fee55c..2702b16eb 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -1,76 +1,92 @@ -import React, { useState, useEffect } from "react"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; -import { Resolver } from "@stoplight/json-ref-resolver"; +import React, { useState, useEffect } from 'react'; +import { Resolver } from '@stoplight/json-ref-resolver'; +import Heading from '@theme/Heading'; +import ReactMarkdown from 'react-markdown'; +import CodeBlock from '@theme/CodeBlock'; +import Admonition from '@theme/Admonition'; +import Details from '@theme/Details'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; -import Details from "@theme/Details"; -import Admonition from "@theme/Admonition"; -import Heading from "@theme/Heading"; +// Define the correct schema type +type SchemaProperty = { + deprecated?: boolean; + description?: string; +}; + +type Properties = { + [key: string]: SchemaProperty; +}; -// Schema Initial Data -const NebariSchema = { - title: "Nebari Configuration Schema", - description: "The Nebari configuration schema.", - type: "object", - properties: { - name: { - type: "string", - description: "The name of the package.", - examples: ["nebari"], - }, - description: { - type: "string", - description: "The description of the package.", - examples: ["A package manager for conda packages."], - }, - }, +type Schema = { + title: string; + description: string; + type: string; + properties: Properties; }; -// Main Component -export default function NebariJsonSchema({ toc = null }) { - const schemaURL = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; - const [schema, setSchema] = useState(NebariSchema); - const [resolved, setResolved] = useState(false); +const defaultSchema: Schema = { + "title": "Nebari Configuration", + "description": "The configuration schema for Nebari.", + "type": "object", + "properties": { + "deprecated": { + deprecated: true + } + } +}; + +function useSchema(schemaUrl: string) { + const [schema, setSchema] = useState(defaultSchema); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); useEffect(() => { - const fetchSchema = async () => { + async function fetchSchema() { try { - const response = await fetch(schemaURL, { headers: { Accept: "application/json" } }); + const response = await fetch(schemaUrl, { headers: { Accept: 'application/json' } }); const rawSchema = await response.json(); const resolver = new Resolver(); - const resolvedSchema = await resolver.resolve(rawSchema); + const resolvedSchema = await resolver.resolve(rawSchema, {}); setSchema(resolvedSchema.result); - setResolved(true); - } catch (error) { - console.error('Failed to fetch and resolve schema', error); + } catch (err) { + setError(err.message); + } finally { + setLoading(false); } - }; + } fetchSchema(); - }, []); + }, [schemaUrl]); + + return { schema, loading, error }; +} + +export default function NebariConfig({ toc = null }) { + const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; + const { schema, loading, error } = useSchema(schemaUrl); + + if (loading) return

Loading schema...

; + if (error) return

Error loading schema: {error}

; + if (!schema) return null; return ( <> - This documentation is autogenerated from{" "} - - Nebari config yaml's JSON Schema - . + This documentation is autogenerated from the Nebari configuration JSON Schema. + View the original schema. - - {schema.description} -

- {schema.properties && Object.entries(schema.properties).sort().map(([key, value]) => ( - - ))} + + + ); } -// Sub-Components -function SchemaToc({ schema }) { +function SchemaToc({ properties }: { properties: Properties }) { + const propertyEntries = Object.entries(properties).sort(); return (
    - {Object.entries(schema.properties).sort().map(([key, value]) => ( + {propertyEntries.map(([key, value]) => (
  • {value.deprecated ? {key} : key} @@ -81,56 +97,27 @@ function SchemaToc({ schema }) { ); } -function Setting({ name, value, withTypes = true, toc = null }) { - if (toc) { - toc.push({ value: name, id: name.replace(/_/g, "-"), level: 3 }); - } - +function PropertiesList({ properties }: { properties: Properties }) { return ( <> - - {value.deprecated ? {name} : name} - {value.deprecated && ( -

    - - Deprecated - -

    - )} - {value.description && {value.description.trim()}} - {withTypes && } - {value.examples && ( -
    - {value.examples.join(", ")} -
    - )} + {Object.entries(properties).map(([key, value]) => ( + + ))} ); } -function Type({ value }) { - const types = []; - const customTypes = { options: [] }; - - value.anyOf?.forEach(v => { - if (v.type) { - types.push({v.type}); - if (v.enum) { - customTypes.options.push(...v.enum.map(e => {e})); - } - } - }); - +function PropertyDetail({ name, property, level = 1 }: { name: string; property: SchemaProperty; level?: number }) { return ( <> - {types.length > 0 && Type: {types.reduce((prev, curr) => [prev, ', ', curr])}} - {value.default !== undefined && Default: {JSON.stringify(value.default)}} - {customTypes.options.length > 0 && ( - <> -
    - Options: {customTypes.options} - - )} + + + {property.deprecated ? {name} : name} + + {property.deprecated &&

    Deprecated

    } + {property.description && } ); } + +const Markdown = ({ text }: { text: string }) => {text}; From 7d5665671df1db6c398276294079e45fd2713da8 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Tue, 7 May 2024 09:57:37 -0300 Subject: [PATCH 03/13] update schema rendering & support for local run --- docs/docs/explanations/nebari-yaml-schema.mdx | 2 +- .../components/NebariSchemaLoader/index.tsx | 214 +++++++++++++----- 2 files changed, 158 insertions(+), 58 deletions(-) diff --git a/docs/docs/explanations/nebari-yaml-schema.mdx b/docs/docs/explanations/nebari-yaml-schema.mdx index bb160df06..bbcb47803 100644 --- a/docs/docs/explanations/nebari-yaml-schema.mdx +++ b/docs/docs/explanations/nebari-yaml-schema.mdx @@ -9,4 +9,4 @@ This section includes the Nebari configuration schema loaded dynamically below: import NebariConfig from '@site/src/components/NebariSchemaLoader'; - + diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 2702b16eb..e112e6eae 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -1,102 +1,102 @@ -import React, { useState, useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { Resolver } from '@stoplight/json-ref-resolver'; -import Heading from '@theme/Heading'; -import ReactMarkdown from 'react-markdown'; -import CodeBlock from '@theme/CodeBlock'; import Admonition from '@theme/Admonition'; +import Heading from '@theme/Heading'; import Details from '@theme/Details'; +import ReactMarkdown from 'react-markdown'; +import JSONSchema from '../../../static/nebari-config-schema.json' import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -// Define the correct schema type +const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; + type SchemaProperty = { deprecated?: boolean; description?: string; + type?: string | string[]; + pattern?: string; + title?: string; + items?: any; + properties?: { [key: string]: SchemaProperty }; + enum?: string[]; + default?: any; + allOf?: SchemaProperty[]; + examples?: string[]; + optionsAre?: string[]; }; -type Properties = { - [key: string]: SchemaProperty; -}; +type Properties = { [key: string]: SchemaProperty }; type Schema = { title: string; description: string; type: string; properties: Properties; + required?: string[]; }; const defaultSchema: Schema = { - "title": "Nebari Configuration", - "description": "The configuration schema for Nebari.", - "type": "object", - "properties": { - "deprecated": { - deprecated: true - } - } + title: "ConfigSchema", + description: "The configuration schema for Nebari.", + type: "object", + properties: {} }; -function useSchema(schemaUrl: string) { +function useSchema(schemaUrl: string, useLocal = false) { const [schema, setSchema] = useState(defaultSchema); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { - async function fetchSchema() { - try { - const response = await fetch(schemaUrl, { headers: { Accept: 'application/json' } }); - const rawSchema = await response.json(); - const resolver = new Resolver(); - const resolvedSchema = await resolver.resolve(rawSchema, {}); - setSchema(resolvedSchema.result); - } catch (err) { - setError(err.message); - } finally { - setLoading(false); + if (useLocal) { + setSchema(JSON.parse(JSON.stringify(JSONSchema))); + setLoading(false); + setError(null); + } else { + async function fetchSchema() { + try { + const response = await fetch(schemaUrl, { headers: { 'Accept': 'application/json' } }); + if (!response.ok) { + throw new Error(`Failed to fetch schema: ${response.status} ${response.statusText}`); + } + + const json = await response.json(); + const resolver = new Resolver(); + const resolvedSchema = await resolver.resolve(json, {}); + setSchema(resolvedSchema.result); + } catch (err) { + console.error('Error:', err); + setError(err.message); + } finally { + setLoading(false); + } } + + fetchSchema(); } - fetchSchema(); - }, [schemaUrl]); + }, [schemaUrl, useLocal]); // Added useLocal as a dependency return { schema, loading, error }; } -export default function NebariConfig({ toc = null }) { - const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; - const { schema, loading, error } = useSchema(schemaUrl); +export default function NebariConfig() { + const { schema, loading, error } = useSchema(schemaUrl, true); if (loading) return

    Loading schema...

    ; if (error) return

    Error loading schema: {error}

    ; - if (!schema) return null; return ( <> This documentation is autogenerated from the Nebari configuration JSON Schema. - View the original schema. + View the original schema. - ); } -function SchemaToc({ properties }: { properties: Properties }) { - const propertyEntries = Object.entries(properties).sort(); - return ( - - ); -} - function PropertiesList({ properties }: { properties: Properties }) { return ( <> @@ -107,17 +107,117 @@ function PropertiesList({ properties }: { properties: Properties }) { ); } -function PropertyDetail({ name, property, level = 1 }: { name: string; property: SchemaProperty; level?: number }) { - return ( +function PropertyDetail({ name, property }: { name: string; property: SchemaProperty }) { + const hasNestedProperties = property.properties && Object.keys(property.properties).length > 0; + const shouldUseDetails = (property.allOf && hasNestedProperties) || hasNestedProperties; + + const mergedProperty = shouldUseDetails ? mergeAllOf(property) : property; + + return shouldUseDetails ? ( +
    + + {mergedProperty.title || name} + + + {mergedProperty.properties && } +
    + ) : ( <> - - - {property.deprecated ? {name} : name} + + {property.title || name} + + {hasNestedProperties && } + + ); +} + +const MarkdownCodeSeparator = ({ examples, inputKey }) => { + // Function to extract the YAML code block and briefing paragraph from each example + const parseContent = (input) => { + const codeRegex = /```yaml[\s\S]*?```/; // Regex to match the YAML code block + const codeMatch = input.match(codeRegex); + + let codeBlock = ''; + if (codeMatch) { + // Extract code and remove the fencing + codeBlock = codeMatch[0].replace(/```yaml|```/g, '').trim(); + // Normalize indentation + const lines = codeBlock.split('\n'); + const minIndentation = lines.filter(line => line.trim()) + .reduce((min, line) => Math.min(min, line.search(/\S/)), Infinity); + codeBlock = lines.map(line => line.substring(minIndentation)).join('\n'); + } + + const briefing = input.replace(codeRegex, '').trim(); // Remove the code block from the briefing + + return { briefing, codeBlock }; + }; + + // Check if examples is defined and is an array + if (!Array.isArray(examples)) { + return
    No examples provided
    ; + } + + if (examples.length > 1) { + // Render content inside tabs when there are multiple examples + return ( + ({ label: `Example ${index + 1}`, value: `example-${index}` }))}> + {examples.map((example, index) => { + const { briefing, codeBlock } = parseContent(example); // Correct placement + return ( + +
    + {briefing} +
    +                                    {codeBlock}
    +                                
    +
    +
    + ); + })} +
    + ); + } else { + // If only one example, no need for tabs + const { briefing, codeBlock } = parseContent(examples[0]); + return ( +
    + {briefing} +
    +                    {codeBlock}
    +                
    +
    + ); + } +}; + +function PropertyContent({ property }: { property: SchemaProperty }) { + return ( + <> + {property.description && {property.description}} + {property.type &&

    Type: {Array.isArray(property.type) ? property.type.join(", ") : property.type}

    } + {property.default !== undefined &&

    Default: {JSON.stringify(property.default)}

    } + {property.enum &&

    Available options: {property.enum.join(", ")}

    } + {property.optionsAre &&

    Options: {property.optionsAre.join(", ")}

    } + {property.pattern &&

    Pattern: {property.pattern}

    } + {property.examples && } {property.deprecated &&

    Deprecated

    } - {property.description && } + ); } +function mergeAllOf(property: SchemaProperty): SchemaProperty { + if (!property.allOf) return property; + const base = { ...property, allOf: undefined }; + return property.allOf.reduce((acc, cur) => { + return { + ...acc, + ...mergeAllOf(cur), + properties: { ...acc.properties, ...cur.properties }, + }; + }, base); +} + const Markdown = ({ text }: { text: string }) => {text}; From df316ffb50ef67ab96a24a36df779bcbaf092f19 Mon Sep 17 00:00:00 2001 From: viniciusdc Date: Tue, 7 May 2024 17:48:35 -0300 Subject: [PATCH 04/13] Update schema mdx render components --- .../components/NebariSchemaLoader/index.tsx | 163 ++++++++++++------ 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index e112e6eae..3368a405d 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -1,12 +1,13 @@ -import React, { useEffect, useState } from 'react'; import { Resolver } from '@stoplight/json-ref-resolver'; import Admonition from '@theme/Admonition'; -import Heading from '@theme/Heading'; import Details from '@theme/Details'; -import ReactMarkdown from 'react-markdown'; -import JSONSchema from '../../../static/nebari-config-schema.json' -import Tabs from '@theme/Tabs'; +import Heading from '@theme/Heading'; import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import React, { useEffect, useState } from 'react'; +import ReactMarkdown from 'react-markdown'; + +import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -49,7 +50,10 @@ function useSchema(schemaUrl: string, useLocal = false) { useEffect(() => { if (useLocal) { - setSchema(JSON.parse(JSON.stringify(JSONSchema))); + const resolver = new Resolver(); + resolver.resolve(JSONSchema, {}).then((resolvedSchema) => { + setSchema(resolvedSchema.result); + }); setLoading(false); setError(null); } else { @@ -91,45 +95,61 @@ export default function NebariConfig() { This documentation is autogenerated from the Nebari configuration JSON Schema. View the original schema. + {/*
    +
    {JSON.stringify(schema, null, 2)}
    +
    */} ); } -function PropertiesList({ properties }: { properties: Properties }) { +function PropertieTitle({ title, subHeading = false, deprecated = false }) { + return ( +
    + + {title} {deprecated && Deprecated} + +
    + ); +} + +function PropertiesList({ properties, sub_heading = false }: { properties: Properties; sub_heading?: boolean }) { return ( <> {Object.entries(properties).map(([key, value]) => ( - +
    + {/* // if sub_heading is true, render a heading for each property as an + // h3, else render the property title as an h2 */} + + + {/* Check if value.allOf is defined and has entries */} + {value.allOf && value.allOf.length > 0 ? ( + value.allOf[0].properties ? ( +
    Available Options}> + {/* If the first item in allOf has properties, display them as a nested list */} + +
    + ) : null + ) : ( + null + )} +
    ))} ); } -function PropertyDetail({ name, property }: { name: string; property: SchemaProperty }) { - const hasNestedProperties = property.properties && Object.keys(property.properties).length > 0; - const shouldUseDetails = (property.allOf && hasNestedProperties) || hasNestedProperties; - - const mergedProperty = shouldUseDetails ? mergeAllOf(property) : property; - - return shouldUseDetails ? ( -
    - - {mergedProperty.title || name} - - - {mergedProperty.properties && } -
    - ) : ( - <> - - {property.title || name} - - - {hasNestedProperties && } - - ); +function mergeAllOf(property: SchemaProperty): SchemaProperty { + if (!property.allOf) return property; + // Start with a clone of the original property without the allOf key + const base = { ...property, allOf: undefined }; + // Merge all properties from the allOf array into the base + return property.allOf.reduce((acc, cur) => ({ + ...acc, + ...mergeAllOf(cur), // Recursively merge all nested allOf properties + properties: { ...acc.properties, ...cur.properties } // Merge nested properties separately + }), base); } const MarkdownCodeSeparator = ({ examples, inputKey }) => { @@ -192,32 +212,67 @@ const MarkdownCodeSeparator = ({ examples, inputKey }) => { } }; -function PropertyContent({ property }: { property: SchemaProperty }) { - return ( - <> - {property.description && {property.description}} - {property.type &&

    Type: {Array.isArray(property.type) ? property.type.join(", ") : property.type}

    } - {property.default !== undefined &&

    Default: {JSON.stringify(property.default)}

    } - {property.enum &&

    Available options: {property.enum.join(", ")}

    } - {property.optionsAre &&

    Options: {property.optionsAre.join(", ")}

    } - {property.pattern &&

    Pattern: {property.pattern}

    } - {property.examples && } - {property.deprecated &&

    Deprecated

    } +function PropertyContent({ property }) { + // Helper function to check if any table data is available + const hasTableData = property.type || property.default !== undefined || property.enum || property.optionsAre || property.pattern || property.deprecated; - + return ( +
    + {property.description && ( +
    + {property.description} +
    + )} + {hasTableData && ( + + + {property.type && ( + + + + + )} + {property.default !== undefined && ( + + + + + )} + {property.enum && ( + + + + + )} + {property.optionsAre && ( + + + + + )} + {property.pattern && ( + + + + + )} + +
    Type: + {Array.isArray(property.type) ? property.type.join(", ") : property.type} +
    Default: + {JSON.stringify(property.default)} +
    Available options:{property.enum.join(", ")}
    Options:{property.optionsAre.join(", ")}
    Pattern: + {property.pattern} +
    + )} + {property.examples && ( +
    + +
    + )} +
    ); } -function mergeAllOf(property: SchemaProperty): SchemaProperty { - if (!property.allOf) return property; - const base = { ...property, allOf: undefined }; - return property.allOf.reduce((acc, cur) => { - return { - ...acc, - ...mergeAllOf(cur), - properties: { ...acc.properties, ...cur.properties }, - }; - }, base); -} const Markdown = ({ text }: { text: string }) => {text}; From b2b48733af4bf65bf28ca3daeeb4f92ac2412d8d Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Tue, 7 May 2024 19:47:08 -0300 Subject: [PATCH 05/13] update schema rendering --- .../components/NebariSchemaLoader/index.tsx | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 3368a405d..120e0b48c 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -98,17 +98,40 @@ export default function NebariConfig() { {/*
    {JSON.stringify(schema, null, 2)}
    */} + ); } +function SchemaToc({ schema }) { + return ( + + ); +} + function PropertieTitle({ title, subHeading = false, deprecated = false }) { + const titleStyle = { + background: 'linear-gradient(to right, var(--ifm-color-primary) 0%, var(--ifm-color-primary) 5px, var(--ifm-admonition-background-color) 5px, var(--ifm-admonition-background-color) 100%)', + padding: '8px 15px', + borderRadius: '5px', + display: 'inline-block' + }; return (
    - {title} {deprecated && Deprecated} + + {title} {deprecated && Deprecated} +
    ); @@ -225,6 +248,14 @@ function PropertyContent({ property }) { )} {hasTableData && ( + {/* Adding CSS within the component */} + {property.type && ( From 9f1962004ecb77faf52f1fd3683c37816cff5c31 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Wed, 8 May 2024 00:24:05 -0300 Subject: [PATCH 06/13] add toc back and some fixes --- docs/src/components/NebariSchemaLoader/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 120e0b48c..b84d8f77a 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -24,6 +24,7 @@ type SchemaProperty = { allOf?: SchemaProperty[]; examples?: string[]; optionsAre?: string[]; + note?: string; }; type Properties = { [key: string]: SchemaProperty }; @@ -301,6 +302,11 @@ function PropertyContent({ property }) { )} + {property.note && ( + + + + )} ); } From ca249b5ebdb7a1759a128619421bdca3decf9f39 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Wed, 8 May 2024 00:24:45 -0300 Subject: [PATCH 07/13] enable PR preview --- docs/src/components/NebariSchemaLoader/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index b84d8f77a..fd0785076 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -7,7 +7,7 @@ import Tabs from '@theme/Tabs'; import React, { useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import JSONSchema from '../../../static/nebari-config-schema.json'; +// import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -85,7 +85,7 @@ function useSchema(schemaUrl: string, useLocal = false) { } export default function NebariConfig() { - const { schema, loading, error } = useSchema(schemaUrl, true); + const { schema, loading, error } = useSchema(schemaUrl, false); if (loading) return

    Loading schema...

    ; if (error) return

    Error loading schema: {error}

    ; From a20b7804c8e41d5b89948862bba443deaeae62ac Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Wed, 8 May 2024 23:55:04 -0300 Subject: [PATCH 08/13] udpate react component for better grouping and nested anyOf properties --- .../components/NebariSchemaLoader/index.tsx | 128 ++++++++++++++---- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index fd0785076..e609dee3e 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -22,9 +22,12 @@ type SchemaProperty = { enum?: string[]; default?: any; allOf?: SchemaProperty[]; + anyOf?: SchemaProperty[]; examples?: string[]; optionsAre?: string[]; note?: string; + depends_on?: string | object; + group_by?: string; }; type Properties = { [key: string]: SchemaProperty }; @@ -84,6 +87,17 @@ function useSchema(schemaUrl: string, useLocal = false) { return { schema, loading, error }; } +function ParentComponent({ schema }) { + return ( +
    + + + +
    + ); +} + + export default function NebariConfig() { const { schema, loading, error } = useSchema(schemaUrl, false); @@ -99,9 +113,7 @@ export default function NebariConfig() { {/*
    {JSON.stringify(schema, null, 2)}
    */} - - - + ); } @@ -138,44 +150,85 @@ function PropertieTitle({ title, subHeading = false, deprecated = false }) { ); } -function PropertiesList({ properties, sub_heading = false }: { properties: Properties; sub_heading?: boolean }) { +function mergeProperties(property, key) { + if (!property[key]) return property; + const base = { ...property, [key]: undefined }; + return property[key].reduce((acc, cur) => ({ + ...acc, + ...mergeProperties(cur, key), // Recursive call to handle nested structures + properties: { ...acc.properties, ...cur.properties } // Merge nested properties + }), base); +} + +function renderProperties(value, key, sub_heading) { + if (value[key] && value[key].length > 0 && value[key][0].properties) { + return ( +
    Available Options}> + +
    + ); + } + return null; +} + +function PropertiesList({ properties, sub_heading = false }) { + const groupedByTabs = {}; + const standaloneProperties = []; + + // Organize properties by group_by key + Object.entries(properties).forEach(([key, value]) => { + if (value.group_by) { + const groupKey = value.group_by; + if (!groupedByTabs[groupKey]) { + groupedByTabs[groupKey] = []; + } + groupedByTabs[groupKey].push({ key, value }); + } else { + standaloneProperties.push({ key, value }); + } + }); + return ( <> - {Object.entries(properties).map(([key, value]) => ( + {/* Render standalone properties */} + {standaloneProperties.map(({ key, value }) => (
    - {/* // if sub_heading is true, render a heading for each property as an - // h3, else render the property title as an h2 */} - {/* Check if value.allOf is defined and has entries */} - {value.allOf && value.allOf.length > 0 ? ( - value.allOf[0].properties ? ( -
    Available Options}> - {/* If the first item in allOf has properties, display them as a nested list */} - -
    - ) : null - ) : ( - null - )} + {renderProperties(value, 'allOf', sub_heading)} + {renderProperties(value, 'anyOf', sub_heading)} +
    + ))} + {/* Render grouped properties in tabs */} + {Object.entries(groupedByTabs).map(([groupKey, groupProps]) => ( +
    + + `\`${key}\``).join(', ')}) + are mutually exclusive. You can only use one of them at a time.`} /> + + + {/* {groupProps.map(({ key, value }) => ( + // + + + {renderProperties(value, 'allOf', sub_heading)} + {renderProperties(value, 'anyOf', sub_heading)} + {/* */} + {/* ))} */} + {groupProps.map(({ key, value }) => ( +
    + + + {renderProperties(value, 'allOf', sub_heading)} + {renderProperties(value, 'anyOf', sub_heading)} +
    + ))}
    ))} ); } -function mergeAllOf(property: SchemaProperty): SchemaProperty { - if (!property.allOf) return property; - // Start with a clone of the original property without the allOf key - const base = { ...property, allOf: undefined }; - // Merge all properties from the allOf array into the base - return property.allOf.reduce((acc, cur) => ({ - ...acc, - ...mergeAllOf(cur), // Recursively merge all nested allOf properties - properties: { ...acc.properties, ...cur.properties } // Merge nested properties separately - }), base); -} - const MarkdownCodeSeparator = ({ examples, inputKey }) => { // Function to extract the YAML code block and briefing paragraph from each example const parseContent = (input) => { @@ -242,6 +295,13 @@ function PropertyContent({ property }) { return (
    + {/* // For properties that contain the depends_on key, render a warning + // admonition to inform users that the property is dependent on another */} + {property.depends_on && ( + + + + )} {property.description && (
    {property.description} @@ -294,6 +354,14 @@ function PropertyContent({ property }) {
    )} + {property.depends_on && ( + + + + + )}
    Depends on: + {JSON.stringify(property.depends_on)} +
    )} From 217aed13dc7c3263f0a0035956f4013c49a7e7f9 Mon Sep 17 00:00:00 2001 From: viniciusdc Date: Thu, 9 May 2024 15:39:29 -0300 Subject: [PATCH 09/13] updates --- docs/src/components/NebariSchemaLoader/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index e609dee3e..ce64e9e0c 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -7,7 +7,7 @@ import Tabs from '@theme/Tabs'; import React, { useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -// import JSONSchema from '../../../static/nebari-config-schema.json'; +import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -99,7 +99,7 @@ function ParentComponent({ schema }) { export default function NebariConfig() { - const { schema, loading, error } = useSchema(schemaUrl, false); + const { schema, loading, error } = useSchema(schemaUrl, true); if (loading) return

    Loading schema...

    ; if (error) return

    Error loading schema: {error}

    ; From b8a2456642fbe1f9251b8bfcabb8e5de311ce2f7 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Thu, 30 May 2024 23:25:39 -0300 Subject: [PATCH 10/13] update to render example & better defaults --- .../components/NebariSchemaLoader/index.tsx | 199 ++++++++---------- docs/static/nebari-config-schema.json | 1 + 2 files changed, 93 insertions(+), 107 deletions(-) create mode 120000 docs/static/nebari-config-schema.json diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index ce64e9e0c..40e359c47 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -4,10 +4,10 @@ import Details from '@theme/Details'; import Heading from '@theme/Heading'; import TabItem from '@theme/TabItem'; import Tabs from '@theme/Tabs'; -import React, { useEffect, useState } from 'react'; +import React, { ReactElement, useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import JSONSchema from '../../../static/nebari-config-schema.json'; +// import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -99,7 +99,7 @@ function ParentComponent({ schema }) { export default function NebariConfig() { - const { schema, loading, error } = useSchema(schemaUrl, true); + const { schema, loading, error } = useSchema(schemaUrl, false); if (loading) return

    Loading schema...

    ; if (error) return

    Error loading schema: {error}

    ; @@ -118,7 +118,7 @@ export default function NebariConfig() { ); } -function SchemaToc({ schema }) { +function SchemaToc({ schema }: { schema: Schema }) { return (
      {Object.entries(schema.properties).sort().map(([key, value]) => ( @@ -172,57 +172,17 @@ function renderProperties(value, key, sub_heading) { } function PropertiesList({ properties, sub_heading = false }) { - const groupedByTabs = {}; - const standaloneProperties = []; - - // Organize properties by group_by key - Object.entries(properties).forEach(([key, value]) => { - if (value.group_by) { - const groupKey = value.group_by; - if (!groupedByTabs[groupKey]) { - groupedByTabs[groupKey] = []; - } - groupedByTabs[groupKey].push({ key, value }); - } else { - standaloneProperties.push({ key, value }); - } - }); - return ( <> {/* Render standalone properties */} - {standaloneProperties.map(({ key, value }) => ( + {Object.entries(properties).map(([key, value]) => ( + // Escape a new line after each property
      {renderProperties(value, 'allOf', sub_heading)} {renderProperties(value, 'anyOf', sub_heading)} -
      - ))} - {/* Render grouped properties in tabs */} - {Object.entries(groupedByTabs).map(([groupKey, groupProps]) => ( -
      - - `\`${key}\``).join(', ')}) - are mutually exclusive. You can only use one of them at a time.`} /> - - - {/* {groupProps.map(({ key, value }) => ( - // - - - {renderProperties(value, 'allOf', sub_heading)} - {renderProperties(value, 'anyOf', sub_heading)} - {/* */} - {/* ))} */} - {groupProps.map(({ key, value }) => ( -
      - - - {renderProperties(value, 'allOf', sub_heading)} - {renderProperties(value, 'anyOf', sub_heading)} -
      - ))} +
      ))} @@ -251,19 +211,22 @@ const MarkdownCodeSeparator = ({ examples, inputKey }) => { return { briefing, codeBlock }; }; - // Check if examples is defined and is an array - if (!Array.isArray(examples)) { + // Check if examples is defined and is either an array or an object + if (!examples || (typeof examples !== 'object')) { return
      No examples provided
      ; } - if (examples.length > 1) { + const exampleEntries = Array.isArray(examples) ? examples.map((example, index) => ({ label: `Example ${index + 1}`, value: example, key: `example-${index}` })) + : Object.entries(examples).map(([key, value]) => ({ label: key, value, key })); + + if (exampleEntries.length > 1) { // Render content inside tabs when there are multiple examples return ( - ({ label: `Example ${index + 1}`, value: `example-${index}` }))}> - {examples.map((example, index) => { - const { briefing, codeBlock } = parseContent(example); // Correct placement + ({ label: entry.label, value: entry.key }))}> + {exampleEntries.map((entry, index) => { + const { briefing, codeBlock } = parseContent(entry.value); // Correct placement return ( - +
      {briefing}
      @@ -277,7 +240,7 @@ const MarkdownCodeSeparator = ({ examples, inputKey }) => {
               );
           } else {
               // If only one example, no need for tabs
      -        const { briefing, codeBlock } = parseContent(examples[0]);
      +        const { briefing, codeBlock } = parseContent(exampleEntries[0].value);
               return (
                   
      {briefing} @@ -289,19 +252,80 @@ const MarkdownCodeSeparator = ({ examples, inputKey }) => { } }; -function PropertyContent({ property }) { - // Helper function to check if any table data is available - const hasTableData = property.type || property.default !== undefined || property.enum || property.optionsAre || property.pattern || property.deprecated; + +interface PropertyRowProps { + label: string; + value: any; + isPreFormatted?: boolean; +} + +const PropertyRow: React.FC = ({ label, value, isPreFormatted = false }) => { + if (value === undefined) return Not specified; + + const formattedValue = isPreFormatted + ? (label === 'Depends on' ? {JSON.stringify(value)} : +
      +                {JSON.stringify(value, null, 2)}
      +            
      ) + : {Array.isArray(value) ? value.join(", ") : String(value)}; + + return ( + + + {label}: + + + {value !== null ? formattedValue : Not specified} + + + ); +} + +interface Property { + type?: string; + enum?: string[]; + optionsAre?: string; + pattern?: string; + depends_on?: any; + default?: any; + description?: string; + examples?: string[]; + note?: string; + warning?: string; +} + +const DefaultValueRow: React.FC<{ property: Property }> = ({ property }) => { + const shouldUsePreFormat = (value: any) => typeof value === 'object'; + + return ( + <> + {property.type && } + {property.enum && } + {property.optionsAre && } + {property.pattern && } + {property.depends_on && } + {property.default !== undefined && ( + + )} + + ); +} + +const PropertyContent: React.FC<{ property: Property }> = ({ property }) => { + const hasTableData = property.type || property.default !== undefined || property.enum || + property.optionsAre || property.pattern || property.depends_on; return (
      - {/* // For properties that contain the depends_on key, render a warning - // admonition to inform users that the property is dependent on another */} - {property.depends_on && ( + {/* {property.depends_on && ( - )} + )} */} {property.description && (
      {property.description} @@ -318,50 +342,7 @@ function PropertyContent({ property }) { `} - {property.type && ( - - Type: - - {Array.isArray(property.type) ? property.type.join(", ") : property.type} - - - )} - {property.default !== undefined && ( - - Default: - - {JSON.stringify(property.default)} - - - )} - {property.enum && ( - - Available options: - {property.enum.join(", ")} - - )} - {property.optionsAre && ( - - Options: - {property.optionsAre.join(", ")} - - )} - {property.pattern && ( - - Pattern: - - {property.pattern} - - - )} - {property.depends_on && ( - - Depends on: - - {JSON.stringify(property.depends_on)} - - - )} + )} @@ -375,9 +356,13 @@ function PropertyContent({ property }) { )} + {property.warning && ( + + + + )}
      ); } - const Markdown = ({ text }: { text: string }) => {text}; diff --git a/docs/static/nebari-config-schema.json b/docs/static/nebari-config-schema.json new file mode 120000 index 000000000..7e7d53233 --- /dev/null +++ b/docs/static/nebari-config-schema.json @@ -0,0 +1 @@ +/Users/vinicius/Quansight/Projects/Nebari/nebari/nebari-config-schema.json \ No newline at end of file From 73aebb840626abedea2064af511cd29d09a53c54 Mon Sep 17 00:00:00 2001 From: "Vinicius D. Cerutti" <51954708+viniciusdc@users.noreply.github.com> Date: Thu, 30 May 2024 23:28:54 -0300 Subject: [PATCH 11/13] Delete docs/static/nebari-config-schema.json --- docs/static/nebari-config-schema.json | 1 - 1 file changed, 1 deletion(-) delete mode 120000 docs/static/nebari-config-schema.json diff --git a/docs/static/nebari-config-schema.json b/docs/static/nebari-config-schema.json deleted file mode 120000 index 7e7d53233..000000000 --- a/docs/static/nebari-config-schema.json +++ /dev/null @@ -1 +0,0 @@ -/Users/vinicius/Quansight/Projects/Nebari/nebari/nebari-config-schema.json \ No newline at end of file From 9e9ab040d2abd5fe632786082f65c42d23e8d8cf Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Mon, 3 Jun 2024 12:33:17 -0300 Subject: [PATCH 12/13] Include right-side toc --- docs/docs/explanations/nebari-yaml-schema.mdx | 2 +- .../components/NebariSchemaLoader/index.tsx | 103 +++++++++++------- 2 files changed, 66 insertions(+), 39 deletions(-) diff --git a/docs/docs/explanations/nebari-yaml-schema.mdx b/docs/docs/explanations/nebari-yaml-schema.mdx index bbcb47803..af77168bb 100644 --- a/docs/docs/explanations/nebari-yaml-schema.mdx +++ b/docs/docs/explanations/nebari-yaml-schema.mdx @@ -9,4 +9,4 @@ This section includes the Nebari configuration schema loaded dynamically below: import NebariConfig from '@site/src/components/NebariSchemaLoader'; - + diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 40e359c47..9eb08172c 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -7,7 +7,7 @@ import Tabs from '@theme/Tabs'; import React, { ReactElement, useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -// import JSONSchema from '../../../static/nebari-config-schema.json'; +import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -82,24 +82,24 @@ function useSchema(schemaUrl: string, useLocal = false) { fetchSchema(); } - }, [schemaUrl, useLocal]); // Added useLocal as a dependency + }, [schemaUrl, useLocal]); return { schema, loading, error }; } -function ParentComponent({ schema }) { +function ParentComponent({ schema, toc = null }) { return (
      - +
      ); } -export default function NebariConfig() { - const { schema, loading, error } = useSchema(schemaUrl, false); +export default function NebariConfig({ toc = null }) { + const { schema, loading, error } = useSchema(schemaUrl, true); if (loading) return

      Loading schema...

      ; if (error) return

      Error loading schema: {error}

      ; @@ -113,7 +113,7 @@ export default function NebariConfig() { {/*
      {JSON.stringify(schema, null, 2)}
      */} - + ); } @@ -123,7 +123,7 @@ function SchemaToc({ schema }: { schema: Schema }) {
        {Object.entries(schema.properties).sort().map(([key, value]) => (
      • - + {value.deprecated ? {key} : key}
      • @@ -132,7 +132,7 @@ function SchemaToc({ schema }: { schema: Schema }) { ); } -function PropertieTitle({ title, subHeading = false, deprecated = false }) { +function PropertyTitle({ title, subHeading = false, deprecated = false }) { const titleStyle = { background: 'linear-gradient(to right, var(--ifm-color-primary) 0%, var(--ifm-color-primary) 5px, var(--ifm-admonition-background-color) 5px, var(--ifm-admonition-background-color) 100%)', padding: '8px 15px', @@ -141,7 +141,7 @@ function PropertieTitle({ title, subHeading = false, deprecated = false }) { }; return (
        - + {title} {deprecated && Deprecated} @@ -150,40 +150,72 @@ function PropertieTitle({ title, subHeading = false, deprecated = false }) { ); } -function mergeProperties(property, key) { - if (!property[key]) return property; - const base = { ...property, [key]: undefined }; - return property[key].reduce((acc, cur) => ({ - ...acc, - ...mergeProperties(cur, key), // Recursive call to handle nested structures - properties: { ...acc.properties, ...cur.properties } // Merge nested properties - }), base); +function mergeProperties(property, keys) { + const base = { ...property }; + keys.forEach(key => { + if (!property[key]) { + return; + } + if (Array.isArray(property[key])) { + base[key] = undefined; // Clean up the base object by removing the processed key + base.properties = property[key].reduce((acc, cur) => { + let mergedProperties = { ...acc, ...cur.properties }; + return { ...acc, ...mergeProperties(cur, keys).properties, ...mergedProperties }; + }, base.properties || {}); + } else if (key === 'additionalProperties' && typeof property[key] === 'object') { + base.properties = { + ...base.properties, + ...mergeProperties(property[key], ['properties']).properties + }; + } + } + ); + return base; } -function renderProperties(value, key, sub_heading) { - if (value[key] && value[key].length > 0 && value[key][0].properties) { +function capitalizeFirstLetter(string) { + let base_string = string.replace(/_/g, " "); + return base_string.charAt(0).toUpperCase() + base_string.slice(1); +} + +function renderProperties(value, keys, sub_heading, settingKey = null) { + const mergedProperties = mergeProperties(value, keys).properties ?? {}; + if (Object.keys(mergedProperties).length > 0) { return ( -
        Available Options}> - +
        {capitalizeFirstLetter(settingKey)}: Available Options : Available Options}> +
        ); } return null; } -function PropertiesList({ properties, sub_heading = false }) { + +function Setting({ settingKey, value, subHeading, level = 1, toc = null }) { + if (toc) { + if (!toc.find((item) => item.value === settingKey)) { + toc.push({ + value: settingKey, + id: settingKey.replace(/_/g, "-").toLowerCase(), + level: level + 2, + }); + } + } + return ( +
        + + + {renderProperties(value, ['allOf', 'anyOf', 'additionalProperties'], subHeading)} +
        +
        + ); +} + +function PropertiesList({ properties, sub_heading = false, toc = null }) { return ( <> - {/* Render standalone properties */} - {Object.entries(properties).map(([key, value]) => ( - // Escape a new line after each property -
        - - - {renderProperties(value, 'allOf', sub_heading)} - {renderProperties(value, 'anyOf', sub_heading)} -
        -
        + {Object.entries(properties).sort().map(([key, value]) => ( + ))} ); @@ -321,11 +353,6 @@ const PropertyContent: React.FC<{ property: Property }> = ({ property }) => { return (
        - {/* {property.depends_on && ( - - - - )} */} {property.description && (
        {property.description} From ab3d893a23dab4c909746006bdfee1edf6109d6f Mon Sep 17 00:00:00 2001 From: viniciusdc Date: Mon, 3 Jun 2024 12:58:14 -0300 Subject: [PATCH 13/13] disable schema local import --- docs/src/components/NebariSchemaLoader/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/components/NebariSchemaLoader/index.tsx b/docs/src/components/NebariSchemaLoader/index.tsx index 9eb08172c..227df51d8 100644 --- a/docs/src/components/NebariSchemaLoader/index.tsx +++ b/docs/src/components/NebariSchemaLoader/index.tsx @@ -7,7 +7,7 @@ import Tabs from '@theme/Tabs'; import React, { ReactElement, useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import JSONSchema from '../../../static/nebari-config-schema.json'; +// import JSONSchema from '../../../static/nebari-config-schema.json'; const schemaUrl = "https://raw.githubusercontent.com/viniciusdc/nebari/nebari-schema-models/nebari-config-schema.json"; @@ -99,7 +99,7 @@ function ParentComponent({ schema, toc = null }) { export default function NebariConfig({ toc = null }) { - const { schema, loading, error } = useSchema(schemaUrl, true); + const { schema, loading, error } = useSchema(schemaUrl, false); if (loading) return

        Loading schema...

        ; if (error) return

        Error loading schema: {error}

        ;