diff --git a/.frontmatter/database/mediaDb.json b/.frontmatter/database/mediaDb.json index 42547567..a02ccc7a 100644 --- a/.frontmatter/database/mediaDb.json +++ b/.frontmatter/database/mediaDb.json @@ -1 +1 @@ -{"template":{}} \ No newline at end of file +{ "template": {} } diff --git a/.frontmatter/database/pinnedItemsDb.json b/.frontmatter/database/pinnedItemsDb.json index 9e26dfee..0967ef42 100644 --- a/.frontmatter/database/pinnedItemsDb.json +++ b/.frontmatter/database/pinnedItemsDb.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/.frontmatter/database/taxonomyDb.json b/.frontmatter/database/taxonomyDb.json index 9e26dfee..0967ef42 100644 --- a/.frontmatter/database/taxonomyDb.json +++ b/.frontmatter/database/taxonomyDb.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/.vscode/settings.json b/.vscode/settings.json index a41c27bf..bd590f00 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,9 @@ { - "[markdown]": { - }, - "typescript.surveys.enabled": false, - "typescript.disableAutomaticTypeAcquisition": true, - "output.smartScroll.enabled": false, - "problems.autoReveal": false, - "terminal.integrated.focusAfterRun": "terminal", - "biome.lspBin": null + "[markdown]": {}, + "typescript.surveys.enabled": false, + "typescript.disableAutomaticTypeAcquisition": true, + "output.smartScroll.enabled": false, + "problems.autoReveal": false, + "terminal.integrated.focusAfterRun": "terminal", + "biome.lspBin": null } diff --git a/bin/docstatic.js b/bin/docstatic.js index 6d665fa6..d24f122b 100755 --- a/bin/docstatic.js +++ b/bin/docstatic.js @@ -1,8 +1,8 @@ #!/usr/bin/env node const fs = require("fs-extra"); -const path = require("path"); -const { execSync } = require("child_process"); +const path = require("node:path"); +const { execSync } = require("node:child_process"); const projectName = process.argv[2]; if (!projectName) { diff --git a/biome.json b/biome.json index e3cf79f2..f0210ab0 100644 --- a/biome.json +++ b/biome.json @@ -4,25 +4,30 @@ "maxSize": 10485760, "includes": [ "**", - "!**/.next/**", - "!**/node_modules/**", - "!**/dist/**", - "!**/public/**", - "!**/content/**", - "!**/coverage/**", - "!**/tina/__generated__/**", + "!**/.next", + "!**/node_modules", + "!**/dist", + "!**/public", + "!**/content", + "!**/coverage", + "!**/tina/__generated__", "!**/tina/tina-lock.json", - "!**/src/styles/**", + "!**/src/styles", "!**/reuse/code-files.json", "!**/reuse/snippets-files.json", "!**/reuse/media/index.json", "!**/src/data/docs-metadata.json", - "!**/config/**/*.json" + "!**/config/**/*.json", + "!**/static/admin", + "!**/build", + "!**/.docusaurus", + "!**/src/css/theme-variables.css", + "!**/update-manifest.json" ] }, "overrides": [ { - "includes": ["scripts/**", "bin/**", "create-docstatic/**"], + "includes": ["**/scripts/**", "**/bin/**", "**/create-docstatic/**"], "linter": { "rules": { "suspicious": { @@ -30,6 +35,16 @@ } } } + }, + { + "includes": ["**/src/css/custom.css"], + "linter": { + "rules": { + "style": { + "noDescendingSpecificity": "off" + } + } + } } ], "formatter": { @@ -53,7 +68,7 @@ "linter": { "enabled": true, "rules": { - "recommended": true, + "preset": "recommended", "suspicious": { "noConsole": "error", "noExplicitAny": "off", @@ -79,7 +94,8 @@ "complexity": { "noForEach": "error", "useOptionalChain": "error", - "noBannedTypes": "off" + "noBannedTypes": "off", + "noImportantStyles": "off" } } }, @@ -94,6 +110,7 @@ "quoteStyle": "double", "attributePosition": "auto", "bracketSpacing": true - } + }, + "jsxRuntime": "reactClassic" } } diff --git a/create-docstatic/index.js b/create-docstatic/index.js index 55a5eaab..2cecf737 100644 --- a/create-docstatic/index.js +++ b/create-docstatic/index.js @@ -1,9 +1,9 @@ #!/usr/bin/env node -const fs = require("fs"); -const os = require("os"); -const path = require("path"); -const { execSync, execFileSync } = require("child_process"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { execSync, execFileSync } = require("node:child_process"); const HELP = ` Usage: npx create-docstatic@latest [options] @@ -38,6 +38,33 @@ function fail(message) { process.exit(1); } +// Minimal numeric semver compare; enough for the x.y.z versions we publish. +function compareVersions(a, b) { + const pa = String(a).split("-")[0].split(".").map(Number); + const pb = String(b).split("-")[0].split(".").map(Number); + for (let i = 0; i < 3; i++) { + const d = (pa[i] || 0) - (pb[i] || 0); + if (d !== 0) return d < 0 ? -1 : 1; + } + return 0; +} + +// A docstatic release can require a newer CLI than the one being run — for +// example when the template starts shipping a file under a new name that only +// a newer CLI knows to rename. Refuse by name rather than producing a subtly +// broken site. Manifests without the field predate the check and are allowed. +function assertManifestSupported(manifest) { + const required = manifest.minCreateVersion; + if (!required) return; + const current = require("./package.json").version; + if (compareVersions(current, required) < 0) { + fail( + `This docstatic release needs create-docstatic ${required} or later, but you are running ${current}.\n` + + "Re-run with: npx create-docstatic@latest" + ); + } +} + function parseArgs(argv) { const options = { projectName: null, @@ -248,13 +275,18 @@ function runUpdate(options) { ); } const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + assertManifestSupported(manifest); const templateDir = path.join(packageDir, "template"); + // Some files ship under a different name than they take in the site (see + // renameFiles in the manifest, e.g. biome.template.json -> biome.json). + const renames = manifest.renameFiles || {}; const copy = (rel) => { const src = path.join(templateDir, rel); - const dest = path.join(siteDir, rel); + const destRel = renames[rel] || rel; + const dest = path.join(siteDir, destRel); if (!fs.existsSync(src) || filesEqual(src, dest)) return; - log(fs.existsSync(dest) ? "update" : "add", rel); + log(fs.existsSync(dest) ? "update" : "add", destRel); if (dryRun) return; fs.mkdirSync(path.dirname(dest), { recursive: true }); fs.copyFileSync(src, dest); @@ -378,6 +410,13 @@ function main() { const packageDir = downloadTemplate(options.tag, tmpDir); const templateDir = resolveTemplateDir(packageDir, options.template); + // Checked before anything is written, so a refusal leaves no debris. + const scaffoldManifestPath = path.join(packageDir, "update-manifest.json"); + const scaffoldManifest = fs.existsSync(scaffoldManifestPath) + ? JSON.parse(fs.readFileSync(scaffoldManifestPath, "utf8")) + : null; + if (scaffoldManifest) assertManifestSupported(scaffoldManifest); + console.log(`Creating a new docStatic site in ${targetDir}...`); fs.mkdirSync(targetDir, { recursive: true }); fs.cpSync(templateDir, targetDir, { recursive: true }); @@ -389,6 +428,45 @@ function main() { fs.renameSync(gitignorePath, path.join(targetDir, ".gitignore")); } + // Files the template ships under a different name (biome.template.json -> + // biome.json, so Biome does not discover it inside the docstatic repo). + if (scaffoldManifest) { + const renameFiles = scaffoldManifest.renameFiles || {}; + for (const [from, to] of Object.entries(renameFiles)) { + const fromPath = path.join(targetDir, from); + if (fs.existsSync(fromPath)) { + fs.renameSync(fromPath, path.join(targetDir, to)); + } + } + + // Every declared rename must have landed. Without this a mismatch + // between the manifest and this CLI ships a site missing the renamed + // file entirely (a scaffolded site with no biome.json, say) and says + // nothing about it. + for (const [from, to] of Object.entries(renameFiles)) { + if (fs.existsSync(path.join(targetDir, from))) { + fail(`Template file "${from}" was not renamed to "${to}".`); + } + if (!fs.existsSync(path.join(targetDir, to))) { + fail( + `Template file "${to}" is missing after renaming from "${from}".` + ); + } + } + + // Catch-all for a *.template.json added to the template but never + // declared in renameFiles. + const stray = fs + .readdirSync(targetDir) + .filter((f) => f.endsWith(".template.json")); + if (stray.length) { + fail( + `Template shipped ${stray.join(", ")} without a renameFiles entry. ` + + "This is a docstatic packaging bug; try npx create-docstatic@latest." + ); + } + } + const packageJsonPath = path.join(targetDir, "package.json"); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); diff --git a/create-docstatic/package.json b/create-docstatic/package.json index 29607b03..7a1558aa 100644 --- a/create-docstatic/package.json +++ b/create-docstatic/package.json @@ -1,6 +1,6 @@ { "name": "create-docstatic", - "version": "0.2.0", + "version": "0.2.1", "description": "Create a docStatic documentation site with one command.", "author": "aowendev ", "license": "MIT", diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 0e47fbcf..37b9b342 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -1,13 +1,12 @@ -import remarkMath from 'remark-math'; -import rehypeKatex from 'rehype-katex'; -import { themes } from 'prism-react-renderer'; - -import PrismLight from './src/utils/prismLight'; -import PrismDark from './src/utils/prismDark'; +import { themes } from "prism-react-renderer"; +import rehypeKatex from "rehype-katex"; +import remarkMath from "remark-math"; +import PrismDark from "./src/utils/prismDark"; +import PrismLight from "./src/utils/prismLight"; // Import the blog date filter utility // eslint-disable-next-line @typescript-eslint/no-var-requires -const { getFutureDatedBlogFiles } = require('./src/plugins/blog-date-filter'); +const { getFutureDatedBlogFiles } = require("./src/plugins/blog-date-filter"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createConfig; @@ -16,29 +15,52 @@ const docusaurusData = require("./config/docusaurus/index.json"); // Function to map theme names to actual theme objects const getTheme = (themeName: string) => { switch (themeName) { - case 'github': return themes.github; - case 'vsLight': return themes.vsLight; - case 'vsDark': return themes.vsDark; - case 'dracula': return themes.dracula; - case 'nightOwl': return themes.nightOwl; - case 'nightOwlLight': return themes.nightOwlLight; - case 'oceanicNext': return themes.oceanicNext; - case 'oneLight': return themes.oneLight; - case 'oneDark': return themes.oneDark; - case 'duotoneLight': return themes.duotoneLight; - case 'duotoneDark': return themes.duotoneDark; - case 'gruvboxMaterialLight': return themes.gruvboxMaterialLight; - case 'gruvboxMaterialDark': return themes.gruvboxMaterialDark; - case 'jettwaveLight': return themes.jettwaveLight; - case 'jettwaveDark': return themes.jettwaveDark; - case 'okaidia': return themes.okaidia; - case 'palenight': return themes.palenight; - case 'shadesOfPurple': return themes.shadesOfPurple; - case 'synthwave84': return themes.synthwave84; - case 'ultramin': return themes.ultramin; - case 'prismLight': return PrismLight; - case 'prismDark': return PrismDark; - default: return themes.github; + case "github": + return themes.github; + case "vsLight": + return themes.vsLight; + case "vsDark": + return themes.vsDark; + case "dracula": + return themes.dracula; + case "nightOwl": + return themes.nightOwl; + case "nightOwlLight": + return themes.nightOwlLight; + case "oceanicNext": + return themes.oceanicNext; + case "oneLight": + return themes.oneLight; + case "oneDark": + return themes.oneDark; + case "duotoneLight": + return themes.duotoneLight; + case "duotoneDark": + return themes.duotoneDark; + case "gruvboxMaterialLight": + return themes.gruvboxMaterialLight; + case "gruvboxMaterialDark": + return themes.gruvboxMaterialDark; + case "jettwaveLight": + return themes.jettwaveLight; + case "jettwaveDark": + return themes.jettwaveDark; + case "okaidia": + return themes.okaidia; + case "palenight": + return themes.palenight; + case "shadesOfPurple": + return themes.shadesOfPurple; + case "synthwave84": + return themes.synthwave84; + case "ultramin": + return themes.ultramin; + case "prismLight": + return PrismLight; + case "prismDark": + return PrismDark; + default: + return themes.github; } }; const getPageRoute = (page: string) => { @@ -55,7 +77,13 @@ type FooterItem = | { title: any; items: FooterItem[] } | { label: any; to?: any; href?: any }; -const formatFooterItem = (item: { title: any; items: any[]; label: any; to: any; href: any; }): FooterItem => { +const formatFooterItem = (item: { + title: any; + items: any[]; + label: any; + to: any; + href: any; +}): FooterItem => { if (item.title) { return { title: item.title, @@ -145,12 +173,12 @@ const config = { hooks: { onBrokenMarkdownLinks: "warn", }, - preprocessor: ({fileContent, filePath}: {fileContent: string; filePath: string}) => { + preprocessor: ({ fileContent }: { fileContent: string }) => { // Convert markers to MDX comments before compilation. // Tina CMS writes but Docusaurus expects {/* truncate */}. // The truncateMarker regex in the blog plugin handles the actual split // for list-view truncation *before* this runs, so removing it here is safe. - return fileContent.replace(//g, '{/* truncate */}'); + return fileContent.replace(//g, "{/* truncate */}"); }, }, title: docusaurusData.title, @@ -169,14 +197,14 @@ const config = { stylesheets: [ { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', + href: "https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css", + type: "text/css", integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', + "sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM", + crossorigin: "anonymous", }, ], - + // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want // to replace "en" with "zh-Hans". @@ -194,7 +222,13 @@ const config = { remarkPlugins: [remarkMath], rehypePlugins: [rehypeKatex], // Remove this to remove the "edit this page" links. - editUrl: ({ versionDocsDirPath, docPath }: { versionDocsDirPath: string; docPath: string }) => { + editUrl: ({ + versionDocsDirPath, + docPath, + }: { + versionDocsDirPath: string; + docPath: string; + }) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const _unused = versionDocsDirPath; // docPath gives us the file path relative to docs directory @@ -212,7 +246,7 @@ const config = { blog: { exclude: (() => { // Get the absolute path to the blog directory - const blogDir = require('path').resolve(__dirname, 'blog'); + const blogDir = require("node:path").resolve(__dirname, "blog"); return getFutureDatedBlogFiles(blogDir); })(), showReadingTime: docusaurusData.showReadingTime, @@ -253,7 +287,8 @@ const config = { colorMode: { defaultMode: docusaurusData.colorMode?.defaultMode, disableSwitch: docusaurusData.colorMode?.disableSwitch, - respectPrefersColorScheme: docusaurusData.colorMode?.respectPrefersColorScheme, + respectPrefersColorScheme: + docusaurusData.colorMode?.respectPrefersColorScheme, }, docs: { sidebar: { @@ -275,12 +310,12 @@ const config = { }), copyright: `Copyright Ā© ${new Date().getFullYear()} ${docusaurusData.footer?.copyright}`, }, - prism: { - additionalLanguages: docusaurusData.prism?.additionalLanguages, - magicComments: docusaurusData.prism?.magicComments, - theme: getTheme(docusaurusData.prism.theme), - darkTheme: getTheme(docusaurusData.prism.darkTheme), - }, + prism: { + additionalLanguages: docusaurusData.prism?.additionalLanguages, + magicComments: docusaurusData.prism?.magicComments, + theme: getTheme(docusaurusData.prism.theme), + darkTheme: getTheme(docusaurusData.prism.darkTheme), + }, languageTabs: (() => { // Define all available language configurations const availableLanguages = { @@ -383,11 +418,13 @@ const config = { }; // Get selected languages from global languageTabs setting - const selectedLanguages = docusaurusData.openapi?.languageTabs as Array; - + const selectedLanguages = docusaurusData.openapi?.languageTabs as Array< + keyof typeof availableLanguages + >; + // Map selected languages to their full configurations return selectedLanguages - .map(lang => availableLanguages[lang]) + .map((lang) => availableLanguages[lang]) .filter(Boolean); // Remove any undefined entries })(), }, @@ -399,8 +436,26 @@ const config = { id: "openapi", docsPluginId: "classic", config: (() => { - const config: { [key: string]: { specPath: string; outputDir: string; downloadUrl?: string; tagTemplate?: string; sidebarOptions: { groupPathsBy: string; categoryLinkSource: string } } } = {}; - const apis: Array<{ name: string; specPath: string; outputDir: string; downloadUrl?: string; groupPathsBy?: string; categoryLinkSource?: string }> = docusaurusData.openapi?.apis || []; + const config: { + [key: string]: { + specPath: string; + outputDir: string; + downloadUrl?: string; + tagTemplate?: string; + sidebarOptions: { + groupPathsBy: string; + categoryLinkSource: string; + }; + }; + } = {}; + const apis: Array<{ + name: string; + specPath: string; + outputDir: string; + downloadUrl?: string; + groupPathsBy?: string; + categoryLinkSource?: string; + }> = docusaurusData.openapi?.apis || []; for (const api of apis) { config[api.name] = { @@ -414,7 +469,7 @@ const config = { }, }; } - + return config; })(), }, diff --git a/frontmatter.json b/frontmatter.json index f51058ba..458071d0 100644 --- a/frontmatter.json +++ b/frontmatter.json @@ -73,4 +73,4 @@ "tags", "authors" ] -} \ No newline at end of file +} diff --git a/mcp-server/claude-config.json b/mcp-server/claude-config.jsonc similarity index 91% rename from mcp-server/claude-config.json rename to mcp-server/claude-config.jsonc index 8bc448be..49601929 100644 --- a/mcp-server/claude-config.json +++ b/mcp-server/claude-config.jsonc @@ -11,7 +11,7 @@ // Instructions for use: // // 1. Update the "cwd" path above to match your docstatic project location -// +// // 2. For Claude Desktop, add this to your MCP settings file: // macOS: ~/Library/Application Support/Claude/claude_desktop_config.json // Windows: %APPDATA%/Claude/claude_desktop_config.json @@ -21,4 +21,4 @@ // - Have your docStatic dev server running: npm run dev // - Start the MCP server: npm run mcp:start (in a separate terminal) // -// 4. Restart Claude Desktop after adding this configuration \ No newline at end of file +// 4. Restart Claude Desktop after adding this configuration diff --git a/mcp-server/src/server.ts b/mcp-server/src/server.ts index b9bf5098..e7c380f6 100644 --- a/mcp-server/src/server.ts +++ b/mcp-server/src/server.ts @@ -1,11 +1,11 @@ -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, -} from '@modelcontextprotocol/sdk/types.js'; +} from "@modelcontextprotocol/sdk/types.js"; interface Document { _sys: { @@ -22,23 +22,17 @@ interface Document { _values?: any; } -interface DocumentConnection { - edges: { - node: Document; - }[]; -} - class DocStaticMCPServer { private graphqlUrl: string; private server: Server; - constructor(graphqlUrl = 'http://localhost:4001/graphql') { + constructor(graphqlUrl = "http://localhost:4001/graphql") { this.graphqlUrl = graphqlUrl; - + this.server = new Server( { - name: 'docstatic-server', - version: '1.0.0', + name: "docstatic-server", + version: "1.0.0", }, { capabilities: { @@ -52,36 +46,34 @@ class DocStaticMCPServer { } private async executeGraphQL(query: string, variables?: any): Promise { - try { - const response = await fetch(this.graphqlUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - query, - variables, - }), - }); - - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } + const response = await fetch(this.graphqlUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + query, + variables, + }), + }); - const result = await response.json(); - - if (result.errors) { - throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`); - } + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } - return result.data; - } catch (error) { - console.error('GraphQL execution error:', error); - throw error; + const result = await response.json(); + + if (result.errors) { + throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`); } + + return result.data; } - private async searchDocuments(query: string, limit = 20): Promise { + private async searchDocuments( + query: string, + limit = 20 + ): Promise { const graphqlQuery = ` query SearchDocuments($first: Float) { docConnection(first: $first, sort: "title") { @@ -107,11 +99,13 @@ class DocStaticMCPServer { // Filter documents by search query const searchTerm = query.toLowerCase(); return documents.filter((doc: Document) => { - const bodyText = typeof doc.body === 'string' ? doc.body : JSON.stringify(doc.body); + const bodyText = + typeof doc.body === "string" ? doc.body : JSON.stringify(doc.body); return ( doc.title.toLowerCase().includes(searchTerm) || bodyText.toLowerCase().includes(searchTerm) || - (doc._values && JSON.stringify(doc._values).toLowerCase().includes(searchTerm)) + (doc._values && + JSON.stringify(doc._values).toLowerCase().includes(searchTerm)) ); }); } @@ -135,8 +129,7 @@ class DocStaticMCPServer { try { const data = await this.executeGraphQL(graphqlQuery, { relativePath }); return data.doc; - } catch (error) { - console.error(`Failed to get document ${relativePath}:`, error); + } catch { return null; } } @@ -176,11 +169,17 @@ class DocStaticMCPServer { private extractMDXComponents(content: string): string[] { const componentMatches = content.match(/<[A-Z][a-zA-Z0-9]*[^>]*>/g) || []; - const uniqueComponents = [...new Set(componentMatches.map(match => { - const componentName = match.match(/<([A-Z][a-zA-Z0-9]*)/)?.[1]; - return componentName; - }).filter(Boolean))]; - + const uniqueComponents = [ + ...new Set( + componentMatches + .map((match) => { + const componentName = match.match(/<([A-Z][a-zA-Z0-9]*)/)?.[1]; + return componentName; + }) + .filter(Boolean) + ), + ]; + return uniqueComponents as string[]; } @@ -190,79 +189,83 @@ class DocStaticMCPServer { return { tools: [ { - name: 'search_documents', - description: 'Search through docStatic documentation using keywords', + name: "search_documents", + description: + "Search through docStatic documentation using keywords", inputSchema: { - type: 'object', + type: "object", properties: { query: { - type: 'string', - description: 'Search query to find relevant documents', + type: "string", + description: "Search query to find relevant documents", }, limit: { - type: 'number', - description: 'Maximum number of results to return (default: 20)', + type: "number", + description: + "Maximum number of results to return (default: 20)", default: 20, }, }, - required: ['query'], + required: ["query"], }, }, { - name: 'get_document', - description: 'Get a specific document by its relative path', + name: "get_document", + description: "Get a specific document by its relative path", inputSchema: { - type: 'object', + type: "object", properties: { path: { - type: 'string', - description: 'Relative path to the document (e.g., "installation.mdx")', + type: "string", + description: + 'Relative path to the document (e.g., "installation.mdx")', }, }, - required: ['path'], + required: ["path"], }, }, { - name: 'list_all_documents', - description: 'List all available documents with metadata', + name: "list_all_documents", + description: "List all available documents with metadata", inputSchema: { - type: 'object', + type: "object", properties: {}, }, }, { - name: 'get_documents_by_tag', - description: 'Get documents filtered by a specific tag', + name: "get_documents_by_tag", + description: "Get documents filtered by a specific tag", inputSchema: { - type: 'object', + type: "object", properties: { tag: { - type: 'string', - description: 'Tag to filter documents by', + type: "string", + description: "Tag to filter documents by", }, }, - required: ['tag'], + required: ["tag"], }, }, { - name: 'analyze_mdx_components', - description: 'Analyze MDX components used in a document', + name: "analyze_mdx_components", + description: "Analyze MDX components used in a document", inputSchema: { - type: 'object', + type: "object", properties: { path: { - type: 'string', - description: 'Relative path to the document to analyze', + type: "string", + description: "Relative path to the document to analyze", }, }, - required: ['path'], + required: ["path"], }, }, { - name: 'check_server_status', - description: 'Check if the GraphQL server is running and accessible', + name: "check_server_status", + description: + "Check if the GraphQL server is running and accessible", inputSchema: { - type: 'object', + type: "object", properties: {}, }, }, @@ -276,38 +279,49 @@ class DocStaticMCPServer { const { name, arguments: args } = request.params; switch (name) { - case 'search_documents': { - const { query, limit = 20 } = args as { query: string; limit?: number }; + case "search_documents": { + const { query, limit = 20 } = args as { + query: string; + limit?: number; + }; const results = await this.searchDocuments(query, limit); - + return { content: [ { - type: 'text', - text: JSON.stringify({ - query, - resultCount: results.length, - documents: results.map(doc => ({ - path: doc._sys.relativePath, - title: doc.title, - lastModified: doc.lastmod, - preview: (typeof doc.body === 'string' ? doc.body : JSON.stringify(doc.body)).substring(0, 200) + '...', - })), - }, null, 2), + type: "text", + text: JSON.stringify( + { + query, + resultCount: results.length, + documents: results.map((doc) => ({ + path: doc._sys.relativePath, + title: doc.title, + lastModified: doc.lastmod, + preview: `${( + typeof doc.body === "string" + ? doc.body + : JSON.stringify(doc.body) + ).substring(0, 200)}...`, + })), + }, + null, + 2 + ), }, ], }; } - case 'get_document': { + case "get_document": { const { path } = args as { path: string }; const document = await this.getDocument(path); - + if (!document) { return { content: [ { - type: 'text', + type: "text", text: `Document not found: ${path}`, }, ], @@ -317,71 +331,86 @@ class DocStaticMCPServer { return { content: [ { - type: 'text', - text: JSON.stringify({ - path: document._sys.relativePath, - title: document.title, - lastModified: document.lastmod, - content: document.body, - metadata: document._values, - }, null, 2), + type: "text", + text: JSON.stringify( + { + path: document._sys.relativePath, + title: document.title, + lastModified: document.lastmod, + content: document.body, + metadata: document._values, + }, + null, + 2 + ), }, ], }; } - case 'list_all_documents': { + case "list_all_documents": { const documents = await this.getAllDocuments(); - + return { content: [ { - type: 'text', - text: JSON.stringify({ - totalDocuments: documents.length, - documents: documents.map(doc => ({ - path: doc._sys.relativePath, - title: doc.title, - lastModified: doc.lastmod, - wordCount: (typeof doc.body === 'string' ? doc.body : JSON.stringify(doc.body)).split(' ').length, - })), - }, null, 2), + type: "text", + text: JSON.stringify( + { + totalDocuments: documents.length, + documents: documents.map((doc) => ({ + path: doc._sys.relativePath, + title: doc.title, + lastModified: doc.lastmod, + wordCount: (typeof doc.body === "string" + ? doc.body + : JSON.stringify(doc.body) + ).split(" ").length, + })), + }, + null, + 2 + ), }, ], }; } - case 'get_documents_by_tag': { + case "get_documents_by_tag": { const { tag } = args as { tag: string }; const documents = await this.getDocumentsByTag(tag); - + return { content: [ { - type: 'text', - text: JSON.stringify({ - tag, - documentCount: documents.length, - documents: documents.map(doc => ({ - path: doc._sys.relativePath, - title: doc.title, - lastModified: doc.lastmod, - })), - }, null, 2), + type: "text", + text: JSON.stringify( + { + tag, + documentCount: documents.length, + documents: documents.map((doc) => ({ + path: doc._sys.relativePath, + title: doc.title, + lastModified: doc.lastmod, + })), + }, + null, + 2 + ), }, ], }; } - case 'analyze_mdx_components': { + case "analyze_mdx_components": { const { path } = args as { path: string }; const document = await this.getDocument(path); - + if (!document) { return { content: [ { - type: 'text', + type: "text", text: `Document not found: ${path}`, }, ], @@ -389,36 +418,44 @@ class DocStaticMCPServer { } const components = this.extractMDXComponents(document.body); - + return { content: [ { - type: 'text', - text: JSON.stringify({ - path: document._sys.relativePath, - title: document.title, - mdxComponents: components, - componentCount: components.length, - }, null, 2), + type: "text", + text: JSON.stringify( + { + path: document._sys.relativePath, + title: document.title, + mdxComponents: components, + componentCount: components.length, + }, + null, + 2 + ), }, ], }; } - case 'check_server_status': { + case "check_server_status": { try { const query = `query { __typename }`; await this.executeGraphQL(query); - + return { content: [ { - type: 'text', - text: JSON.stringify({ - status: 'connected', - endpoint: this.graphqlUrl, - message: 'GraphQL server is running and accessible', - }, null, 2), + type: "text", + text: JSON.stringify( + { + status: "connected", + endpoint: this.graphqlUrl, + message: "GraphQL server is running and accessible", + }, + null, + 2 + ), }, ], }; @@ -426,12 +463,19 @@ class DocStaticMCPServer { return { content: [ { - type: 'text', - text: JSON.stringify({ - status: 'error', - endpoint: this.graphqlUrl, - message: error instanceof Error ? error.message : 'Unknown error', - }, null, 2), + type: "text", + text: JSON.stringify( + { + status: "error", + endpoint: this.graphqlUrl, + message: + error instanceof Error + ? error.message + : "Unknown error", + }, + null, + 2 + ), }, ], }; @@ -442,11 +486,12 @@ class DocStaticMCPServer { throw new Error(`Unknown tool: ${name}`); } } catch (error) { - const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + const errorMessage = + error instanceof Error ? error.message : "Unknown error occurred"; return { content: [ { - type: 'text', + type: "text", text: `Error: ${errorMessage}`, }, ], @@ -459,47 +504,49 @@ class DocStaticMCPServer { return { resources: [ { - uri: 'docstatic://documents', - name: 'All Documents', - description: 'Complete list of all documentation files', - mimeType: 'application/json', + uri: "docstatic://documents", + name: "All Documents", + description: "Complete list of all documentation files", + mimeType: "application/json", }, ], }; }); // Read resources - this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - const { uri } = request.params; + this.server.setRequestHandler( + ReadResourceRequestSchema, + async (request) => { + const { uri } = request.params; + + if (uri === "docstatic://documents") { + const documents = await this.getAllDocuments(); + + return { + contents: [ + { + uri, + mimeType: "application/json", + text: JSON.stringify(documents, null, 2), + }, + ], + }; + } - if (uri === 'docstatic://documents') { - const documents = await this.getAllDocuments(); - - return { - contents: [ - { - uri, - mimeType: 'application/json', - text: JSON.stringify(documents, null, 2), - }, - ], - }; + throw new Error(`Unknown resource: ${uri}`); } - - throw new Error(`Unknown resource: ${uri}`); - }); + ); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); - console.error('docStatic MCP server running on stdio'); } } // Create and run the server const server = new DocStaticMCPServer(); server.run().catch((error) => { - console.error('Server error:', error); - process.exit(1); + process.exitCode = 1; + throw error; }); diff --git a/mcp-server/test.js b/mcp-server/test.js index 7d55aa07..95600419 100755 --- a/mcp-server/test.js +++ b/mcp-server/test.js @@ -3,42 +3,34 @@ /** * Test script for the docStatic MCP Server * This script verifies the server can connect to GraphQL and retrieve documents + * + * Reports via exit code and a thrown error, not stdout: + * exit 0 prerequisites are met + * exit 1 GraphQL unreachable or the document query failed */ -const GRAPHQL_URL = 'http://localhost:4001/graphql'; +const GRAPHQL_URL = "http://localhost:4001/graphql"; async function testGraphQLConnection() { - console.log('šŸ” Testing GraphQL connection...'); - - try { - const response = await fetch(GRAPHQL_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - query: '{ __typename }' - }), - }); + const response = await fetch(GRAPHQL_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "{ __typename }" }), + }).catch((error) => { + throw new Error( + `Cannot reach the GraphQL server at ${GRAPHQL_URL}. Run "npm run dev" in the main docstatic directory first. (${error.message})` + ); + }); - if (response.ok) { - console.log('āœ… GraphQL server is running'); - return true; - } else { - console.log(`āŒ GraphQL server responded with ${response.status}`); - return false; - } - } catch (error) { - console.log('āŒ Failed to connect to GraphQL server'); - console.log(' Make sure to run "npm run dev" in the main directory'); - console.log(` Error: ${error.message}`); - return false; + if (!response.ok) { + throw new Error( + `GraphQL server at ${GRAPHQL_URL} responded with ${response.status}` + ); } } async function testDocumentQuery() { - console.log('šŸ“„ Testing document query...'); - - try { - const query = ` + const query = ` query TestDocuments { docConnection(first: 5, sort: "title") { edges { @@ -55,68 +47,39 @@ async function testDocumentQuery() { } `; - const response = await fetch(GRAPHQL_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query }), - }); + const response = await fetch(GRAPHQL_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query }), + }); - const result = await response.json(); + const result = await response.json(); - if (result.errors) { - console.log('āŒ GraphQL query failed:'); - console.log(JSON.stringify(result.errors, null, 2)); - return false; - } - - const documents = result.data.docConnection.edges; - console.log(`āœ… Found ${documents.length} documents`); - - documents.forEach(({ node }) => { - console.log(` - ${node.title} (${node._sys.relativePath})`); - }); + if (result.errors) { + throw new Error( + `GraphQL query failed: ${JSON.stringify(result.errors, null, 2)}` + ); + } - return true; - } catch (error) { - console.log('āŒ Document query failed'); - console.log(` Error: ${error.message}`); - return false; + const documents = result.data?.docConnection?.edges; + if (!Array.isArray(documents)) { + throw new Error( + "Document query returned no docConnection — check the TinaCMS configuration" + ); } } async function runTests() { - console.log('šŸš€ Testing docStatic MCP Server prerequisites...\n'); - - const graphqlOk = await testGraphQLConnection(); - console.log(); - - if (!graphqlOk) { - console.log('šŸ›‘ Cannot proceed - GraphQL server is not available'); - console.log('\nšŸ“ To fix this:'); - console.log(' 1. Run "npm run dev" in the main docstatic directory'); - console.log(' 2. Wait for "TinaCMS is running" message'); - console.log(' 3. Then run "npm run mcp:start" to start the MCP server'); - process.exit(1); - } - - const documentsOk = await testDocumentQuery(); - console.log(); - - if (documentsOk) { - console.log('šŸŽ‰ All tests passed! MCP server should work correctly.'); - console.log('\nšŸ“ Next steps:'); - console.log(' 1. Build the MCP server: npm run mcp:build'); - console.log(' 2. Start the MCP server: npm run mcp:start'); - console.log(' 3. Configure your AI assistant to use the MCP server'); - } else { - console.log('āš ļø Document query failed - check TinaCMS configuration'); - } + await testGraphQLConnection(); + await testDocumentQuery(); } // Handle graceful shutdown -process.on('SIGINT', () => { - console.log('\nšŸ‘‹ Test interrupted'); +process.on("SIGINT", () => { process.exit(0); }); -runTests().catch(console.error); \ No newline at end of file +runTests().catch((error) => { + process.exitCode = 1; + throw error; +}); diff --git a/mcp-server/tsconfig.json b/mcp-server/tsconfig.json index 74694aef..785709f6 100644 --- a/mcp-server/tsconfig.json +++ b/mcp-server/tsconfig.json @@ -14,4 +14,4 @@ }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] -} \ No newline at end of file +} diff --git a/package.json b/package.json index 0e2bb0a7..789a295f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docstatic", - "version": "0.3.101", + "version": "0.3.102", "description": "A Docusaurus + TinaCMS documentation/static site generator with OpenAPI and GraphQL support.", "author": "aowendev ", "license": "MIT", @@ -28,8 +28,10 @@ "generate-files": "node scripts/generate-file-list.js", "generate-docs-metadata": "node scripts/generate-docs-metadata.js", "update-theme-css": "node scripts/update-theme-css.js", - "prebuild": "yarn generate-media-index && yarn generate-files && yarn generate-docs-metadata && yarn update-theme-css && yarn generate-git-identity", - "predev": "yarn generate-media-index && yarn generate-files && yarn generate-docs-metadata && yarn update-theme-css && yarn generate-git-identity", + "generate": "node scripts/generate-media-index.js && node scripts/generate-file-list.js && node scripts/generate-docs-metadata.js && node scripts/update-theme-css.js && node scripts/generate-git-identity.js", + "prebuild": "yarn generate", + "predev": "yarn generate", + "prebuild-local": "yarn generate", "build": "tinacms build && docusaurus build", "build-local": "NODE_OPTIONS=--max-old-space-size=8192 tinacms build --local --skip-indexing --skip-cloud-checks && docusaurus build", "swizzle": "docusaurus swizzle", @@ -46,8 +48,8 @@ "gen-graphql": "docusaurus docs:generate:graphql", "gen-api-docs:version": "docusaurus gen-api-docs:version", "clean-api-docs:version": "docusaurus clean-api-docs:version", - "lint": "biome check config/ reuse/ scripts/ src/ tina/", - "lint:fix": "biome check config/ reuse/ scripts/ src/ tina/ --fix", + "lint": "biome check .", + "lint:fix": "biome check . --fix", "mcp:install": "cd mcp-server && npm install", "mcp:build": "cd mcp-server && npm run build", "mcp:dev": "cd mcp-server && npm run dev", @@ -56,19 +58,19 @@ "postinstall": "npm run mcp:install" }, "dependencies": { - "@algolia/client-search": "^5.53.0", + "@algolia/client-search": "^5.56.0", "@codemirror/language": "6.0.0", - "@docusaurus/core": "^3.10.1", - "@docusaurus/faster": "^3.10.1", - "@docusaurus/plugin-content-docs": "^3.10.1", - "@docusaurus/preset-classic": "^3.10.1", - "@docusaurus/theme-common": "^3.10.1", - "@docusaurus/theme-mermaid": "^3.10.1", - "@docusaurus/types": "^3.10.1", - "@docusaurus/utils": "^3.10.1", - "@docusaurus/utils-validation": "^3.10.1", + "@docusaurus/core": "^3.10.2", + "@docusaurus/faster": "^3.10.2", + "@docusaurus/plugin-content-docs": "^3.10.2", + "@docusaurus/preset-classic": "^3.10.2", + "@docusaurus/theme-common": "^3.10.2", + "@docusaurus/theme-mermaid": "^3.10.2", + "@docusaurus/types": "^3.10.2", + "@docusaurus/utils": "^3.10.2", + "@docusaurus/utils-validation": "^3.10.2", "@mdx-js/react": "^3.0.0", - "@types/react": "^19.2.15", + "@types/react": "^19.2.18", "color": "^5.0.2", "docusaurus-graphql-plugin": "0.7.0", "docusaurus-lunr-search": "^3.6.0", @@ -79,25 +81,25 @@ "fs-extra": "9.0.1", "image-size": "^2.0.2", "raw-loader": "^4.0.2", - "react": "^19.2.6", + "react": "^19.2.8", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^19.2.6", + "react-dom": "^19.2.8", "react-loadable": "^5.5.0", "react-markdown": "^10.1.0", "rehype-katex": "^7.0.1", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "remark-math": "^6.0.0", - "sass": "^1.100.0", + "sass": "^1.102.0", "search-insights": "^2.17.3", "slate": "^0.118.1", "slate-dom": "^0.118.1", "sucrase": "^3.35.0", - "tinacms": "^3.8.4", + "tinacms": "^3.11.0", "title": "^4.0.1", "typescript": "5.6.3", - "webpack": "^5.107.2", + "webpack": "^5.109.2", "yup": "0.32.11" }, "resolutions": { @@ -123,8 +125,8 @@ ] }, "devDependencies": { - "@biomejs/biome": "^2.4.16", - "@tinacms/cli": "^2.4.2", + "@biomejs/biome": "^2.5.7", + "@tinacms/cli": "^2.5.6", "gray-matter": "^4.0.3" }, "engines": { diff --git a/scripts/export_xliff_from_fs.js b/scripts/export_xliff_from_fs.js index 0e2041c8..fc0f8343 100644 --- a/scripts/export_xliff_from_fs.js +++ b/scripts/export_xliff_from_fs.js @@ -1,21 +1,23 @@ #!/usr/bin/env node -const fs = require('fs'); -const path = require('path'); +const fs = require("node:fs"); +const path = require("node:path"); // simple frontmatter extractor (same semantics as xliff util) function extractFrontmatter(text) { - if (!text) return { metadata: {}, body: text || '' }; + if (!text) return { metadata: {}, body: text || "" }; const m = String(text).match(/^---\s*\n([\s\S]*?)\n---\s*\n?/); if (!m) return { metadata: {}, body: text }; const fmRaw = m[1]; const body = text.slice(m[0].length); const metadata = {}; - fmRaw.split(/\n/).forEach((line) => { - const kv = line.match(/^([A-Za-z0-9_\-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/); + for (const line of fmRaw.split(/\n/)) { + const kv = line.match( + /^([A-Za-z0-9_-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/ + ); if (kv) { - metadata[kv[1]] = (kv[2] || kv[3] || (kv[4] || '')).trim(); + metadata[kv[1]] = (kv[2] || kv[3] || kv[4] || "").trim(); } - }); + } return { metadata, body }; } @@ -29,50 +31,70 @@ function walkDir(dir, cb) { } async function main() { - const language = process.argv[2] || 'fr'; + const language = process.argv[2] || "fr"; const outFile = process.argv[3] || `translations-${language}.xlf`; - const docsRoot = path.join(process.cwd(), 'docs'); + const docsRoot = path.join(process.cwd(), "docs"); if (!fs.existsSync(docsRoot)) { - console.error('docs/ directory not found in', process.cwd()); + console.error("docs/ directory not found in", process.cwd()); process.exit(1); } const docNodes = []; walkDir(docsRoot, (file) => { if (!/\.mdx?$|\.md$/i.test(file)) return; - const rel = path.relative(process.cwd(), file).replace(/\\\\/g, '/'); - const raw = fs.readFileSync(file, 'utf8'); + const rel = path.relative(process.cwd(), file).replace(/\\\\/g, "/"); + const raw = fs.readFileSync(file, "utf8"); const stat = fs.statSync(file); const parsed = extractFrontmatter(raw); - const title = parsed.metadata && parsed.metadata.title ? parsed.metadata.title : path.basename(file); - docNodes.push({ node: { raw, title, lastmod: stat.mtime.toISOString(), _sys: { relativePath: rel } } }); + const title = parsed.metadata?.title + ? parsed.metadata.title + : path.basename(file); + docNodes.push({ + node: { + raw, + title, + lastmod: stat.mtime.toISOString(), + _sys: { relativePath: rel }, + }, + }); }); // Build fake translations that exist but are older, so exportOutOfDateAsXliff // will consider them out-of-date and include units. const i18nNodes = docNodes.map((edge) => { - const rel = `${language}/docusaurus-plugin-content-docs/current/${edge.node._sys.relativePath.replace(/^docs\//, '')}`; + const rel = `${language}/docusaurus-plugin-content-docs/current/${edge.node._sys.relativePath.replace(/^docs\//, "")}`; // translation body can be empty; we just need an older lastmod - return { node: { raw: edge.node.raw, title: edge.node.title, lastmod: new Date(2000,0,1).toISOString(), _sys: { relativePath: rel } } }; + return { + node: { + raw: edge.node.raw, + title: edge.node.title, + lastmod: new Date(2000, 0, 1).toISOString(), + _sys: { relativePath: rel }, + }, + }; }); // Minimal fake client matching the shape expected by xliff util const client = { queries: { - docConnection: async () => ({ data: { docConnection: { edges: docNodes } } }), - i18nConnection: async () => ({ data: { i18nConnection: { edges: i18nNodes } } }), + docConnection: async () => ({ + data: { docConnection: { edges: docNodes } }, + }), + i18nConnection: async () => ({ + data: { i18nConnection: { edges: i18nNodes } }, + }), }, }; // Require the xliff util and call exportOutOfDateAsXliff - const xliff = require('../src/utils/xliff'); + const xliff = require("../src/utils/xliff"); try { const xml = await xliff.exportOutOfDateAsXliff(client, language); - fs.writeFileSync(path.join(process.cwd(), outFile), xml, 'utf8'); - console.error('Wrote', outFile); + fs.writeFileSync(path.join(process.cwd(), outFile), xml, "utf8"); + console.error("Wrote", outFile); } catch (e) { - console.error('Error running export:', e && e.stack ? e.stack : e); + console.error("Error running export:", e?.stack ? e.stack : e); process.exit(1); } } diff --git a/scripts/generate-docs-metadata.js b/scripts/generate-docs-metadata.js index ace3fc92..3bb0075b 100644 --- a/scripts/generate-docs-metadata.js +++ b/scripts/generate-docs-metadata.js @@ -34,7 +34,11 @@ function generateDocsMetadata() { const { data: frontmatter } = matter(fileContent); // Only include published documents with tags - if (frontmatter.published !== false && frontmatter.tags && Array.isArray(frontmatter.tags)) { + if ( + frontmatter.published !== false && + frontmatter.tags && + Array.isArray(frontmatter.tags) + ) { // Generate the URL path for Docusaurus let urlPath = relativeFilePath .replace(/\.(mdx?|md)$/, "") @@ -50,7 +54,9 @@ function generateDocsMetadata() { } docs.push({ - title: frontmatter.title || path.basename(entry.name, path.extname(entry.name)), + title: + frontmatter.title || + path.basename(entry.name, path.extname(entry.name)), description: frontmatter.description || "", tags: frontmatter.tags || [], path: urlPath, @@ -59,12 +65,16 @@ function generateDocsMetadata() { }); } } catch (error) { - console.warn(`Warning: Could not process ${fullPath}: ${error.message}`); + console.warn( + `Warning: Could not process ${fullPath}: ${error.message}` + ); } } } } catch (error) { - console.warn(`Warning: Could not read directory ${dir}: ${error.message}`); + console.warn( + `Warning: Could not read directory ${dir}: ${error.message}` + ); } } @@ -93,4 +103,4 @@ if (require.main === module) { generateDocsMetadata(); } -module.exports = generateDocsMetadata; \ No newline at end of file +module.exports = generateDocsMetadata; diff --git a/scripts/generate-git-identity.js b/scripts/generate-git-identity.js index ebc17385..9596ec54 100644 --- a/scripts/generate-git-identity.js +++ b/scripts/generate-git-identity.js @@ -3,9 +3,9 @@ * Writes the current Git user's identity to static/git-identity.json * so the Tina admin (browser) can read it during local development. */ -const { execSync } = require("child_process"); -const fs = require("fs"); -const path = require("path"); +const { execSync } = require("node:child_process"); +const fs = require("node:fs"); +const path = require("node:path"); function safe(cmd) { try { @@ -26,9 +26,11 @@ function main() { const outFile = path.join(outDir, "git-identity.json"); try { if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }); - fs.writeFileSync(outFile, JSON.stringify(data, null, 2) + "\n"); + fs.writeFileSync(outFile, `${JSON.stringify(data, null, 2)}\n`); // eslint-disable-next-line no-console - console.log(`[git-identity] Wrote ${outFile}: ${name}${email ? ` <${email}>` : ""}`); + console.log( + `[git-identity] Wrote ${outFile}: ${name}${email ? ` <${email}>` : ""}` + ); } catch (err) { // eslint-disable-next-line no-console console.warn("[git-identity] Failed to write git identity:", err.message); diff --git a/scripts/generate-media-index.js b/scripts/generate-media-index.js index d24e8dcd..85325163 100644 --- a/scripts/generate-media-index.js +++ b/scripts/generate-media-index.js @@ -5,24 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require('fs'); -const path = require('path'); -const { imageSize } = require('image-size'); +const fs = require("node:fs"); +const path = require("node:path"); +const { imageSize } = require("image-size"); -const IMG_DIR = path.join(__dirname, '../static/img'); -const OUTPUT_FILE = path.join(__dirname, '../reuse/media/index.json'); +const IMG_DIR = path.join(__dirname, "../static/img"); +const OUTPUT_FILE = path.join(__dirname, "../reuse/media/index.json"); function getMediaFiles(dir, baseDir = IMG_DIR) { let results = []; const list = fs.readdirSync(dir); - list.forEach(file => { + for (const file of list) { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); - if (stat && stat.isDirectory()) { + if (stat?.isDirectory()) { results = results.concat(getMediaFiles(filePath, baseDir)); } else if (/\.(jpg|jpeg|png|gif|svg|webp)$/i.test(file)) { const ext = path.extname(file).toLowerCase(); - let dimensions = undefined; + let dimensions; // Only get dimensions for raster images if (/(jpg|jpeg|png|gif|webp)$/i.test(ext)) { try { @@ -31,7 +31,7 @@ function getMediaFiles(dir, baseDir = IMG_DIR) { if (size.width && size.height) { dimensions = `${size.width}x${size.height}`; } - } catch (e) { + } catch (_e) { // Skip dimensions for this file, continue processing others } } @@ -39,13 +39,13 @@ function getMediaFiles(dir, baseDir = IMG_DIR) { const lastModified = stat.mtime.toISOString(); results.push({ filename: file, - path: path.relative(baseDir, filePath).replace(/\\/g, '/'), + path: path.relative(baseDir, filePath).replace(/\\/g, "/"), size: stat.size, ...(dimensions ? { dimensions } : {}), - lastModified + lastModified, }); } - }); + } return results; } @@ -55,4 +55,4 @@ function main() { console.log(`Media index written to ${OUTPUT_FILE}`); } -main(); \ No newline at end of file +main(); diff --git a/scripts/run_graphql_export.js b/scripts/run_graphql_export.js index ba34343f..e5b50a94 100644 --- a/scripts/run_graphql_export.js +++ b/scripts/run_graphql_export.js @@ -1,14 +1,14 @@ #!/usr/bin/env node -const fs = require('fs'); -const path = require('path'); +const fs = require("node:fs"); +const path = require("node:path"); -const xliff = require('../src/utils/xliff'); -const GRAPHQL_URL = process.env.GRAPHQL_URL || 'http://localhost:4001/graphql'; +const xliff = require("../src/utils/xliff"); +const GRAPHQL_URL = process.env.GRAPHQL_URL || "http://localhost:4001/graphql"; async function gql(query, variables) { const res = await fetch(GRAPHQL_URL, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query, variables }), }); const json = await res.json(); @@ -36,14 +36,20 @@ const client = { (async () => { try { - console.error('Calling exporter using GraphQL at', GRAPHQL_URL); - const xml = await xliff.exportOutOfDateAsXliff(client, process.argv[2] || 'fr'); - const out = path.join(process.cwd(), process.argv[3] || 'fr-translations.generated.xlf'); - fs.writeFileSync(out, xml, 'utf8'); - console.error('Wrote', out); + console.error("Calling exporter using GraphQL at", GRAPHQL_URL); + const xml = await xliff.exportOutOfDateAsXliff( + client, + process.argv[2] || "fr" + ); + const out = path.join( + process.cwd(), + process.argv[3] || "fr-translations.generated.xlf" + ); + fs.writeFileSync(out, xml, "utf8"); + console.error("Wrote", out); console.log(xml.slice(0, 2000)); } catch (e) { - console.error('Export failed:', e && e.stack ? e.stack : e); + console.error("Export failed:", e?.stack ? e.stack : e); process.exit(1); } })(); diff --git a/scripts/sync-template.js b/scripts/sync-template.js index ba46a432..4d785e38 100644 --- a/scripts/sync-template.js +++ b/scripts/sync-template.js @@ -18,8 +18,8 @@ * --check Report what would change without writing (exits 1 if out of sync) */ -const fs = require("fs"); -const path = require("path"); +const fs = require("node:fs"); +const path = require("node:path"); const ROOT = path.join(__dirname, ".."); const TEMPLATE = path.join(ROOT, "template"); @@ -38,7 +38,7 @@ const MIRROR_SRC_DIRS = [ const COPY_FILES = [ "docusaurus.config.ts", "sidebars.ts", - "biome.json", + // biome.json ships under a different name, see BIOME_TEMPLATE_NAME below "frontmatter.json", "tina/config.jsx", "config/docusaurus/openapi-tag-template.md", @@ -61,12 +61,29 @@ const SCRIPTS_ALLOWLIST = [ "util.js", ]; -// Stale template files removed on sync +// Biome only auto-discovers "biome.json"/"biome.jsonc", so the template ships +// its config under this name and the create CLI renames it on scaffold. +const BIOME_TEMPLATE_NAME = "biome.template.json"; + +// Oldest create-docstatic that can consume this manifest correctly. Bump this +// whenever the manifest gains semantics an older CLI would silently ignore — +// renameFiles landed in 0.2.1, and a CLI without it scaffolds a site with no +// biome.json at all. The CLI refuses rather than producing a broken site. +const MIN_CREATE_VERSION = "0.2.1"; + +// Stale files removed from BOTH template/ and, via the update manifest, from +// existing sites. Only put things here that sites should genuinely lose. const REMOVE_FILES = [ "util.js", // moved to scripts/util.js "babel.config.js", // root site dropped it (@docusaurus/faster) ]; +// Stale files removed from template/ only. biome.json lives here because a +// scaffolded site must KEEP its biome.json — it is merely shipped under +// BIOME_TEMPLATE_NAME, so listing it in REMOVE_FILES would tell every existing +// site to delete its config. +const TEMPLATE_ONLY_REMOVE = ["biome.json"]; + // Root package.json scripts that make no sense in a scaffolded site const EXCLUDED_SCRIPTS = [ "postinstall", @@ -191,7 +208,7 @@ mirrorScripts(); for (const file of COPY_FILES) copyFile(file); syncPackageJson(); -for (const rel of REMOVE_FILES) { +for (const rel of [...REMOVE_FILES, ...TEMPLATE_ONLY_REMOVE]) { const dest = path.join(TEMPLATE, rel); if (fs.existsSync(dest)) { log("remove", rel); @@ -212,6 +229,22 @@ for (const rel of REMOVE_FILES) { } } +// Biome discovers nested config files regardless of files.includes, so shipping +// template/biome.json would make `biome check .` abort at the repo root with +// "found a nested root configuration". Marking it "root": false is NOT a fix: +// Biome then looks for a parent root config and, finding none in a scaffolded +// site, silently ignores the whole file. So the template ships it under a name +// Biome does not discover, and the create CLI renames it during scaffolding +// (same trick as the dotless "gitignore" above). +{ + const serialized = fs.readFileSync(path.join(ROOT, "biome.json"), "utf8"); + const dest = path.join(TEMPLATE, BIOME_TEMPLATE_NAME); + if (!fs.existsSync(dest) || fs.readFileSync(dest, "utf8") !== serialized) { + log(fs.existsSync(dest) ? "update" : "add", BIOME_TEMPLATE_NAME); + if (!CHECK) fs.writeFileSync(dest, serialized); + } +} + // docusaurus.config.ts requires blog/ and generate-media-index writes into // reuse/media/, so a scaffolded site needs both to exist. seedFile( @@ -242,10 +275,16 @@ This is your first blog post. Edit it in the CMS at { const manifest = { manifestVersion: 1, + minCreateVersion: MIN_CREATE_VERSION, // Directories copied over the site's copy, overwriting file by file mirrorDirs: [...MIRROR_SRC_DIRS, "scripts"], // Individual files overwritten - files: COPY_FILES.filter((f) => f !== "src/pages/example-page.mdx"), + files: [ + ...COPY_FILES.filter((f) => f !== "src/pages/example-page.mdx"), + BIOME_TEMPLATE_NAME, + ], + // Template path -> path written into the site + renameFiles: { [BIOME_TEMPLATE_NAME]: "biome.json" }, // Stale files deleted if present removeFiles: REMOVE_FILES, // Created only if missing (content-ish or required-to-exist files) diff --git a/scripts/test_generated_export.mjs b/scripts/test_generated_export.mjs index 0fc78468..757139f3 100644 --- a/scripts/test_generated_export.mjs +++ b/scripts/test_generated_export.mjs @@ -1,17 +1,17 @@ (async () => { try { - const mod = await import('../tina/__generated__/config.prebuild.jsx'); - const clientMod = await import('../tina/__generated__/client.js'); + const mod = await import("../tina/__generated__/config.prebuild.jsx"); + const clientMod = await import("../tina/__generated__/client.js"); const client = clientMod.client || clientMod.default || clientMod; if (!mod.exportOutOfDateAsXliff) { - console.error('exportOutOfDateAsXliff not found in generated module'); + console.error("exportOutOfDateAsXliff not found in generated module"); process.exit(2); } - const xlf = await mod.exportOutOfDateAsXliff(client, 'fr'); + const xlf = await mod.exportOutOfDateAsXliff(client, "fr"); // Print first 2000 chars for inspection console.log(xlf.slice(0, 2000)); } catch (e) { - console.error('error running generated exporter:', e); + console.error("error running generated exporter:", e); process.exit(1); } })(); diff --git a/scripts/test_src_export.cjs b/scripts/test_src_export.cjs index aebd8b19..e8fab721 100644 --- a/scripts/test_src_export.cjs +++ b/scripts/test_src_export.cjs @@ -1,12 +1,12 @@ -const xliff = require('../src/utils/xliff'); -const clientModule = require('../tina/__generated__/client'); +const xliff = require("../src/utils/xliff"); +const clientModule = require("../tina/__generated__/client"); const client = clientModule.client || clientModule.default || clientModule; (async () => { try { - const xlf = await xliff.exportOutOfDateAsXliff(client, 'fr'); + const xlf = await xliff.exportOutOfDateAsXliff(client, "fr"); console.log(xlf.slice(0, 2000)); } catch (e) { - console.error('error running src exporter:', e); + console.error("error running src exporter:", e); process.exit(1); } })(); diff --git a/sidebars.ts b/sidebars.ts index 1e5b6f18..81231d84 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -1,7 +1,7 @@ -const fs = require("fs"); -const path = require("path"); +const fs = require("node:fs"); +const path = require("node:path"); const sidebarData = require("./config/sidebar/index.json"); -const docusaurusData = require("./config/docusaurus/index.json"); +const _docusaurusData = require("./config/docusaurus/index.json"); const getDocId = (doc) => { return doc @@ -73,7 +73,7 @@ const getItem = (item) => { }, ]; } - + if (type === "link") { if (item.href && item.title) { itemProps.label = item.title; diff --git a/src/components/CollapsibleField/index.jsx b/src/components/CollapsibleField/index.jsx index 4cbe771a..35c545d9 100644 --- a/src/components/CollapsibleField/index.jsx +++ b/src/components/CollapsibleField/index.jsx @@ -28,17 +28,9 @@ const CollapsibleField = wrapFieldsWithMeta( } const toggleCollapsed = () => { - setIsCollapsed(!isCollapsed); + setIsCollapsed((collapsed) => !collapsed); }; - const hasValue = - input.value && - (Array.isArray(input.value) - ? input.value.length > 0 - : typeof input.value === "string" - ? input.value.trim() !== "" - : true); - return ( <> {/* Toggle button positioned independently */} @@ -82,10 +74,7 @@ const CollapsibleField = wrapFieldsWithMeta( > { +const Comment = () => { // This component intentionally returns null // The comment is only visible in the source code return null; diff --git a/src/components/ConditionalText/index.jsx b/src/components/ConditionalText/index.jsx index e2a3baf8..9975712c 100644 --- a/src/components/ConditionalText/index.jsx +++ b/src/components/ConditionalText/index.jsx @@ -24,21 +24,19 @@ const ConditionalText = ({ let pageConditions = []; let currentLanguage = "en"; + // useDoc() throws outside a doc page (blog posts, custom pages), so this + // guard is load-bearing. useDocusaurusContext() needs no guard: its provider + // is mounted at the app root. try { - // Get document metadata (conditions from frontmatter) + // biome-ignore lint/correctness/useHookAtTopLevel: useDoc throws off doc pages; the catch is the only way to render this component elsewhere const doc = useDoc(); pageConditions = doc?.frontMatter?.conditions || []; } catch { // Not in a doc context, pageConditions stays empty } - try { - // Get current language from Docusaurus context - const { i18n } = useDocusaurusContext(); - currentLanguage = i18n?.currentLocale || "en"; - } catch { - // Context not available, use default - } + const { i18n } = useDocusaurusContext(); + currentLanguage = i18n?.currentLocale || "en"; // Check if required conditions are met against page metadata conditions const checkConditionsMet = () => { @@ -46,21 +44,25 @@ const ConditionalText = ({ if (logic === "all") { // All required conditions must be present in page metadata - return conditions.every((condition) => pageConditions.includes(condition)); + return conditions.every((condition) => + pageConditions.includes(condition) + ); } // Any required condition must be present in page metadata return conditions.some((condition) => pageConditions.includes(condition)); }; - // Check if language conditions are satisfied + // Check if language conditions are satisfied. Only one language is ever + // active, so "all" is only satisfiable by a single-entry list — previously + // both branches were identical and languageLogic had no effect at all. const checkLanguageConditions = () => { if (languages.length === 0) return true; if (languageLogic === "all") { - // For 'all' logic, current language must be in the list - return languages.includes(currentLanguage); + // Every listed language must match the active one + return languages.every((language) => language === currentLanguage); } - // For 'any' logic, current language must match at least one + // Any listed language may match the active one return languages.includes(currentLanguage); }; @@ -90,7 +92,8 @@ const ConditionalText = ({ } // Apply action logic: show or hide based on whether conditions are met - const shouldShow = action === "hide" ? !conditionsSatisfied : conditionsSatisfied; + const shouldShow = + action === "hide" ? !conditionsSatisfied : conditionsSatisfied; // const debugInfo = debug // ? { @@ -131,11 +134,11 @@ const ConditionalText = ({ )} */} - {shouldShow ? ( - children - ) : ( - fallback && {fallback} - )} + {shouldShow + ? children + : fallback && ( + {fallback} + )} ); }; diff --git a/src/components/ConditionalText/template.jsx b/src/components/ConditionalText/template.jsx index 2f809df3..f7a479cd 100644 --- a/src/components/ConditionalText/template.jsx +++ b/src/components/ConditionalText/template.jsx @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import conditionsData from "../../../reuse/conditions/index.json"; import docusaurusData from "../../../config/docusaurus/index.json"; +import conditionsData from "../../../reuse/conditions/index.json"; import ConditionsTreeField from "../ConditionsField"; // Build condition options from conditions data @@ -67,7 +67,8 @@ export const ConditionalTextBlockTemplate = { ], ui: { component: "select", - description: "Choose whether to show or hide content when conditions match", + description: + "Choose whether to show or hide content when conditions match", }, }, { @@ -78,7 +79,8 @@ export const ConditionalTextBlockTemplate = { options: conditionOptions, ui: { component: ConditionsTreeField, - description: "Content action will be triggered when these conditions are met (defined in page metadata)", + description: + "Content action will be triggered when these conditions are met (defined in page metadata)", }, }, { diff --git a/src/components/ConditionsField/index.jsx b/src/components/ConditionsField/index.jsx index e17342be..7a2e78be 100644 --- a/src/components/ConditionsField/index.jsx +++ b/src/components/ConditionsField/index.jsx @@ -72,54 +72,11 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => { }; const handleConditionToggle = (conditionValue) => { - try { - const newConditions = selectedConditions.includes(conditionValue) - ? selectedConditions.filter((c) => c !== conditionValue) - : [...selectedConditions, conditionValue]; + const newConditions = selectedConditions.includes(conditionValue) + ? selectedConditions.filter((c) => c !== conditionValue) + : [...selectedConditions, conditionValue]; - input.onChange(newConditions); - } catch (error) { - // Silent error handling for production - } - }; - - const handleCategoryToggle = (category, conditions) => { - try { - const categoryValues = conditions.map((c) => c.value); - const allSelected = categoryValues.every((value) => - selectedConditions.includes(value) - ); - - let newConditions; - if (allSelected) { - // Deselect all conditions in this category - newConditions = selectedConditions.filter( - (c) => !categoryValues.includes(c) - ); - } else { - // Select all conditions in this category - const toAdd = categoryValues.filter( - (value) => !selectedConditions.includes(value) - ); - newConditions = [...selectedConditions, ...toAdd]; - } - - input.onChange(newConditions); - } catch (error) { - // Silent error handling for production - } - }; - - const getCategoryStatus = (conditions) => { - const categoryValues = conditions.map((c) => c.value); - const selectedCount = categoryValues.filter((value) => - selectedConditions.includes(value) - ).length; - const totalCount = categoryValues.length; - - if (selectedCount === 0) return "none"; - if (selectedCount === totalCount) return "all"; - return "some"; + input.onChange(newConditions); }; return ( @@ -177,11 +134,6 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => {
{Object.entries(conditionsTree).map(([category, conditions]) => { const isExpanded = expandedCategories.has(category); - const categoryStatus = getCategoryStatus(conditions); - const selectedInCategory = conditions.filter((c) => - selectedConditions.includes(c.value) - ).length; - return (
{/* Category Header */} @@ -204,12 +156,13 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => { ā–¶ - toggleCategory(category)} - className="flex-1 text-left text-sm cursor-pointer select-none" + className="flex-1 text-left text-sm cursor-pointer select-none bg-transparent border-none p-0" > {category} - +
{/* Category Conditions */} diff --git a/src/components/Dashboard/BrokenLinksDashboard.jsx b/src/components/Dashboard/BrokenLinksDashboard.jsx index 5b5e82ac..45821b51 100644 --- a/src/components/Dashboard/BrokenLinksDashboard.jsx +++ b/src/components/Dashboard/BrokenLinksDashboard.jsx @@ -1,879 +1,1226 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const BrokenLinksDashboard = () => { - const [linkData, setLinkData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [showDetails, setShowDetails] = useState(false); - const [selectedFile, setSelectedFile] = useState(null); - - // Function to extract links from MDX content - const extractLinksFromContent = (content, filePath) => { - const links = []; - - // Regex for markdown links [text](url) - const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g; - // Regex for HTML links - const htmlLinkRegex = /]+href=["']([^"']+)["'][^>]*>/gi; - // Regex for reference links [text][ref] and [ref]: url - const refLinkRegex = /\[([^\]]+)\]\[([^\]]*)\]/g; - const refDefRegex = /^\[([^\]]+)\]:\s*(.+)$/gm; - - let match; - - // Extract markdown links - while ((match = markdownLinkRegex.exec(content)) !== null) { - links.push({ - text: match[1], - url: match[2].trim(), - type: 'markdown', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - - // Extract HTML links - while ((match = htmlLinkRegex.exec(content)) !== null) { - links.push({ - text: match[0], - url: match[1].trim(), - type: 'html', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - - // Extract reference definitions - const refDefs = {}; - while ((match = refDefRegex.exec(content)) !== null) { - refDefs[match[1].toLowerCase()] = match[2].trim(); - } - - // Extract reference links - while ((match = refLinkRegex.exec(content)) !== null) { - const refKey = (match[2] || match[1]).toLowerCase(); - if (refDefs[refKey]) { - links.push({ - text: match[1], - url: refDefs[refKey], - type: 'reference', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - } - - return links; - }; - - // Function to validate a single link - const validateLink = async (link) => { - try { - const url = link.url.trim(); - - // Skip anchors, mailto, and tel links - if (url.startsWith('#') || url.startsWith('mailto:') || url.startsWith('tel:')) { - return { ...link, status: 'skipped', reason: 'Not validated (anchor/mailto/tel)' }; - } - - // Handle relative/internal links - if (!url.startsWith('http://') && !url.startsWith('https://')) { - // Check if it's a relative link to another doc - if (url.endsWith('.mdx') || url.endsWith('.md')) { - return { ...link, status: 'valid', reason: 'Internal doc link (assumed valid)' }; - } - return { ...link, status: 'valid', reason: 'Internal link (assumed valid)' }; - } - - // Validate external links with timeout - use original no-cors approach first - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 8000); - - try { - // Primary approach: Use no-cors mode (original working method) - const response = await fetch(url, { - method: 'HEAD', - signal: controller.signal, - mode: 'no-cors', - headers: { - 'User-Agent': 'Mozilla/5.0 (compatible; docStatic Link Checker/1.0)' - } - }); - - clearTimeout(timeoutId); - - // With no-cors mode, if no error is thrown, assume link is reachable - return { ...link, status: 'valid', reason: 'Link is reachable' }; - - } catch (fetchError) { - clearTimeout(timeoutId); - - if (fetchError.name === 'AbortError') { - return { ...link, status: 'broken', reason: 'Timeout (>8s)' }; - } - - // Fallback: Check if this might be a CORS/CORP issue for known problematic domains - const urlObj = new URL(url); - const knownCorsDomains = [ - 'docs.github.com', - 'support.microsoft.com', - 'docs.microsoft.com', - 'developer.mozilla.org' - ]; - - const isKnownCorsDomain = knownCorsDomains.some(domain => - urlObj.hostname === domain || urlObj.hostname.endsWith('.' + domain) - ); - - if (isKnownCorsDomain) { - return { - ...link, - status: 'warning', - reason: 'CORS/CORP policy prevents validation - manual check required' - }; - } - - // For other errors, use original logic - if (fetchError.message.includes('network') || fetchError.message.includes('fetch')) { - return { ...link, status: 'broken', reason: 'Network error or unreachable' }; - } - - // For other errors, assume CORS restrictions but link might be valid - return { ...link, status: 'warning', reason: 'CORS restricted (unable to verify)' }; - } - } catch (error) { - return { ...link, status: 'broken', reason: error.message }; - } - }; - - // Function to open file in CMS editor - const openInCMS = (filePath) => { - // Extract relative path from full path - const relativePath = filePath.replace(/^\/docs\//, '').replace(/\.mdx?$/i, ''); - const cmsUrl = `/admin/index.html#/collections/edit/doc/${encodeURIComponent(relativePath)}`; - window.open(cmsUrl, '_blank'); - }; - - // Function to scan docs directory for MDX files using GraphQL - const scanDocsForLinks = async () => { - setLoading(true); - setError(null); - - try { - // Import the Tina client - const { client } = await import('../../../tina/__generated__/client'); - - // Fetch all docs from the main collection - const docsResult = await client.queries.docConnection({ - sort: 'title', - first: 500 // Request more documents - }); - - const docs = docsResult.data.docConnection.edges || []; - - const allLinks = []; - const fileStats = {}; - - // Process each document - for (const edge of docs) { - const node = edge.node; - const fileName = `${node._sys.filename}.mdx`; - const filePath = `/docs/${node._sys.relativePath}`; - - // Get the document body content - let content = ''; - if (node.body) { - // Extract text content from rich text blocks - content = extractTextFromBody(node.body); - } - - // Add title content if available - if (node.title) { - content = `# ${node.title}\n\n${content}`; - } - - const links = extractLinksFromContent(content, filePath); - - fileStats[filePath] = { - totalLinks: links.length, - fileName: fileName, - title: node.title || node._sys.filename, - relativePath: node._sys.relativePath - }; - - allLinks.push(...links); - } - - // Validate all links - const validatedLinks = []; - for (const link of allLinks) { - const validatedLink = await validateLink(link); - validatedLinks.push(validatedLink); - } - - // Calculate statistics - const stats = validatedLinks.reduce((acc, link) => { - acc.total++; - if (link.status === 'valid') acc.valid++; - else if (link.status === 'broken') acc.broken++; - else if (link.status === 'warning') acc.warning++; - else if (link.status === 'skipped') acc.skipped++; - return acc; - }, { total: 0, valid: 0, broken: 0, warning: 0, skipped: 0 }); - - // Group by file - const linksByFile = {}; - validatedLinks.forEach(link => { - const fileName = link.filePath.split('/').pop(); - if (!linksByFile[fileName]) { - linksByFile[fileName] = []; - } - linksByFile[fileName].push(link); - }); - - setLinkData({ - stats, - fileStats, - linksByFile, - allLinks: validatedLinks, - brokenLinks: validatedLinks.filter(link => link.status === 'broken'), - warningLinks: validatedLinks.filter(link => link.status === 'warning'), - timestamp: new Date().toISOString() - }); - } catch (error) { - setError(error.message); - console.error('Error scanning for broken links:', error); - } finally { - setLoading(false); - } - }; - - // Function to extract text content from Tina CMS rich text body - const extractTextFromBody = (body) => { - if (!body || !body.children) return ''; - - const extractFromChildren = (children) => { - return children.map(child => { - if (child.type === 'text') { - return child.text || ''; - } - if (child.type === 'a' && child.url) { - const text = child.children ? extractFromChildren(child.children) : ''; - return `[${text}](${child.url})`; - } - if (child.children) { - return extractFromChildren(child.children); - } - return ''; - }).join(''); - }; - - return extractFromChildren(body.children); - }; - - - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!linkData && !loading && !error) { - return ( -
-
-
- - - - - - - -

- Broken Links Dashboard -

-
- -
-
- ); - } - - if (loading) { - return ( -
-
-
- Loading Dashboard -
-
- Scanning docs for links and validating... -
- - {/* Progress Bar for Loading */} -
-
-
-
- -
- ); - } - - if (error) { - return ( -
-
-
- - - - - - Error -
-
{error}
- -
-
- ); - } - - if (!linkData) { - return ( -
- No data available -
- ); - } - - const { stats, fileStats, linksByFile, brokenLinks, warningLinks } = linkData; - const problemLinks = [...(brokenLinks || []), ...(warningLinks || [])]; - - return ( -
-
-
- - - - - - - -

- Broken Links Dashboard -

-
- -
- - {/* Statistics Cards */} -
-
-
- - - - -
-
-

Total Links

-

{stats.total}

-
-
- -
-
- - - -
-
-

Valid Links

-

{stats.valid}

-
-
- -
-
- - - - -
-
-

Broken Links

-

{stats.broken}

-
-
- -
-
- - - - - -
-
-

Warning Links

-

{stats.warning || 0}

-
-
- -
-
- - - - -
-
-

Files Scanned

-

{Object.keys(fileStats).length}

-
-
-
- - {/* Broken Links Section */} - {problemLinks.length > 0 && ( -
-

- 🚨 Problem Links ({problemLinks.length}) -

-
- {problemLinks.map((link, index) => ( -
- - -
- ))} -
-
- )} - - {/* Files with Broken Links */} - {(() => { - const filesWithProblemLinks = Object.entries(fileStats).filter(([filePath, stats]) => { - const fileName = stats.fileName; - const fileLinks = linksByFile[fileName] || []; - return fileLinks.some(link => link.status === 'broken' || link.status === 'warning'); - }); - - if (filesWithProblemLinks.length === 0) { - return null; - } - - return ( -
-
-

- - - - - Files with Problem Links ({filesWithProblemLinks.length}) -

- -
- -
- {filesWithProblemLinks.slice(0, showDetails ? undefined : 5).map(([filePath, stats], index) => { - const fileName = stats.fileName; - const fileLinks = linksByFile[fileName] || []; - const brokenCount = fileLinks.filter(link => link.status === 'broken').length; - const warningCount = fileLinks.filter(link => link.status === 'warning').length; - const totalProblems = brokenCount + warningCount; - - return ( -
0 ? '#fff5f5' : '#fff8f0', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center' - }} - > -
-
- {stats.title || fileName} -
-
- {stats.totalLinks} total links • {totalProblems} problem{totalProblems !== 1 ? 's' : ''} - {brokenCount > 0 && ( - - ({brokenCount} broken{warningCount > 0 ? `, ${warningCount} warning` : ''}) - - )} - {brokenCount === 0 && warningCount > 0 && ( - - ({warningCount} warning) - - )} -
-
- -
- ); - })} -
- - {!showDetails && filesWithProblemLinks.length > 5 && ( -
- And {filesWithProblemLinks.length - 5} more files... -
- )} -
- ); - })()} - - {/* Health Status */} -
-
- - {(stats.broken === 0 && (stats.warning || 0) === 0) ? ( - <> - - - - All Links Valid! - - ) : stats.broken === 0 ? ( - <> - - - - - - {stats.warning} Warning Links - - ) : ( - <> - - - - - {stats.broken} Broken Links{(stats.warning || 0) > 0 ? ` and ${stats.warning} Warnings` : ''} - - )} - -
-
- Link validation completed on {new Date().toLocaleString()} -
-
-
- ); -}; - -export default BrokenLinksDashboard; \ No newline at end of file +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; + +const BrokenLinksDashboard = () => { + const [linkData, setLinkData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showDetails, setShowDetails] = useState(false); + const [_selectedFile, _setSelectedFile] = useState(null); + + // Function to extract links from MDX content + const extractLinksFromContent = (content, filePath) => { + const links = []; + + // Regex for markdown links [text](url) + const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g; + // Regex for HTML links + const htmlLinkRegex = /]+href=["']([^"']+)["'][^>]*>/gi; + // Regex for reference links [text][ref] and [ref]: url + const refLinkRegex = /\[([^\]]+)\]\[([^\]]*)\]/g; + const refDefRegex = /^\[([^\]]+)\]:\s*(.+)$/gm; + + // Extract markdown links + for (const match of content.matchAll(markdownLinkRegex)) { + links.push({ + text: match[1], + url: match[2].trim(), + type: "markdown", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + + // Extract HTML links + for (const match of content.matchAll(htmlLinkRegex)) { + links.push({ + text: match[0], + url: match[1].trim(), + type: "html", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + + // Extract reference definitions + const refDefs = {}; + for (const match of content.matchAll(refDefRegex)) { + refDefs[match[1].toLowerCase()] = match[2].trim(); + } + + // Extract reference links + for (const match of content.matchAll(refLinkRegex)) { + const refKey = (match[2] || match[1]).toLowerCase(); + if (refDefs[refKey]) { + links.push({ + text: match[1], + url: refDefs[refKey], + type: "reference", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + } + + return links; + }; + + // Function to validate a single link + const validateLink = async (link) => { + try { + const url = link.url.trim(); + + // Skip anchors, mailto, and tel links + if ( + url.startsWith("#") || + url.startsWith("mailto:") || + url.startsWith("tel:") + ) { + return { + ...link, + status: "skipped", + reason: "Not validated (anchor/mailto/tel)", + }; + } + + // Handle relative/internal links + if (!url.startsWith("http://") && !url.startsWith("https://")) { + // Check if it's a relative link to another doc + if (url.endsWith(".mdx") || url.endsWith(".md")) { + return { + ...link, + status: "valid", + reason: "Internal doc link (assumed valid)", + }; + } + return { + ...link, + status: "valid", + reason: "Internal link (assumed valid)", + }; + } + + // Validate external links with timeout - use original no-cors approach first + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 8000); + + try { + // Primary approach: Use no-cors mode (original working method) + const _response = await fetch(url, { + method: "HEAD", + signal: controller.signal, + mode: "no-cors", + headers: { + "User-Agent": + "Mozilla/5.0 (compatible; docStatic Link Checker/1.0)", + }, + }); + + clearTimeout(timeoutId); + + // With no-cors mode, if no error is thrown, assume link is reachable + return { ...link, status: "valid", reason: "Link is reachable" }; + } catch (fetchError) { + clearTimeout(timeoutId); + + if (fetchError.name === "AbortError") { + return { ...link, status: "broken", reason: "Timeout (>8s)" }; + } + + // Fallback: Check if this might be a CORS/CORP issue for known problematic domains + const urlObj = new URL(url); + const knownCorsDomains = [ + "docs.github.com", + "support.microsoft.com", + "docs.microsoft.com", + "developer.mozilla.org", + ]; + + const isKnownCorsDomain = knownCorsDomains.some( + (domain) => + urlObj.hostname === domain || urlObj.hostname.endsWith(`.${domain}`) + ); + + if (isKnownCorsDomain) { + return { + ...link, + status: "warning", + reason: + "CORS/CORP policy prevents validation - manual check required", + }; + } + + // For other errors, use original logic + if ( + fetchError.message.includes("network") || + fetchError.message.includes("fetch") + ) { + return { + ...link, + status: "broken", + reason: "Network error or unreachable", + }; + } + + // For other errors, assume CORS restrictions but link might be valid + return { + ...link, + status: "warning", + reason: "CORS restricted (unable to verify)", + }; + } + } catch (error) { + return { ...link, status: "broken", reason: error.message }; + } + }; + + // Function to open file in CMS editor + const openInCMS = (filePath) => { + // Extract relative path from full path + const relativePath = filePath + .replace(/^\/docs\//, "") + .replace(/\.mdx?$/i, ""); + const cmsUrl = `/admin/index.html#/collections/edit/doc/${encodeURIComponent(relativePath)}`; + window.open(cmsUrl, "_blank"); + }; + + // Function to scan docs directory for MDX files using GraphQL + const scanDocsForLinks = async () => { + setLoading(true); + setError(null); + + try { + // Import the Tina client + const { client } = await import("../../../tina/__generated__/client"); + + // Fetch all docs from the main collection + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + + const docs = docsResult.data.docConnection.edges || []; + + const allLinks = []; + const fileStats = {}; + + // Process each document + for (const edge of docs) { + const node = edge.node; + const fileName = `${node._sys.filename}.mdx`; + const filePath = `/docs/${node._sys.relativePath}`; + + // Get the document body content + let content = ""; + if (node.body) { + // Extract text content from rich text blocks + content = extractTextFromBody(node.body); + } + + // Add title content if available + if (node.title) { + content = `# ${node.title}\n\n${content}`; + } + + const links = extractLinksFromContent(content, filePath); + + fileStats[filePath] = { + totalLinks: links.length, + fileName: fileName, + title: node.title || node._sys.filename, + relativePath: node._sys.relativePath, + }; + + allLinks.push(...links); + } + + // Validate all links + const validatedLinks = []; + for (const link of allLinks) { + const validatedLink = await validateLink(link); + validatedLinks.push(validatedLink); + } + + // Calculate statistics + const stats = validatedLinks.reduce( + (acc, link) => { + acc.total++; + if (link.status === "valid") acc.valid++; + else if (link.status === "broken") acc.broken++; + else if (link.status === "warning") acc.warning++; + else if (link.status === "skipped") acc.skipped++; + return acc; + }, + { total: 0, valid: 0, broken: 0, warning: 0, skipped: 0 } + ); + + // Group by file + const linksByFile = {}; + for (const link of validatedLinks) { + const fileName = link.filePath.split("/").pop(); + if (!linksByFile[fileName]) { + linksByFile[fileName] = []; + } + linksByFile[fileName].push(link); + } + + setLinkData({ + stats, + fileStats, + linksByFile, + allLinks: validatedLinks, + brokenLinks: validatedLinks.filter((link) => link.status === "broken"), + warningLinks: validatedLinks.filter( + (link) => link.status === "warning" + ), + timestamp: new Date().toISOString(), + }); + } catch (error) { + setError(error.message); + } finally { + setLoading(false); + } + }; + + // Function to extract text content from Tina CMS rich text body + const extractTextFromBody = (body) => { + if (!body?.children) return ""; + + const extractFromChildren = (children) => { + return children + .map((child) => { + if (child.type === "text") { + return child.text || ""; + } + if (child.type === "a" && child.url) { + const text = child.children + ? extractFromChildren(child.children) + : ""; + return `[${text}](${child.url})`; + } + if (child.children) { + return extractFromChildren(child.children); + } + return ""; + }) + .join(""); + }; + + return extractFromChildren(body.children); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!linkData && !loading && !error) { + return ( +
+
+
+ + + + + + + +

+ Broken Links Dashboard +

+
+ +
+
+ ); + } + + if (loading) { + return ( +
+
+
+ Loading Dashboard +
+
+ Scanning docs for links and validating... +
+ + {/* Progress Bar for Loading */} +
+
+
+
+ +
+ ); + } + + if (error) { + return ( +
+
+
+ + + + + + Error +
+
{error}
+ +
+
+ ); + } + + if (!linkData) { + return ( +
+ No data available +
+ ); + } + + const { stats, fileStats, linksByFile, brokenLinks, warningLinks } = linkData; + const problemLinks = [...(brokenLinks || []), ...(warningLinks || [])]; + + return ( +
+
+
+ + + + + + + +

+ Broken Links Dashboard +

+
+ +
+ + {/* Statistics Cards */} +
+
+
+ + + + +
+
+

Total Links

+

{stats.total}

+
+
+ +
+
+ + + +
+
+

Valid Links

+

{stats.valid}

+
+
+ +
+
+ + + + +
+
+

Broken Links

+

{stats.broken}

+
+
+ +
+
+ + + + + +
+
+

Warning Links

+

+ {stats.warning || 0} +

+
+
+ +
+
+ + + + +
+
+

Files Scanned

+

+ {Object.keys(fileStats).length} +

+
+
+
+ + {/* Broken Links Section */} + {problemLinks.length > 0 && ( +
+

+ 🚨 Problem Links ({problemLinks.length}) +

+
+ {problemLinks.map((link, index) => ( +
+ + +
+ ))} +
+
+ )} + + {/* Files with Broken Links */} + {(() => { + const filesWithProblemLinks = Object.entries(fileStats).filter( + ([_filePath, stats]) => { + const fileName = stats.fileName; + const fileLinks = linksByFile[fileName] || []; + return fileLinks.some( + (link) => link.status === "broken" || link.status === "warning" + ); + } + ); + + if (filesWithProblemLinks.length === 0) { + return null; + } + + return ( +
+
+

+ + + + + Files with Problem Links ({filesWithProblemLinks.length}) +

+ +
+ +
+ {filesWithProblemLinks + .slice(0, showDetails ? undefined : 5) + .map(([filePath, stats], index) => { + const fileName = stats.fileName; + const fileLinks = linksByFile[fileName] || []; + const brokenCount = fileLinks.filter( + (link) => link.status === "broken" + ).length; + const warningCount = fileLinks.filter( + (link) => link.status === "warning" + ).length; + const totalProblems = brokenCount + warningCount; + + return ( +
0 ? "#fff5f5" : "#fff8f0", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > +
+
+ {stats.title || fileName} +
+
+ {stats.totalLinks} total links • {totalProblems}{" "} + problem{totalProblems !== 1 ? "s" : ""} + {brokenCount > 0 && ( + + ({brokenCount} broken + {warningCount > 0 + ? `, ${warningCount} warning` + : ""} + ) + + )} + {brokenCount === 0 && warningCount > 0 && ( + + ({warningCount} warning) + + )} +
+
+ +
+ ); + })} +
+ + {!showDetails && filesWithProblemLinks.length > 5 && ( +
+ And {filesWithProblemLinks.length - 5} more files... +
+ )} +
+ ); + })()} + + {/* Health Status */} +
+
+ + {stats.broken === 0 && (stats.warning || 0) === 0 ? ( + <> + + + + All Links Valid! + + ) : stats.broken === 0 ? ( + <> + + + + + + {stats.warning} Warning Links + + ) : ( + <> + + + + + {stats.broken} Broken Links + {(stats.warning || 0) > 0 + ? ` and ${stats.warning} Warnings` + : ""} + + )} + +
+
+ Link validation completed on {new Date().toLocaleString()} +
+
+
+ ); +}; + +export default BrokenLinksDashboard; diff --git a/src/components/Dashboard/ContentReuseDashboard.jsx b/src/components/Dashboard/ContentReuseDashboard.jsx index cfe9d41e..b33af0cd 100644 --- a/src/components/Dashboard/ContentReuseDashboard.jsx +++ b/src/components/Dashboard/ContentReuseDashboard.jsx @@ -5,41 +5,58 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useEffect, useState } from 'react'; -import { client } from '../../../tina/__generated__/client'; +import React, { useState } from "react"; +import { client } from "../../../tina/__generated__/client"; // --- AST utilities --- function extractPlainText(node) { - if (!node || typeof node !== 'object') return ''; - if (typeof node.text === 'string') return node.text; - if (Array.isArray(node)) return node.map(extractPlainText).filter(Boolean).join(' '); - if (Array.isArray(node.children)) return node.children.map(extractPlainText).filter(Boolean).join(' '); - return ''; + if (!node || typeof node !== "object") return ""; + if (typeof node.text === "string") return node.text; + if (Array.isArray(node)) + return node.map(extractPlainText).filter(Boolean).join(" "); + if (Array.isArray(node.children)) + return node.children.map(extractPlainText).filter(Boolean).join(" "); + return ""; } function extractInlineCode(node, results = []) { - if (!node || typeof node !== 'object') return results; - if (Array.isArray(node)) { node.forEach(n => extractInlineCode(n, results)); return results; } - if (node.name === 'CodeSnippet') return results; // already a proper snippet - if (node.code === true && typeof node.text === 'string' && node.text.trim().length > 1) { + if (!node || typeof node !== "object") return results; + if (Array.isArray(node)) { + for (const n of node) extractInlineCode(n, results); + return results; + } + if (node.name === "CodeSnippet") return results; // already a proper snippet + if ( + node.code === true && + typeof node.text === "string" && + node.text.trim().length > 1 + ) { results.push(node.text.trim()); } - if ((node.type === 'code_block' || node.type === 'code') && typeof node.value === 'string' && node.value.trim()) { + if ( + (node.type === "code_block" || node.type === "code") && + typeof node.value === "string" && + node.value.trim() + ) { results.push(node.value.trim()); } - if (Array.isArray(node.children)) node.children.forEach(c => extractInlineCode(c, results)); + if (Array.isArray(node.children)) + for (const c of node.children) extractInlineCode(c, results); return results; } function extractParagraphTexts(node, results = []) { - if (!node || typeof node !== 'object') return results; - if (Array.isArray(node)) { node.forEach(n => extractParagraphTexts(n, results)); return results; } - if (node.type === 'p' || node.type === 'paragraph') { + if (!node || typeof node !== "object") return results; + if (Array.isArray(node)) { + for (const n of node) extractParagraphTexts(n, results); + return results; + } + if (node.type === "p" || node.type === "paragraph") { const text = extractPlainText(node).trim(); if (text.length >= 60) results.push(text); } else if (Array.isArray(node.children)) { - node.children.forEach(c => extractParagraphTexts(c, results)); + for (const c of node.children) extractParagraphTexts(c, results); } return results; } @@ -56,7 +73,7 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { } const codeSnippets = Object.entries(codeValueMap) .map(([value, paths]) => ({ value, paths })) - .filter(s => s.value.length > 2) + .filter((s) => s.value.length > 2) .sort((a, b) => b.paths.length - a.paths.length); // 2. Glossary terms appearing as plain text (not via GlossaryTerm component) @@ -66,9 +83,19 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { const plainPaths = []; for (const { path, body } of docBodies) { if (!body || term.usedIn.includes(path)) continue; - if (extractPlainText(body).toLowerCase().includes(term.termText.toLowerCase())) plainPaths.push(path); + if ( + extractPlainText(body) + .toLowerCase() + .includes(term.termText.toLowerCase()) + ) + plainPaths.push(path); } - if (plainPaths.length > 0) termText.push({ key: term.key, termText: term.termText, paths: plainPaths }); + if (plainPaths.length > 0) + termText.push({ + key: term.key, + termText: term.termText, + paths: plainPaths, + }); } // 3. Text blocks appearing in 2+ docs that could be snippets @@ -76,9 +103,11 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { for (const { path, body } of docBodies) { if (!body) continue; for (const para of extractParagraphTexts(body)) { - const normalized = para.trim().toLowerCase().replace(/\s+/g, ' '); - if (!paraMap[normalized]) paraMap[normalized] = { original: para, paths: [] }; - if (!paraMap[normalized].paths.includes(path)) paraMap[normalized].paths.push(path); + const normalized = para.trim().toLowerCase().replace(/\s+/g, " "); + if (!paraMap[normalized]) + paraMap[normalized] = { original: para, paths: [] }; + if (!paraMap[normalized].paths.includes(path)) + paraMap[normalized].paths.push(path); } } const duplicateText = Object.values(paraMap) @@ -88,16 +117,27 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { // 4. Variable values appearing as plain text (not via VariableSet component) const variables = []; for (const vs of variableSetsData) { - for (const variable of (vs.variableItems || [])) { - for (const translation of (variable.translations || [])) { - if (translation.lang !== 'en' || !translation.value || translation.value.length < 3) continue; + for (const variable of vs.variableItems || []) { + for (const translation of variable.translations || []) { + if ( + translation.lang !== "en" || + !translation.value || + translation.value.length < 3 + ) + continue; const value = translation.value; const plainPaths = []; for (const { path, body } of docBodies) { if (!body) continue; if (extractPlainText(body).includes(value)) plainPaths.push(path); } - if (plainPaths.length > 0) variables.push({ setName: vs.name, key: variable.key, value, paths: plainPaths }); + if (plainPaths.length > 0) + variables.push({ + setName: vs.name, + key: variable.key, + value, + paths: plainPaths, + }); } } } @@ -108,245 +148,455 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { // --- Data fetching --- async function fetchReuseData() { - const glossaryConn = await client.queries.glossaryTermsConnection({ first: 100 }); - const variableSetsConn = await client.queries.variableSetsConnection({ first: 100 }); + const glossaryConn = await client.queries.glossaryTermsConnection({ + first: 100, + }); + const variableSetsConn = await client.queries.variableSetsConnection({ + first: 100, + }); let snippets = []; if (client.queries.snippetsConnection) { - const snippetsConn = await client.queries.snippetsConnection({ first: 100 }); - snippets = (snippetsConn.data?.snippetsConnection?.edges || []).map(edge => ({ - name: edge.node._sys?.filename, - path: edge.node._sys?.relativePath, - description: edge.node.description || '' - })); + const snippetsConn = await client.queries.snippetsConnection({ + first: 100, + }); + snippets = (snippetsConn.data?.snippetsConnection?.edges || []).map( + (edge) => ({ + name: edge.node._sys?.filename, + path: edge.node._sys?.relativePath, + description: edge.node.description || "", + }) + ); } else { - snippets = [{ name: 'example.mdx', path: 'reuse/snippets/example.mdx', description: 'Snippets Example' }]; + snippets = [ + { + name: "example.mdx", + path: "reuse/snippets/example.mdx", + description: "Snippets Example", + }, + ]; } - const codeSnippets = [{ name: 'example.xml', path: 'reuse/code/example.xml' }]; + const codeSnippets = [ + { name: "example.xml", path: "reuse/code/example.xml" }, + ]; const docsResult = await client.queries.docConnection({ first: 1000 }); const docs = docsResult.data?.docConnection?.edges || []; const docBodies = docs.map((edge) => ({ path: edge.node._sys?.relativePath || edge.node._sys?.filename, - body: edge.node.body || null + body: edge.node.body || null, })); function bodyContainsComponent(node, componentName, propName, matchFn) { - if (!node || typeof node !== 'object') return false; - if (Array.isArray(node)) return node.some(n => bodyContainsComponent(n, componentName, propName, matchFn)); + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) + return node.some((n) => + bodyContainsComponent(n, componentName, propName, matchFn) + ); if (node.name === componentName && node.props) { const val = node.props[propName]; if (matchFn(val)) return true; } if (Array.isArray(node.children)) { - return node.children.some(child => bodyContainsComponent(child, componentName, propName, matchFn)); + return node.children.some((child) => + bodyContainsComponent(child, componentName, propName, matchFn) + ); } return false; } function findComponentUsage(componentName, propName, matchFn) { return docBodies - .filter(({ body }) => bodyContainsComponent(body, componentName, propName, matchFn)) + .filter(({ body }) => + bodyContainsComponent(body, componentName, propName, matchFn) + ) .map(({ path }) => path); } - const glossaryTermsData = (glossaryConn.data?.glossaryTermsConnection?.edges || []).map((edge) => { + const glossaryTermsData = ( + glossaryConn.data?.glossaryTermsConnection?.edges || [] + ).map((edge) => { const item = edge.node.glossaryTerms?.[0] || edge.node; return { key: item.key, - termText: item.translations?.find(t => t.lang === 'en')?.term || item.key, - definition: item.translations?.[0]?.definition || '', - usedIn: findComponentUsage('GlossaryTerm', 'termKey', (val) => val === item.key) + termText: + item.translations?.find((t) => t.lang === "en")?.term || item.key, + definition: item.translations?.[0]?.definition || "", + usedIn: findComponentUsage( + "GlossaryTerm", + "termKey", + (val) => val === item.key + ), }; }); - const variableSetsData = (variableSetsConn.data?.variableSetsConnection?.edges || []).map((edge) => { + const variableSetsData = ( + variableSetsConn.data?.variableSetsConnection?.edges || [] + ).map((edge) => { const item = edge.node.variableSets?.[0] || edge.node; return { name: item.name, variables: item.variables?.length || 0, variableItems: item.variables || [], - usedIn: findComponentUsage('VariableSet', 'variableSelection', (val) => typeof val === 'string' && (val === item.name || val.startsWith(item.name + '_'))) + usedIn: findComponentUsage( + "VariableSet", + "variableSelection", + (val) => + typeof val === "string" && + (val === item.name || val.startsWith(`${item.name}_`)) + ), }; }); - const suggestions = computeSuggestions(docBodies, glossaryTermsData, variableSetsData); + const suggestions = computeSuggestions( + docBodies, + glossaryTermsData, + variableSetsData + ); return { codeSnippets: codeSnippets.map((item) => ({ ...item, - usedIn: findComponentUsage('CodeSnippet', 'filepath', (val) => typeof val === 'string' && val.includes(item.name)) + usedIn: findComponentUsage( + "CodeSnippet", + "filepath", + (val) => typeof val === "string" && val.includes(item.name) + ), })), glossaryTerms: glossaryTermsData, snippets: snippets.map((item) => ({ ...item, - usedIn: findComponentUsage('Snippet', 'filepath', (val) => typeof val === 'string' && val.includes(item.name)) + usedIn: findComponentUsage( + "Snippet", + "filepath", + (val) => typeof val === "string" && val.includes(item.name) + ), })), variableSets: variableSetsData, - suggestions + suggestions, }; } // --- UI helpers --- const getEditUrl = (relativePath) => { - const clean = relativePath.replace(/\.(mdx?|md)$/, ''); + const clean = relativePath.replace(/\.(mdx?|md)$/, ""); return `/admin/index.html#/collections/edit/doc/${clean}`; }; const CATEGORIES = [ { - type: 'codeSnippets', - label: 'Code Snippets', - color: '#3b82f6', - bgClass: 'bg-blue-100', + type: "codeSnippets", + label: "Code Snippets", + color: "#3b82f6", + bgClass: "bg-blue-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'glossaryTerms', - label: 'Glossary Terms', - color: '#10b981', - bgClass: 'bg-green-100', + type: "glossaryTerms", + label: "Glossary Terms", + color: "#10b981", + bgClass: "bg-green-100", icon: ( - - + + ), sectionIcon: ( - - + + - ) + ), }, { - type: 'snippets', - label: 'Snippets', - color: '#f59e0b', - bgClass: 'bg-orange-100', + type: "snippets", + label: "Snippets", + color: "#f59e0b", + bgClass: "bg-orange-100", icon: ( - - - - - - - + + + + + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'variableSets', - label: 'Variable Sets', - color: '#8b5cf6', - bgClass: 'bg-purple-100', + type: "variableSets", + label: "Variable Sets", + color: "#8b5cf6", + bgClass: "bg-purple-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) - } + ), + }, ]; const SUGGESTION_CATEGORIES = [ { - type: 'codeSnippets', - label: 'Possible Snippets', - description: 'Inline code blocks that could become snippets', - color: '#3b82f6', - bgClass: 'bg-blue-100', + type: "codeSnippets", + label: "Possible Snippets", + description: "Inline code blocks that could become snippets", + color: "#3b82f6", + bgClass: "bg-blue-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'termText', - label: 'Possible Terms', - description: 'Plain text glossary terms', - color: '#10b981', - bgClass: 'bg-green-100', + type: "termText", + label: "Possible Terms", + description: "Plain text glossary terms", + color: "#10b981", + bgClass: "bg-green-100", icon: ( - - + + ), sectionIcon: ( - - + + - ) + ), }, { - type: 'duplicateText', - label: 'Possible Snippets', - description: 'Text blocks appearing in two or more topics', - color: '#f59e0b', - bgClass: 'bg-orange-100', + type: "duplicateText", + label: "Possible Snippets", + description: "Text blocks appearing in two or more topics", + color: "#f59e0b", + bgClass: "bg-orange-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'variables', - label: 'Possible Variables', - description: 'Plain text variable values', - color: '#8b5cf6', - bgClass: 'bg-purple-100', + type: "variables", + label: "Possible Variables", + description: "Plain text variable values", + color: "#8b5cf6", + bgClass: "bg-purple-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) - } + ), + }, ]; // --- Component --- @@ -367,56 +617,105 @@ const ContentReuseDashboard = () => { setLoading(false); }) .catch((err) => { - setError(err.message || 'Failed to load content reuse data'); + setError(err.message || "Failed to load content reuse data"); setLoading(false); }); }; const headerButtons = (label) => ( ); const dashboardHeader = ( -
-
+
+
- - - - - + + + + + -

Content Reuse Dashboard

+

+ Content Reuse Dashboard +

- {headerButtons(loading ? 'Loading...' : reuseData ? 'Refresh' : 'Load')} + {headerButtons(loading ? "Loading..." : reuseData ? "Refresh" : "Load")}
); if (!reuseData && !loading && !error) { return ( -
+
{dashboardHeader}
); @@ -424,27 +723,51 @@ const ContentReuseDashboard = () => { if (loading) { return ( -
-
-
Loading Dashboard
-
Loading content reuse data...
-
-
+
+
+
+ Loading Dashboard +
+
+ Loading content reuse data... +
+
+
-
- ); - } - - if (!contentData && !loading) { - return ( -
-
-
- - - - - - - - - -

Content Overview Dashboard

-
- -
- {error && ( -
- Error: {error} -
- )} -
- ); - } - - const StatCard = ({ title, count, total, color, percentage, onClick }) => { - const getStatusIcon = (status) => { - const icons = { - 'Draft': ( - - - - - - - ), - 'Review': ( - - - - - ), - 'Translate': ( - - - - - - ), - 'Approved': ( - - - - - - - - ), - 'Published': ( - - - - - - - ), - 'Unlisted': ( - - - - - ) - }; - return icons[status] || icons['Draft']; - }; - - const getBackgroundColor = (status) => { - const backgrounds = { - 'Draft': 'bg-orange-100', - 'Review': 'bg-blue-100', - 'Translate': 'bg-purple-100', - 'Approved': 'bg-green-100', - 'Published': 'bg-emerald-100', - 'Unlisted': 'bg-gray-100' - }; - return backgrounds[status] || 'bg-gray-100'; - }; - - return ( -
count > 0 && onClick && onClick(title)} - className={`bg-white rounded-xl border border-gray-200 shadow-sm flex items-center gap-4 p-6 transition-all duration-200 ${ - count > 0 ? 'cursor-pointer hover:shadow-md' : 'cursor-default opacity-60' - }`} - > -
-
{getStatusIcon(title)}
-
-
-

{title}

-

{count || 0}

-

- {isNaN(percentage) ? '0' : percentage.toFixed(0)}% of {total} -

-
-
- ); - }; - - return ( -
-
-
- - - - - - - - - -

- Content Overview Dashboard -

-
-
-
- Overall Progress: {contentData.totalProgress}% -
- -
-
- - {/* Documentation Workflow */} -
-

- - - - - - - Documentation ({contentData.docs.total} topics) -

-
- - - - - - -
-
- - {/* Document List Modal */} - {showDocuments && ( -
-
-
-

- - - - - {showDocuments} Documents ({filteredDocs.length}) -

- -
- -
- {filteredDocs.length === 0 ? ( -
- No documents found with {showDocuments.toLowerCase()} status -
- ) : ( - filteredDocs.map((edge, index) => { - const doc = edge.node; - return ( -
-
-
- {doc.title || doc._sys.filename} -
-
- {doc._sys.relativePath} -
- {doc.description && ( -
- {doc.description.length > 100 ? doc.description.substring(0, 100) + '...' : doc.description} -
- )} -
- -
- - {getStatus(doc)} - - - - Edit - -
-
- ); - }) - )} -
-
-
- )} - - {/* Recent Activity */} -
-
-

- - - - Recent Activity -

-
- - -
-
-
- {contentData.recentActivity.length === 0 ? ( -
- No recent activity found for the selected time period -
- ) : ( - contentData.recentActivity.map((item, index) => ( -
-
-
- {item.title} -
-
- - {item.type} - - {item.path} -
-
-
-
- {item.status} -
-
- {new Date(item.lastModified).toLocaleDateString()} -
- - Edit - -
-
- )) - )} -
-
- - {error && ( -
- - - - - - - Some data may be simulated due to connection issues: {error} - -
- )} -
- ); -}; - -export default Dashboard1; \ No newline at end of file +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useCallback, useEffect, useRef, useState } from "react"; + +const getStatus = (node) => { + if (node.published) return "Published"; + if (node.approved) return "Approved"; + if (node.translate) return "Translate"; + if (node.review) return "Review"; + if (node.draft) return "Draft"; + if (node.unlisted) return "Unlisted"; + return "No Status"; +}; + +const Dashboard1 = () => { + const [contentData, setContentData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showDocuments, setShowDocuments] = useState(null); + const [filteredDocs, setFilteredDocs] = useState([]); + const [allDocs, setAllDocs] = useState([]); + const [activityLimit, setActivityLimit] = useState(10); + const [activityPeriod, setActivityPeriod] = useState("week"); // 'week', 'month', 'all' + + // Tracks whether the overview has been loaded at least once, so changing a + // filter refetches but mounting does not auto-load. Kept in a ref so the + // effect below doesn't have to depend on contentData (which the fetch sets, + // which would loop). + const hasLoadedRef = useRef(false); + + const fetchContentOverview = useCallback(async () => { + setLoading(true); + setError(null); + + try { + const { client } = await import("../../../tina/__generated__/client"); + + // Fetch all docs from main collection + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + + const docs = docsResult.data.docConnection.edges || []; + + // Store all docs for filtering + setAllDocs(docs); + + // Analyze workflow status for docs + const docStats = docs.reduce( + (acc, edge) => { + const node = edge.node; + acc.total++; + + if (node.draft) acc.draft++; + if (node.review) acc.review++; + if (node.translate) acc.translate++; + if (node.approved) acc.approved++; + if (node.published) acc.published++; + if (node.unlisted) acc.unlisted++; + + return acc; + }, + { + total: 0, + draft: 0, + review: 0, + translate: 0, + approved: 0, + published: 0, + unlisted: 0, + } + ); + + // Get recent activity with configurable filters + // Only include docs that have a lastmod field set + const now = new Date(); + const getTimePeriodFilter = () => { + if (activityPeriod === "week") { + return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); // 7 days ago + } else if (activityPeriod === "month") { + return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); // 30 days ago + } + return null; // No time filter for 'all' + }; + + const timeCutoff = getTimePeriodFilter(); + + const recentActivity = docs + .filter((edge) => { + const node = edge.node; + const _relativePath = node._sys.relativePath; + + // Skip documents without lastmod field + if (!node.lastmod) return false; + + // Apply time filter if specified + if (timeCutoff) { + const docDate = new Date(node.lastmod); + if (docDate < timeCutoff) return false; + } + + return true; + }) + .map((edge) => { + const node = edge.node; + // Use lastmod as primary source, with system lastModified as fallback + const timestamp = node.lastmod || node._sys?.lastModified; + + return { + title: node.title || node._sys.filename, + type: "Documentation", + status: getStatus(node), + lastModified: timestamp, + path: node._sys.relativePath, + // Debug info + debugInfo: { + sysLastModified: node._sys?.lastModified, + lastmod: node.lastmod, + filename: node._sys.filename, + }, + }; + }) + .sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified)) + .slice(0, activityLimit); + + setContentData({ + docs: docStats, + recentActivity, + totalProgress: + Math.round((docStats.published / docStats.total) * 100) || 0, + }); + } catch (err) { + setError(err.message); + } finally { + hasLoadedRef.current = true; + setLoading(false); + } + }, [activityLimit, activityPeriod]); + + const getStatusColor = (status) => { + const colors = { + "No Status": "#6b7280", + Draft: "#f59e0b", + Review: "#3b82f6", + Translate: "#8b5cf6", + Approved: "#10b981", + Published: "#059669", + Unlisted: "#6b7280", + }; + return colors[status] || "#6b7280"; + }; + + const filterDocumentsByStatus = (status) => { + const filtered = allDocs.filter((edge) => { + const node = edge.node; + switch (status.toLowerCase()) { + case "draft": + return node.draft; + case "review": + return node.review; + case "translate": + return node.translate; + case "approved": + return node.approved; + case "published": + return node.published; + case "unlisted": + return node.unlisted; + default: + return false; + } + }); + setFilteredDocs(filtered); + setShowDocuments(status); + }; + + const getEditUrl = (doc) => { + const isLocal = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; + const relativePath = doc._sys.relativePath; + + if (isLocal) { + // Local Tina admin URL + return `/admin/index.html#/collections/edit/doc/${relativePath.replace(".mdx", "").replace(".md", "")}`; + } else { + // Production Tina admin URL (TinaCloud) + return `/admin/index.html#/collections/edit/doc/${relativePath.replace(".mdx", "").replace(".md", "")}`; + } + }; + + // Refetch when the activity filters change (fetchContentOverview's identity + // changes with them), but not before the first load. + useEffect(() => { + if (!hasLoadedRef.current) return; + fetchContentOverview(); + }, [fetchContentOverview]); + + if (loading) { + return ( +
+
+
+ Loading Dashboard +
+
+ Loading content overview... +
+ + {/* Progress Bar for Loading */} +
+
+
+
+ +
+ ); + } + + if (!contentData && !loading) { + return ( +
+
+
+ + + + + + + + + +

+ Content Overview Dashboard +

+
+ +
+ {error && ( +
+ Error: {error} +
+ )} +
+ ); + } + + const StatCard = ({ title, count, total, color, percentage, onClick }) => { + const getStatusIcon = (status) => { + const icons = { + Draft: ( + + + + + + + ), + Review: ( + + + + + ), + Translate: ( + + + + + + ), + Approved: ( + + + + + + + + ), + Published: ( + + + + + + + ), + Unlisted: ( + + + + + ), + }; + return icons[status] || icons.Draft; + }; + + const getBackgroundColor = (status) => { + const backgrounds = { + Draft: "bg-orange-100", + Review: "bg-blue-100", + Translate: "bg-purple-100", + Approved: "bg-green-100", + Published: "bg-emerald-100", + Unlisted: "bg-gray-100", + }; + return backgrounds[status] || "bg-gray-100"; + }; + + return ( + // biome-ignore lint/a11y/useSemanticElements: the card body is block content, which cannot legally nest inside a +
+
+ + {/* Documentation Workflow */} +
+

+ + + + + + + Documentation ({contentData.docs.total} topics) +

+
+ + + + + + +
+
+ + {/* Document List Modal */} + {showDocuments && ( +
+
+
+

+ + + + + {showDocuments} Documents ({filteredDocs.length}) +

+ +
+ +
+ {filteredDocs.length === 0 ? ( +
+ No documents found with {showDocuments.toLowerCase()} status +
+ ) : ( + filteredDocs.map((edge, index) => { + const doc = edge.node; + return ( +
+
+
+ {doc.title || doc._sys.filename} +
+
+ {doc._sys.relativePath} +
+ {doc.description && ( +
+ {doc.description.length > 100 + ? `${doc.description.substring(0, 100)}...` + : doc.description} +
+ )} +
+ +
+ + {getStatus(doc)} + + + + Edit + +
+
+ ); + }) + )} +
+
+
+ )} + + {/* Recent Activity */} +
+
+

+ + + + Recent Activity +

+
+ + +
+
+
+ {contentData.recentActivity.length === 0 ? ( +
+ No recent activity found for the selected time period +
+ ) : ( + contentData.recentActivity.map((item, index) => ( +
+
+
+ {item.title} +
+
+ + {item.type} + + {item.path} +
+
+
+
+ {item.status} +
+
+ {new Date(item.lastModified).toLocaleDateString()} +
+ + Edit + +
+
+ )) + )} +
+
+ + {error && ( +
+ + + + + + + Some data may be simulated due to connection issues: {error} + +
+ )} +
+ ); +}; + +export default Dashboard1; diff --git a/src/components/Dashboard/DocumentMutationDashboard.jsx b/src/components/Dashboard/DocumentMutationDashboard.jsx index 2209aa3c..6423b693 100644 --- a/src/components/Dashboard/DocumentMutationDashboard.jsx +++ b/src/components/Dashboard/DocumentMutationDashboard.jsx @@ -5,27 +5,35 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useState } from 'react'; +import React, { useState } from "react"; const DocumentMutationDashboard = () => { - const [createTitle, setCreateTitle] = useState(''); - const [deleteId, setDeleteId] = useState(''); - const [updateId, setUpdateId] = useState(''); - const [updateTitle, setUpdateTitle] = useState(''); - const [status, setStatus] = useState(''); + const [createTitle, setCreateTitle] = useState(""); + const [deleteId, setDeleteId] = useState(""); + const [updateId, setUpdateId] = useState(""); + const [updateTitle, setUpdateTitle] = useState(""); + const [status, setStatus] = useState(""); const [documents, setDocuments] = useState([]); // Real mutation handlers // Use Tina client for GraphQL operations const handleListDocuments = async () => { - setStatus(''); + setStatus(""); setDocuments([]); try { - const { client } = await import('../../../tina/__generated__/client'); - const docsResult = await client.queries.docConnection({ sort: 'title', first: 500 }); + const { client } = await import("../../../tina/__generated__/client"); + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, + }); const docs = docsResult.data.docConnection.edges || []; - setDocuments(docs.map(edge => ({ id: edge.node._sys.filename, title: edge.node.title || edge.node._sys.filename }))); - setStatus('Listed documents'); + setDocuments( + docs.map((edge) => ({ + id: edge.node._sys.filename, + title: edge.node.title || edge.node._sys.filename, + })) + ); + setStatus("Listed documents"); } catch (err) { setStatus(`Error: ${err.message}`); setDocuments([]); @@ -33,9 +41,9 @@ const DocumentMutationDashboard = () => { }; const handleCreate = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation CreateDocument($collection: String!, $relativePath: String!, $params: DocumentMutation!) { createDocument(collection: $collection, relativePath: $relativePath, params: $params) { @@ -46,23 +54,23 @@ const DocumentMutationDashboard = () => { } } `; - const variables = { - collection: 'doc', - relativePath: `${createTitle.replace(/\s+/g, '-')}.mdx`, - params: { doc: { title: createTitle } } + const variables = { + collection: "doc", + relativePath: `${createTitle.replace(/\s+/g, "-")}.mdx`, + params: { doc: { title: createTitle } }, }; const result = await client.request({ query: mutation, variables }); setStatus(`Created document: ${result.data.createDocument.title}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setCreateTitle(''); + setCreateTitle(""); }; const handleDelete = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation DeleteDocument($collection: String!, $relativePath: String!) { deleteDocument(collection: $collection, relativePath: $relativePath) { @@ -73,21 +81,21 @@ const DocumentMutationDashboard = () => { } `; const variables = { - collection: 'doc', - relativePath: `${deleteId}.mdx` + collection: "doc", + relativePath: `${deleteId}.mdx`, }; await client.request({ query: mutation, variables }); setStatus(`Deleted document ID: ${deleteId}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setDeleteId(''); + setDeleteId(""); }; const handleUpdate = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation UpdateDocument($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) { updateDocument(collection: $collection, relativePath: $relativePath, params: $params) { @@ -98,71 +106,94 @@ const DocumentMutationDashboard = () => { } } `; - const variables = { - collection: 'doc', - relativePath: `${updateId}.mdx`, - params: { doc: { title: updateTitle } } - }; + const variables = { + collection: "doc", + relativePath: `${updateId}.mdx`, + params: { doc: { title: updateTitle } }, + }; await client.request({ query: mutation, variables }); setStatus(`Updated document ID: ${updateId} with title: ${updateTitle}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setUpdateId(''); - setUpdateTitle(''); + setUpdateId(""); + setUpdateTitle(""); }; return ( -
+

Document Mutation Dashboard

-
+

Create Document

setCreateTitle(e.target.value)} + onChange={(e) => setCreateTitle(e.target.value)} /> - +
-
+

Delete Document

setDeleteId(e.target.value)} + onChange={(e) => setDeleteId(e.target.value)} /> - +
-
+

Update Document

setUpdateId(e.target.value)} + onChange={(e) => setUpdateId(e.target.value)} /> setUpdateTitle(e.target.value)} + onChange={(e) => setUpdateTitle(e.target.value)} /> - +
-
+

List Documents

- + {documents.length > 0 && ( -
    - {documents.map(doc => ( -
  • {doc.title} ({doc.id})
  • +
      + {documents.map((doc) => ( +
    • + {doc.title} ({doc.id}) +
    • ))}
    )}
- {status &&
{status}
} + {status && ( +
{status}
+ )}
); }; diff --git a/src/components/Dashboard/GraphQLtest.jsx b/src/components/Dashboard/GraphQLtest.jsx index f67dd7fe..443e7708 100644 --- a/src/components/Dashboard/GraphQLtest.jsx +++ b/src/components/Dashboard/GraphQLtest.jsx @@ -7,69 +7,76 @@ // add this dashboard to template.jsx if you have GraphQL connection issues -import React, { useState, useEffect } from 'react'; -import docusaurusSettings from '../../../config/docusaurus/index.json'; +import React, { useCallback, useEffect, useRef, useState } from "react"; +import docusaurusSettings from "../../../config/docusaurus/index.json"; -const Dashboard3 = () => { +const GraphQLtest = () => { const [connectionTests, setConnectionTests] = useState([]); const [loading, setLoading] = useState(false); + // Concurrency guard: a ref rather than `loading` state, so testConnections + // keeps a stable identity and the effect below doesn't re-run on every toggle. + const runningRef = useRef(false); + + const testConnections = useCallback(async () => { + if (runningRef.current) return; // Prevent concurrent executions + runningRef.current = true; - const testConnections = async () => { - if (loading) return; // Prevent concurrent executions - setLoading(true); const tests = []; try { // Test 1: Try the original GraphQL endpoint try { - const response1 = await fetch('http://localhost:4001/graphql', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + const response1 = await fetch("http://localhost:4001/graphql", { + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - query: '{ __typename }' + query: "{ __typename }", }), }); tests.push({ - name: 'http://localhost:4001/graphql', - status: response1.ok ? 'SUCCESS' : `FAILED (${response1.status})`, - details: response1.ok ? 'Connected successfully' : `HTTP ${response1.status}`, - color: response1.ok ? '#059669' : '#dc2626' + name: "http://localhost:4001/graphql", + status: response1.ok ? "SUCCESS" : `FAILED (${response1.status})`, + details: response1.ok + ? "Connected successfully" + : `HTTP ${response1.status}`, + color: response1.ok ? "#059669" : "#dc2626", }); } catch (err) { tests.push({ - name: 'http://localhost:4001/graphql', - status: 'ERROR', + name: "http://localhost:4001/graphql", + status: "ERROR", details: err.message, - color: '#dc2626' + color: "#dc2626", }); } // Test 2: Check TinaCloud configuration try { const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - + if (!clientId) { tests.push({ - name: 'TinaCloud Configuration', - status: 'CONFIG ERROR', - details: 'NEXT_PUBLIC_TINA_CLIENT_ID is not set in environment variables', - color: '#f59e0b' + name: "TinaCloud Configuration", + status: "CONFIG ERROR", + details: + "NEXT_PUBLIC_TINA_CLIENT_ID is not set in environment variables", + color: "#f59e0b", }); } else { tests.push({ - name: 'TinaCloud Configuration', - status: 'CONFIGURED', + name: "TinaCloud Configuration", + status: "CONFIGURED", details: `Client ID configured. Note: TINA_TOKEN is server-side only (this is correct for security).`, - color: '#059669' + color: "#059669", }); } } catch (err) { tests.push({ - name: 'TinaCloud Configuration', - status: 'ERROR', + name: "TinaCloud Configuration", + status: "ERROR", details: `Error checking configuration: ${err.message}`, - color: '#dc2626' + color: "#dc2626", }); } @@ -77,60 +84,69 @@ const Dashboard3 = () => { try { const siteUrl = docusaurusSettings.url.siteUrl; const url = new URL(siteUrl); - + // According to Tina docs, the GraphQL API is at /admin/api/graphql const correctGraphQLUrl = `https://${url.hostname}/admin/api/graphql`; - + const response3 = await fetch(correctGraphQLUrl, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query: '{ __typename }' }), + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "{ __typename }" }), }); tests.push({ name: `Live Site GraphQL (${correctGraphQLUrl})`, - status: response3.ok ? 'SUCCESS' : response3.status === 405 ? 'SECURED āœ“' : `FAILED (${response3.status})`, - details: response3.ok - ? 'Connected to live site GraphQL' - : response3.status === 405 - ? 'šŸ”’ HTTP 405 - Site is properly secured. Direct GraphQL access blocked (this is correct!)' + status: response3.ok + ? "SUCCESS" + : response3.status === 405 + ? "SECURED āœ“" + : `FAILED (${response3.status})`, + details: response3.ok + ? "Connected to live site GraphQL" + : response3.status === 405 + ? "šŸ”’ HTTP 405 - Site is properly secured. Direct GraphQL access blocked (this is correct!)" : `HTTP ${response3.status} - This is normal for production sites`, - color: response3.ok ? '#059669' : response3.status === 405 ? '#059669' : '#f59e0b' + color: response3.ok + ? "#059669" + : response3.status === 405 + ? "#059669" + : "#f59e0b", }); - } catch (err) { + } catch (_err) { tests.push({ - name: 'Live Site GraphQL', - status: 'SECURED āœ“', - details: 'šŸ”’ Network blocked - Production sites properly block direct GraphQL access for security. Use TinaCMS Generated Client instead.', - color: '#059669' + name: "Live Site GraphQL", + status: "SECURED āœ“", + details: + "šŸ”’ Network blocked - Production sites properly block direct GraphQL access for security. Use TinaCMS Generated Client instead.", + color: "#059669", }); } // Test 4: Check if we can import the Tina client try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); if (client) { tests.push({ - name: 'Tina Generated Client', - status: 'AVAILABLE', - details: 'Client imported successfully', - color: '#059669' + name: "Tina Generated Client", + status: "AVAILABLE", + details: "Client imported successfully", + color: "#059669", }); // Test 5: Try using the Tina client try { const result = await client.queries.docConnection(); tests.push({ - name: 'Tina Client Query', - status: 'SUCCESS', + name: "Tina Client Query", + status: "SUCCESS", details: `Found ${result.data.docConnection.edges.length} documents`, - color: '#059669' + color: "#059669", }); } catch (clientErr) { tests.push({ - name: 'Tina Client Query', - status: 'ERROR', + name: "Tina Client Query", + status: "ERROR", details: clientErr.message, - color: '#dc2626' + color: "#dc2626", }); } @@ -138,151 +154,180 @@ const Dashboard3 = () => { try { const docResult = await client.queries.docConnection({ first: 3, - sort: 'title' + sort: "title", }); - + const docs = docResult.data.docConnection.edges; - const sampleDocs = docs.slice(0, 3).map(edge => edge.node.title || edge.node._sys.filename).join(', '); - + const sampleDocs = docs + .slice(0, 3) + .map((edge) => edge.node.title || edge.node._sys.filename) + .join(", "); + // Determine data source based on environment - const isLocalDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; + const isLocalDev = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const dataSource = isLocalDev - ? 'Local files (localhost GraphQL server)' - : clientId - ? 'ā˜ļø TinaCloud (live site via content.tinajs.io)' - : 'ā“ Unknown source'; - + const dataSource = isLocalDev + ? "Local files (localhost GraphQL server)" + : clientId + ? "ā˜ļø TinaCloud (live site via content.tinajs.io)" + : "ā“ Unknown source"; + tests.push({ - name: 'Tina Admin Data Access', - status: 'SUCCESS', - details: `Retrieved ${docs.length} documents. Source: ${dataSource}. Sample: ${sampleDocs || 'No titles available'}`, - color: '#059669' + name: "Tina Admin Data Access", + status: "SUCCESS", + details: `Retrieved ${docs.length} documents. Source: ${dataSource}. Sample: ${sampleDocs || "No titles available"}`, + color: "#059669", }); // Test 7: Try to get a specific document if (docs.length > 0) { try { const firstDoc = docs[0].node; - const docQuery = await client.queries.doc({ - relativePath: firstDoc._sys.relativePath + const docQuery = await client.queries.doc({ + relativePath: firstDoc._sys.relativePath, }); - + tests.push({ - name: 'Tina Document Query', - status: 'SUCCESS', + name: "Tina Document Query", + status: "SUCCESS", details: `Successfully fetched full document: "${docQuery.data.doc.title || docQuery.data.doc._sys.filename}"`, - color: '#059669' + color: "#059669", }); } catch (docErr) { tests.push({ - name: 'Tina Document Query', - status: 'PARTIAL', + name: "Tina Document Query", + status: "PARTIAL", details: `Document list works but single doc query failed: ${docErr.message}`, - color: '#f59e0b' + color: "#f59e0b", }); } } } catch (dataErr) { tests.push({ - name: 'Tina Admin Data Access', - status: 'ERROR', + name: "Tina Admin Data Access", + status: "ERROR", details: `Failed to fetch documents from admin context: ${dataErr.message}`, - color: '#dc2626' + color: "#dc2626", }); } } } catch (err) { tests.push({ - name: 'Tina Generated Client', - status: 'NOT AVAILABLE', + name: "Tina Generated Client", + status: "NOT AVAILABLE", details: err.message, - color: '#f59e0b' + color: "#f59e0b", }); } // Test 8: Environment detection and context - const isLocalDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; - const isProduction = process.env.NODE_ENV === 'production'; + const isLocalDev = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; + const _isProduction = process.env.NODE_ENV === "production"; const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - + tests.push({ - name: 'Environment Detection', - status: 'INFO', - details: `${isLocalDev ? 'Local Development' : 'Cloud/Production'} | Node ENV: ${process.env.NODE_ENV} | Client ID: ${clientId ? 'Set' : 'Not Set'}`, - color: '#2563eb' + name: "Environment Detection", + status: "INFO", + details: `${isLocalDev ? "Local Development" : "Cloud/Production"} | Node ENV: ${process.env.NODE_ENV} | Client ID: ${clientId ? "Set" : "Not Set"}`, + color: "#2563eb", }); setConnectionTests(tests); } catch (globalErr) { - console.error('Global test error:', globalErr); - setConnectionTests([{ - name: 'Global Error', - status: 'ERROR', - details: globalErr.message, - color: '#dc2626' - }]); + setConnectionTests([ + { + name: "Global Error", + status: "ERROR", + details: globalErr.message, + color: "#dc2626", + }, + ]); } finally { + runningRef.current = false; setLoading(false); } - }; + }, []); useEffect(() => { testConnections(); - }, []); + }, [testConnections]); return ( -
-
-

šŸ”Œ GraphQL Connection Test

-
- -
+ +
{connectionTests.map((test, index) => ( -
-
-
{test.name}
-
+
+
+ {test.name} +
+
{test.status}
-
+
{test.details}
@@ -290,11 +335,13 @@ const Dashboard3 = () => {
{loading && ( -
+
Running connection tests...
)} @@ -302,4 +349,4 @@ const Dashboard3 = () => { ); }; -export default GraphQLtest; \ No newline at end of file +export default GraphQLtest; diff --git a/src/components/Dashboard/MediaDashboard.jsx b/src/components/Dashboard/MediaDashboard.jsx index 03a4bdd9..662c933f 100644 --- a/src/components/Dashboard/MediaDashboard.jsx +++ b/src/components/Dashboard/MediaDashboard.jsx @@ -1,822 +1,1054 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const MediaDashboard = () => { - const [mediaData, setMediaData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [mediaFiles, setMediaFiles] = useState([]); - const [filterType, setFilterType] = useState('all'); - const [imageUsages, setImageUsages] = useState({}); - const [expandedFile, setExpandedFile] = useState(null); - const [lightboxImage, setLightboxImage] = useState(null); - - // Helper: get extension from filename - const getExtension = (filename) => { - const match = filename.match(/\.([^.]+)$/); - return match ? match[1].toLowerCase() : ''; - }; - - // Helper: guess type from extension - const getType = (filename) => { - const ext = getExtension(filename); - if (["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "tiff", "ico", "avif"].includes(ext)) return "image"; - if (["mp4", "webm", "mov", "avi", "mkv"].includes(ext)) return "video"; - if (["mp3", "wav", "ogg", "flac"].includes(ext)) return "audio"; - return "file"; - }; - - const openLightbox = (file) => { - setLightboxImage(file); - }; - - const closeLightbox = () => { - setLightboxImage(null); - }; - - const extractTextFromAST = (node) => { - if (!node) return ''; - - let text = ''; - - if (typeof node === 'string') { - return node; - } - - if (typeof node === 'object') { - // Handle different node types - if (node.type === 'text' && node.value) { - text += node.value; - } - - // Handle nodes with props (like Figure components) - if (node.props) { - // Extract props as text for searching - text += JSON.stringify(node.props); - } - - // Handle JSX elements - if (node.type === 'element' && node.props) { - text += JSON.stringify(node.props); - } - - // Handle MDX JSX elements - if (node.name === 'Figure' && node.props) { - text += JSON.stringify(node.props); - } - - // Recursively process children - if (node.children && Array.isArray(node.children)) { - for (const child of node.children) { - text += extractTextFromAST(child); - } - } - - // Handle other array-like structures - if (Array.isArray(node)) { - for (const item of node) { - text += extractTextFromAST(item); - } - } - } - - return text; - }; - - const scanDocumentsForImageUsage = async (mediaFiles) => { - try { - const { client } = await import('../../../tina/__generated__/client'); - // Fetch all documents to scan for image usage using connection query - const docsResult = await client.queries.docConnection({ - sort: 'title', - first: 500 // Request more documents - }); - const docs = docsResult.data.docConnection.edges || []; - const usages = {}; - mediaFiles.forEach(file => { usages[file.path] = []; }); - docs.forEach(edge => { - const node = edge.node; - const title = node.title || node._sys.filename; - const relativePath = node._sys.relativePath; - let content = ''; - if (node.body && typeof node.body === 'object') { - content = extractTextFromAST(node.body); - } else if (typeof node.body === 'string') { - content = node.body; - } - if (content && (relativePath.includes('figures.mdx') || relativePath.includes('assets.mdx'))) { - console.log(`Main scan - ${relativePath}, content length: ${content.length}`); - } - mediaFiles.forEach(file => { - if (content.includes(file.filename) || content.includes(file.path)) { - usages[file.path].push({ - title, - relativePath, - filename: node._sys.filename, - lastModified: node.lastmod || node._sys?.lastModified, - editUrl: `/admin/#/collections/edit/doc/${relativePath.replace(/\.[^/.]+$/, '')}` - }); - } - }); - }); - setImageUsages(usages); - return usages; - } catch (err) { - console.error('Error scanning documents for image usage:', err); - return {}; - } - }; - - const fetchMediaFiles = async () => { - setLoading(true); - setError(null); - try { - const { client } = await import('../../../tina/__generated__/client'); - // Query Tina's MediaCollection (reuse/media/index.json) - const mediaResult = await client.queries.media({ relativePath: "index.json" }); - const mediaList = (mediaResult?.data?.media?.media) || []; - // Add type, extension, url, and name fields for UI compatibility - const files = mediaList.map((file) => { - const ext = getExtension(file.filename); - const type = getType(file.filename); - // Use file.path for correct subfolder support - const url = `/img/${file.path}`; - return { - ...file, - name: file.filename, - extension: ext, - type, - url, - lastModified: file.lastModified || '', - dimensions: file.dimensions || '', - }; - }); - setMediaFiles(files); - const mediaStats = { - total: files.length, - images: files.filter(f => f.type === 'image').length, - totalSize: files.reduce((acc, file) => acc + (typeof file.size === 'number' ? file.size / 1024 : 0), 0), - }; - setMediaData({ - files, - stats: mediaStats - }); - await scanDocumentsForImageUsage(files); - } catch (err) { - console.error('Error fetching media files:', err); - setError('Failed to load media files from Tina MediaCollection.'); - } finally { - setLoading(false); - } - }; - - - - const getFilteredFiles = () => { - if (filterType === 'all') return mediaFiles; - return mediaFiles.filter(file => { - switch (filterType) { - case 'images': - return file.type === 'image'; - case 'recent': - const oneWeekAgo = new Date(); - oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); - return new Date(file.lastModified) > oneWeekAgo; - case 'used': - return (imageUsages[file.path] || []).length > 0; - case 'unused': - return (imageUsages[file.path] || []).length === 0; - default: - return true; - } - }); - }; - - const formatFileSize = (size) => { - // size is in bytes (number) - if (typeof size !== 'number') return size; - if (size >= 1024 * 1024) { - return `${(size / (1024 * 1024)).toFixed(1)} MB`; - } - if (size >= 1024) { - return `${(size / 1024).toFixed(1)} KB`; - } - return `${size} B`; - }; - - const formatDate = (dateStr) => { - return new Date(dateStr).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric' - }); - }; - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!mediaData && !loading && !error) { - return ( -
-
-
- - - - - - - -

- Media Usage Dashboard -

-
- -
-
- ); - } - - if (loading) { - return ( -
-
-
- Loading Dashboard -
-
- Loading media files... -
- - {/* Progress Bar for Loading */} -
-
-
-
- -
- ); - } - - if (error) { - return ( -
-
-

Error

-

{error}

-
-
- ); - } - - if (!mediaData) { - return null; - } - - const filteredFiles = getFilteredFiles(); - - return ( -
- {/* Header */} -
-
-
- - - - - - - -

- Media Usage Dashboard -

-
- -
- - {/* Media Statistics Cards */} -
-
-
- - - - -
-
-

Total Files

-

{mediaData.stats.total}

-
-
- -
-
- - - - - -
-
-

Images

-

{mediaData.stats.images}

-
-
- -
-
- - - -
-
-

Used

-

{Object.values(imageUsages).filter(usages => usages.length > 0).length}

-
-
- -
-
- - - - -
-
-

Unused

-

{Object.values(imageUsages).filter(usages => usages.length === 0).length}

-
-
- -
-
- - - - -
-
-

Total Size

-

{mediaData.stats.totalSize.toFixed(1)} KB

-
-
-
- - {/* Filter Controls */} -
- Filter: - {['all', 'images', 'recent', 'used', 'unused'].map((filter) => ( - - ))} -
-
- - {/* Media Files List */} -
- {filteredFiles.length === 0 ? ( -
-

No media files found for the current filter.

-
- ) : ( -
- {filteredFiles.map((file, index) => ( -
{ - e.currentTarget.style.backgroundColor = '#f6f8fa'; - e.currentTarget.style.borderColor = '#8c959f'; - }} - onMouseLeave={(e) => { - e.currentTarget.style.backgroundColor = '#ffffff'; - e.currentTarget.style.borderColor = '#d1d9e0'; - }} - > - {/* File preview */} -
- {file.type === 'image' ? ( - {file.filename} openLightbox(file)} - onError={(e) => { - e.target.style.display = 'none'; - e.target.nextSibling.style.display = 'flex'; - }} - onMouseOver={(e) => e.target.style.opacity = '0.8'} - onMouseOut={(e) => e.target.style.opacity = '1'} - /> - ) : null} -
- {file.extension ? file.extension.toUpperCase() : ''} -
-
- - {/* File details */} -
-
- {file.filename} -
-
- {file.path} -
-
- {formatFileSize(file.size)} - {file.extension === 'svg' ? ( - vector - ) : ( - file.dimensions && {file.dimensions} - )} - {file.lastModified && Modified: {formatDate(file.lastModified)}} -
-
- - {/* Actions */} -
- -
- - {/* Usage Details - Expandable */} - {expandedFile === file.path && ( -
-

- Used in {(imageUsages[file.path] || []).length} document{(imageUsages[file.path] || []).length !== 1 ? 's' : ''}: -

- - {(imageUsages[file.path] || []).length === 0 ? ( -

- This image is not currently used in any documents. -

- ) : ( -
- {(imageUsages[file.path] || []).map((usage, usageIndex) => ( -
-
-
- {usage.title} -
-
- {usage.relativePath} - {usage.lastModified && ( - • Modified: {formatDate(usage.lastModified)} - )} -
-
- e.target.style.backgroundColor = '#d97706'} - onMouseOut={(e) => e.target.style.backgroundColor = '#f59e0b'} - > - Edit - -
- ))} -
- )} -
- )} -
- ))} -
- )} -
- - {/* Lightbox */} - {lightboxImage && ( -
-
e.stopPropagation()} - > - - {lightboxImage.filename} -
- {lightboxImage.filename} {lightboxImage.dimensions ? `• ${lightboxImage.dimensions}` : ''} • {formatFileSize(lightboxImage.size)} -
-
-
- )} -
- ); -}; - -export default MediaDashboard; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; + +const MediaDashboard = () => { + const [mediaData, setMediaData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [mediaFiles, setMediaFiles] = useState([]); + const [filterType, setFilterType] = useState("all"); + const [imageUsages, setImageUsages] = useState({}); + const [expandedFile, setExpandedFile] = useState(null); + const [lightboxImage, setLightboxImage] = useState(null); + + // Helper: get extension from filename + const getExtension = (filename) => { + const match = filename.match(/\.([^.]+)$/); + return match ? match[1].toLowerCase() : ""; + }; + + // Helper: guess type from extension + const getType = (filename) => { + const ext = getExtension(filename); + if ( + [ + "jpg", + "jpeg", + "png", + "gif", + "webp", + "svg", + "bmp", + "tiff", + "ico", + "avif", + ].includes(ext) + ) + return "image"; + if (["mp4", "webm", "mov", "avi", "mkv"].includes(ext)) return "video"; + if (["mp3", "wav", "ogg", "flac"].includes(ext)) return "audio"; + return "file"; + }; + + const openLightbox = (file) => { + setLightboxImage(file); + }; + + const closeLightbox = () => { + setLightboxImage(null); + }; + + const extractTextFromAST = (node) => { + if (!node) return ""; + + let text = ""; + + if (typeof node === "string") { + return node; + } + + if (typeof node === "object") { + // Handle different node types + if (node.type === "text" && node.value) { + text += node.value; + } + + // Handle nodes with props (like Figure components) + if (node.props) { + // Extract props as text for searching + text += JSON.stringify(node.props); + } + + // Handle JSX elements + if (node.type === "element" && node.props) { + text += JSON.stringify(node.props); + } + + // Handle MDX JSX elements + if (node.name === "Figure" && node.props) { + text += JSON.stringify(node.props); + } + + // Recursively process children + if (node.children && Array.isArray(node.children)) { + for (const child of node.children) { + text += extractTextFromAST(child); + } + } + + // Handle other array-like structures + if (Array.isArray(node)) { + for (const item of node) { + text += extractTextFromAST(item); + } + } + } + + return text; + }; + + const scanDocumentsForImageUsage = async (mediaFiles) => { + try { + const { client } = await import("../../../tina/__generated__/client"); + // Fetch all documents to scan for image usage using connection query + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + const docs = docsResult.data.docConnection.edges || []; + const usages = {}; + for (const file of mediaFiles) { + usages[file.path] = []; + } + for (const edge of docs) { + const node = edge.node; + const title = node.title || node._sys.filename; + const relativePath = node._sys.relativePath; + let content = ""; + if (node.body && typeof node.body === "object") { + content = extractTextFromAST(node.body); + } else if (typeof node.body === "string") { + content = node.body; + } + for (const file of mediaFiles) { + if (content.includes(file.filename) || content.includes(file.path)) { + usages[file.path].push({ + title, + relativePath, + filename: node._sys.filename, + lastModified: node.lastmod || node._sys?.lastModified, + editUrl: `/admin/#/collections/edit/doc/${relativePath.replace(/\.[^/.]+$/, "")}`, + }); + } + } + } + setImageUsages(usages); + return usages; + } catch (_err) { + return {}; + } + }; + + const fetchMediaFiles = async () => { + setLoading(true); + setError(null); + try { + const { client } = await import("../../../tina/__generated__/client"); + // Query Tina's MediaCollection (reuse/media/index.json) + const mediaResult = await client.queries.media({ + relativePath: "index.json", + }); + const mediaList = mediaResult?.data?.media?.media || []; + // Add type, extension, url, and name fields for UI compatibility + const files = mediaList.map((file) => { + const ext = getExtension(file.filename); + const type = getType(file.filename); + // Use file.path for correct subfolder support + const url = `/img/${file.path}`; + return { + ...file, + name: file.filename, + extension: ext, + type, + url, + lastModified: file.lastModified || "", + dimensions: file.dimensions || "", + }; + }); + setMediaFiles(files); + const mediaStats = { + total: files.length, + images: files.filter((f) => f.type === "image").length, + totalSize: files.reduce( + (acc, file) => + acc + (typeof file.size === "number" ? file.size / 1024 : 0), + 0 + ), + }; + setMediaData({ + files, + stats: mediaStats, + }); + await scanDocumentsForImageUsage(files); + } catch (_err) { + setError("Failed to load media files from Tina MediaCollection."); + } finally { + setLoading(false); + } + }; + + const getFilteredFiles = () => { + if (filterType === "all") return mediaFiles; + return mediaFiles.filter((file) => { + switch (filterType) { + case "images": + return file.type === "image"; + case "recent": { + const oneWeekAgo = new Date(); + oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); + return new Date(file.lastModified) > oneWeekAgo; + } + case "used": + return (imageUsages[file.path] || []).length > 0; + case "unused": + return (imageUsages[file.path] || []).length === 0; + default: + return true; + } + }); + }; + + const formatFileSize = (size) => { + // size is in bytes (number) + if (typeof size !== "number") return size; + if (size >= 1024 * 1024) { + return `${(size / (1024 * 1024)).toFixed(1)} MB`; + } + if (size >= 1024) { + return `${(size / 1024).toFixed(1)} KB`; + } + return `${size} B`; + }; + + const formatDate = (dateStr) => { + return new Date(dateStr).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!mediaData && !loading && !error) { + return ( +
+
+
+ + + + + + + +

+ Media Usage Dashboard +

+
+ +
+
+ ); + } + + if (loading) { + return ( +
+
+
+ Loading Dashboard +
+
+ Loading media files... +
+ + {/* Progress Bar for Loading */} +
+
+
+
+ +
+ ); + } + + if (error) { + return ( +
+
+

+ Error +

+

{error}

+
+
+ ); + } + + if (!mediaData) { + return null; + } + + const filteredFiles = getFilteredFiles(); + + return ( +
+ {/* Header */} +
+
+
+ + + + + + + +

+ Media Usage Dashboard +

+
+ +
+ + {/* Media Statistics Cards */} +
+
+
+ + + + +
+
+

Total Files

+

+ {mediaData.stats.total} +

+
+
+ +
+
+ + + + + +
+
+

Images

+

+ {mediaData.stats.images} +

+
+
+ +
+
+ + + +
+
+

Used

+

+ { + Object.values(imageUsages).filter( + (usages) => usages.length > 0 + ).length + } +

+
+
+ +
+
+ + + + +
+
+

Unused

+

+ { + Object.values(imageUsages).filter( + (usages) => usages.length === 0 + ).length + } +

+
+
+ +
+
+ + + + +
+
+

Total Size

+

+ {mediaData.stats.totalSize.toFixed(1)} KB +

+
+
+
+ + {/* Filter Controls */} +
+ + Filter: + + {["all", "images", "recent", "used", "unused"].map((filter) => ( + + ))} +
+
+ + {/* Media Files List */} +
+ {filteredFiles.length === 0 ? ( +
+

+ No media files found for the current filter. +

+
+ ) : ( +
+ {filteredFiles.map((file, index) => ( + // biome-ignore lint/a11y/noStaticElementInteractions: hover styling only, nothing here is activatable +
{ + e.currentTarget.style.backgroundColor = "#f6f8fa"; + e.currentTarget.style.borderColor = "#8c959f"; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = "#ffffff"; + e.currentTarget.style.borderColor = "#d1d9e0"; + }} + > + {/* File preview */} +
+ {file.type === "image" ? ( + {file.filename} openLightbox(file)} + onError={(e) => { + e.target.style.display = "none"; + e.target.nextSibling.style.display = "flex"; + }} + onMouseOver={(e) => (e.target.style.opacity = "0.8")} + onFocus={(e) => (e.target.style.opacity = "0.8")} + onMouseOut={(e) => (e.target.style.opacity = "1")} + onBlur={(e) => (e.target.style.opacity = "1")} + /> + ) : null} +
+ {file.extension ? file.extension.toUpperCase() : ""} +
+
+ + {/* File details */} +
+
+ {file.filename} +
+
+ {file.path} +
+
+ {formatFileSize(file.size)} + {file.extension === "svg" ? ( + vector + ) : ( + file.dimensions && {file.dimensions} + )} + {file.lastModified && ( + Modified: {formatDate(file.lastModified)} + )} +
+
+ + {/* Actions */} +
+ +
+ + {/* Usage Details - Expandable */} + {expandedFile === file.path && ( +
+

+ Used in {(imageUsages[file.path] || []).length} document + {(imageUsages[file.path] || []).length !== 1 ? "s" : ""}: +

+ + {(imageUsages[file.path] || []).length === 0 ? ( +

+ This image is not currently used in any documents. +

+ ) : ( +
+ {(imageUsages[file.path] || []).map( + (usage, usageIndex) => ( + + ) + )} +
+ )} +
+ )} +
+ ))} +
+ )} +
+ + {/* Lightbox */} + {lightboxImage && ( + // biome-ignore lint/a11y/noStaticElementInteractions: click-to-dismiss backdrop; the close button provides the keyboard path +
+
e.stopPropagation()} + > + + {lightboxImage.filename} +
+ {lightboxImage.filename}{" "} + {lightboxImage.dimensions ? `• ${lightboxImage.dimensions}` : ""}{" "} + • {formatFileSize(lightboxImage.size)} +
+
+
+ )} +
+ ); +}; + +export default MediaDashboard; diff --git a/src/components/Dashboard/StatusBar.jsx b/src/components/Dashboard/StatusBar.jsx index 1eb16d7b..f56338a8 100644 --- a/src/components/Dashboard/StatusBar.jsx +++ b/src/components/Dashboard/StatusBar.jsx @@ -1,209 +1,241 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const StatusBar = () => { - const [status, setStatus] = useState({ - connection: { type: 'loading', message: 'Checking connection...' }, - environment: { type: 'unknown', message: 'Detecting environment...' }, - settings: { type: 'loading', message: 'Validating settings...' } - }); - - useEffect(() => { - checkStatus(); - }, []); - - const checkStatus = async () => { - // Check GraphQL connection - let connectionStatus = { type: 'error', message: 'No connection' }; - let environmentStatus = { type: 'unknown', message: 'Unknown' }; - - try { - // Test localhost GraphQL first - const localhostResponse = await fetch('http://localhost:4001/graphql', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query: '{ __typename }' }), - }); - - if (localhostResponse.ok) { - connectionStatus = { type: 'success', message: 'Connected' }; - environmentStatus = { type: 'localhost', message: 'localhost:4001' }; - } - } catch (err) { - // If localhost fails, check for TinaCloud configuration - const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const token = process.env.NEXT_PUBLIC_TINA_TOKEN; - - if (clientId) { - // Try to import and check TinaCMS client for TinaCloud - try { - const { client } = await import('../../../tina/__generated__/client'); - // If we have a client and clientId, assume TinaCloud is configured - connectionStatus = { type: 'success', message: 'TinaCloud configured' }; - environmentStatus = { type: 'tinacloud', message: `TinaCloud (${clientId.substring(0, 8)}...)` }; - } catch (clientErr) { - connectionStatus = { type: 'error', message: 'Configuration error' }; - environmentStatus = { type: 'error', message: 'Client not found' }; - } - } else { - connectionStatus = { type: 'error', message: 'Not configured' }; - environmentStatus = { type: 'error', message: 'No environment set' }; - } - } - - // Check required settings - let settingsStatus = { type: 'success', message: 'All settings OK' }; - const missingSettings = []; - - // Check for essential environment variables - const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const token = process.env.NEXT_PUBLIC_TINA_TOKEN; - - // NEXT_PUBLIC_TINA_TOKEN is not required for TinaCloud environments - // Only check for token if using local development with specific requirements - // if (environmentStatus.type === 'tinacloud' && !token) { - // missingSettings.push('NEXT_PUBLIC_TINA_TOKEN'); - // } - - // Check for essential config files - try { - const { default: docusaurusConfig } = await import('../../../config/docusaurus/index.json'); - if (!docusaurusConfig || Object.keys(docusaurusConfig).length === 0) { - missingSettings.push('Docusaurus config'); - } - } catch (err) { - missingSettings.push('Docusaurus config'); - } - - // Check if TinaCMS client is properly generated - try { - await import('../../../tina/__generated__/client'); - } catch (err) { - missingSettings.push('TinaCMS client (run: yarn tina-build)'); - } - - if (missingSettings.length > 0) { - settingsStatus = { - type: 'warning', - message: `Missing: ${missingSettings.join(', ')}` - }; - } - - setStatus({ - connection: connectionStatus, - environment: environmentStatus, - settings: settingsStatus - }); - }; - - const getStatusColor = (type) => { - switch (type) { - case 'success': return '#059669'; // green - case 'warning': return '#f59e0b'; // yellow - case 'error': return '#dc2626'; // red - case 'localhost': return '#3b82f6'; // blue - case 'tinacloud': return '#8b5cf6'; // purple - case 'loading': return '#6b7280'; // gray - default: return '#6b7280'; // gray - } - }; - - const getStatusIcon = (type) => { - switch (type) { - case 'success': return 'āœ“'; - case 'warning': return '⚠'; - case 'error': return 'āœ—'; - case 'localhost': return ( - - - - - ); - case 'tinacloud': return '☁'; - case 'loading': return '⟳'; - default: return '?'; - } - }; - - // Inject status into existing element if it exists - useEffect(() => { - // Hide Reset and Save buttons on this dashboard page - const hideButtonsStyle = document.createElement('style'); - hideButtonsStyle.id = 'statusbar-hide-buttons'; - hideButtonsStyle.textContent = ` - .relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end button.icon-parent.items-center.font-medium.focus\\:outline-none.focus\\:ring-2.focus\\:shadow-outline.text-center.inline-flex.justify-center.transition-all.duration-150.ease-out.shadow { - display: none !important; - } - `; - - // Add the style if it doesn't exist - if (!document.getElementById('statusbar-hide-buttons')) { - document.head.appendChild(hideButtonsStyle); - } - - const targetElement = document.querySelector('.relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end'); - if (targetElement) { - const statusContainer = targetElement.querySelector('.status-bar-injected'); - if (!statusContainer) { - const statusDiv = document.createElement('div'); - statusDiv.className = 'status-bar-injected flex items-center gap-4 mr-auto'; - statusDiv.style.fontSize = '0.75rem'; - statusDiv.innerHTML = ` -
- ${getStatusIcon(status.connection.type)} - GraphQL: - ${status.connection.message} -
-
- ${getStatusIcon(status.environment.type)} - Environment: - ${status.environment.message} -
-
- ${getStatusIcon(status.settings.type)} - Settings: - ${status.settings.message} -
- `; - targetElement.insertBefore(statusDiv, targetElement.firstChild); - } else { - // Update existing status - statusContainer.innerHTML = ` -
- ${getStatusIcon(status.connection.type)} - GraphQL: - ${status.connection.message} -
-
- ${getStatusIcon(status.environment.type)} - Environment: - ${status.environment.message} -
-
- ${getStatusIcon(status.settings.type)} - Settings: - ${status.settings.message} -
- `; - } - } - - // Cleanup function to remove the style when component unmounts - return () => { - const existingStyle = document.getElementById('statusbar-hide-buttons'); - if (existingStyle) { - existingStyle.remove(); - } - }; - }, [status]); - - return null; // Only inject into existing element, don't render standalone -}; - -export default StatusBar; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useCallback, useEffect, useState } from "react"; + +const getStatusColor = (type) => { + switch (type) { + case "success": + return "#059669"; // green + case "warning": + return "#f59e0b"; // yellow + case "error": + return "#dc2626"; // red + case "localhost": + return "#3b82f6"; // blue + case "tinacloud": + return "#8b5cf6"; // purple + case "loading": + return "#6b7280"; // gray + default: + return "#6b7280"; // gray + } +}; + +const getStatusIcon = (type) => { + switch (type) { + case "success": + return "āœ“"; + case "warning": + return "⚠"; + case "error": + return "āœ—"; + case "localhost": + // Every caller interpolates this into an HTML string, so returning JSX + // here rendered as "[object Object]" in the status bar. + return ( + '' + + '' + + '' + + "" + ); + case "tinacloud": + return "☁"; + case "loading": + return "⟳"; + default: + return "?"; + } +}; + +const StatusBar = () => { + const [status, setStatus] = useState({ + connection: { type: "loading", message: "Checking connection..." }, + environment: { type: "unknown", message: "Detecting environment..." }, + settings: { type: "loading", message: "Validating settings..." }, + }); + + const checkStatus = useCallback(async () => { + // Check GraphQL connection + let connectionStatus = { type: "error", message: "No connection" }; + let environmentStatus = { type: "unknown", message: "Unknown" }; + + try { + // Test localhost GraphQL first + const localhostResponse = await fetch("http://localhost:4001/graphql", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "{ __typename }" }), + }); + + if (localhostResponse.ok) { + connectionStatus = { type: "success", message: "Connected" }; + environmentStatus = { type: "localhost", message: "localhost:4001" }; + } + } catch (_err) { + // If localhost fails, check for TinaCloud configuration + const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; + const _token = process.env.NEXT_PUBLIC_TINA_TOKEN; + + if (clientId) { + // Try to import and check TinaCMS client for TinaCloud + try { + await import("../../../tina/__generated__/client"); + // If we have a client and clientId, assume TinaCloud is configured + connectionStatus = { + type: "success", + message: "TinaCloud configured", + }; + environmentStatus = { + type: "tinacloud", + message: `TinaCloud (${clientId.substring(0, 8)}...)`, + }; + } catch (_clientErr) { + connectionStatus = { type: "error", message: "Configuration error" }; + environmentStatus = { type: "error", message: "Client not found" }; + } + } else { + connectionStatus = { type: "error", message: "Not configured" }; + environmentStatus = { type: "error", message: "No environment set" }; + } + } + + // Check required settings + let settingsStatus = { type: "success", message: "All settings OK" }; + const missingSettings = []; + + // Check for essential environment variables + const _clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; + const _token = process.env.NEXT_PUBLIC_TINA_TOKEN; + + // NEXT_PUBLIC_TINA_TOKEN is not required for TinaCloud environments + // Only check for token if using local development with specific requirements + // if (environmentStatus.type === 'tinacloud' && !token) { + // missingSettings.push('NEXT_PUBLIC_TINA_TOKEN'); + // } + + // Check for essential config files + try { + const { default: docusaurusConfig } = await import( + "../../../config/docusaurus/index.json" + ); + if (!docusaurusConfig || Object.keys(docusaurusConfig).length === 0) { + missingSettings.push("Docusaurus config"); + } + } catch (_err) { + missingSettings.push("Docusaurus config"); + } + + // Check if TinaCMS client is properly generated + try { + await import("../../../tina/__generated__/client"); + } catch (_err) { + missingSettings.push("TinaCMS client (run: yarn tina-build)"); + } + + if (missingSettings.length > 0) { + settingsStatus = { + type: "warning", + message: `Missing: ${missingSettings.join(", ")}`, + }; + } + + setStatus({ + connection: connectionStatus, + environment: environmentStatus, + settings: settingsStatus, + }); + }, []); + + useEffect(() => { + checkStatus(); + }, [checkStatus]); + + // Inject status into existing element if it exists + useEffect(() => { + // Hide Reset and Save buttons on this dashboard page + const hideButtonsStyle = document.createElement("style"); + hideButtonsStyle.id = "statusbar-hide-buttons"; + hideButtonsStyle.textContent = ` + .relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end button.icon-parent.items-center.font-medium.focus\\:outline-none.focus\\:ring-2.focus\\:shadow-outline.text-center.inline-flex.justify-center.transition-all.duration-150.ease-out.shadow { + display: none !important; + } + `; + + // Add the style if it doesn't exist + if (!document.getElementById("statusbar-hide-buttons")) { + document.head.appendChild(hideButtonsStyle); + } + + const targetElement = document.querySelector( + ".relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end" + ); + if (targetElement) { + const statusContainer = targetElement.querySelector( + ".status-bar-injected" + ); + if (!statusContainer) { + const statusDiv = document.createElement("div"); + statusDiv.className = + "status-bar-injected flex items-center gap-4 mr-auto"; + statusDiv.style.fontSize = "0.75rem"; + statusDiv.innerHTML = ` +
+ ${getStatusIcon(status.connection.type)} + GraphQL: + ${status.connection.message} +
+
+ ${getStatusIcon(status.environment.type)} + Environment: + ${status.environment.message} +
+
+ ${getStatusIcon(status.settings.type)} + Settings: + ${status.settings.message} +
+ `; + targetElement.insertBefore(statusDiv, targetElement.firstChild); + } else { + // Update existing status + statusContainer.innerHTML = ` +
+ ${getStatusIcon(status.connection.type)} + GraphQL: + ${status.connection.message} +
+
+ ${getStatusIcon(status.environment.type)} + Environment: + ${status.environment.message} +
+
+ ${getStatusIcon(status.settings.type)} + Settings: + ${status.settings.message} +
+ `; + } + } + + // Cleanup function to remove the style when component unmounts + return () => { + const existingStyle = document.getElementById("statusbar-hide-buttons"); + if (existingStyle) { + existingStyle.remove(); + } + }; + }, [status]); + + return null; // Only inject into existing element, don't render standalone +}; + +export default StatusBar; diff --git a/src/components/Dashboard/TranslationDashboard.jsx b/src/components/Dashboard/TranslationDashboard.jsx index 04ac9ceb..36129bd5 100644 --- a/src/components/Dashboard/TranslationDashboard.jsx +++ b/src/components/Dashboard/TranslationDashboard.jsx @@ -1,1439 +1,2210 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; -import * as xliffUtils from '../../utils/xliff'; -import docusaurusData from '../../../config/docusaurus/index.json'; - -const TranslationDashboard = () => { - const [status, setStatus] = useState(''); - // Delete all orphan topics - const handleDeleteOrphanTopics = async () => { - setStatus(''); - try { - const { client } = await import('../../../tina/__generated__/client'); - const lang = selectedLanguage; - const docOrphaned = translationData && translationData[lang] ? translationData[lang].orphaned : []; - const snippetOrphaned = translationData && translationData[lang] ? (translationData[lang].snippets?.orphaned || []) : []; - const orphaned = [...docOrphaned, ...snippetOrphaned]; - for (const item of orphaned) { - await client.request({ - query: ` - mutation DeleteI18n($collection: String!, $relativePath: String!) { - deleteDocument(collection: $collection, relativePath: $relativePath) { - ... on I18n { - id - } - } - } - `, - variables: { - collection: 'i18n', - relativePath: item.file - } - }); - } - setStatus(`Deleted ${orphaned.length} orphan topics for ${lang}`); - await scanTranslations(); - } catch (err) { - setStatus(`Error: ${err.message}`); - } - }; - - // Add all missing topics - const handleAddMissingTopics = async () => { - setStatus(''); - try { - const { client } = await import('../../../tina/__generated__/client'); - const lang = selectedLanguage; - const missingDocs = translationData && translationData[lang] ? translationData[lang].missing : []; - const missingSnippets = translationData && translationData[lang] ? (translationData[lang].snippets?.missing || []) : []; - const missing = [ - ...missingDocs.map(item => ({ ...item, _isSnippet: false })), - ...missingSnippets.map(item => ({ ...item, _isSnippet: true })) - ]; - if (!missing || missing.length === 0) { - setStatus('No missing topics to add'); - return; - } - setAdding(true); - setAddProgress(0); - for (const [idx, item] of missing.entries()) { - // copy full metadata and body from sourceNode when available - const sourceNode = item.sourceNode || null; - let relPath; - if (item._isSnippet) { - const baseFile = item.file; - const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); - relPath = `${lang}/snippets/${baseFile}${hasExt ? '' : '.mdx'}`; - } else { - const baseFile = item.file.replace(/^docs\//, ''); - const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); - relPath = `${lang}/docusaurus-plugin-content-docs/current/${baseFile}${hasExt ? '' : '.mdx'}`; - } - const paramsBody = {}; - if (sourceNode) { - paramsBody.title = sourceNode.title || item.title; - if (sourceNode.body) paramsBody.body = sourceNode.body; - if (item._isSnippet) { - if (sourceNode.description) paramsBody.description = sourceNode.description; - } else { - if (sourceNode.modifiedBy) paramsBody.modifiedBy = sourceNode.modifiedBy; - if (sourceNode.help !== undefined) paramsBody.help = sourceNode.help; - if (sourceNode.slug) paramsBody.slug = sourceNode.slug; - if (sourceNode.tags) paramsBody.tags = sourceNode.tags; - if (sourceNode.draft !== undefined) paramsBody.draft = sourceNode.draft; - if (sourceNode.review !== undefined) paramsBody.review = sourceNode.review; - if (sourceNode.translate !== undefined) paramsBody.translate = sourceNode.translate; - if (sourceNode.approved !== undefined) paramsBody.approved = sourceNode.approved; - if (sourceNode.published !== undefined) paramsBody.published = sourceNode.published; - if (sourceNode.unlisted !== undefined) paramsBody.unlisted = sourceNode.unlisted; - } - } else { - paramsBody.title = item.title; - } - // ensure created translations start with required workflow metadata - paramsBody.draft = false; - paramsBody.review = false; - paramsBody.translate = true; - paramsBody.approved = false; - paramsBody.published = false; - paramsBody.unlisted = true; - // set lastmod to one day earlier than source (or yesterday) - let lastmodSource = null; - if (sourceNode && sourceNode.lastmod) { - lastmodSource = new Date(sourceNode.lastmod); - } else if (item.sourceLastMod && item.sourceLastMod !== 'No date') { - try { - const parsed = new Date(item.sourceLastMod); - if (!isNaN(parsed.getTime())) lastmodSource = parsed; - } catch (e) { - // ignore parse errors - } - } - paramsBody.lastmod = lastmodSource ? new Date(lastmodSource.getTime() - 1000).toISOString() : new Date(Date.now() - 1000).toISOString(); - - await client.request({ - query: ` - mutation CreateI18n($collection: String!, $relativePath: String!, $params: DocumentMutation!) { - createDocument(collection: $collection, relativePath: $relativePath, params: $params) { - ... on I18n { - id - } - } - } - `, - variables: { - collection: 'i18n', - relativePath: relPath, - params: { i18n: paramsBody } - } - }); - - // update progress - try { - const pct = missing.length > 0 ? Math.round(((idx + 1) / missing.length) * 100) : 100; - setAddProgress(pct); - setStatus(`Adding ${idx + 1}/${missing.length} translations (${pct}%)`); - } catch (e) { - // ignore progress errors - } - } - setStatus(`Added ${missing.length} missing topics for ${lang}`); - await scanTranslations(); - setAddProgress(100); - setTimeout(() => setAddProgress(null), 800); - setAdding(false); - } catch (err) { - setStatus(`Error: ${err.message}`); - setAdding(false); - setAddProgress(null); - } - }; - - // Edit out-of-date doc - const handleEditOutOfDateDoc = (file) => { - const cleanFile = file.replace(/^docs\//, '').replace(/\.mdx$/, '').replace(/\.md$/, ''); - window.open(`/admin#/collections/edit/i18n/${selectedLanguage}/docusaurus-plugin-content-docs/current/${cleanFile}`, '_blank'); - }; - - // Edit out-of-date snippet - const handleEditOutOfDateSnippet = (file) => { - const cleanFile = file.replace(/\.mdx$/, '').replace(/\.md$/, ''); - window.open(`/admin#/collections/edit/i18n/${selectedLanguage}/snippets/${cleanFile}`, '_blank'); - }; - const [translationData, setTranslationData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [importing, setImporting] = useState(false); - const [importProgress, setImportProgress] = useState(null); - const [adding, setAdding] = useState(false); - const [addProgress, setAddProgress] = useState(null); - const [selectedLanguage, setSelectedLanguage] = useState('fr'); - - // Handle Import button: open file picker and run verbose GraphQL import - const handleImportClick = async () => { - try { - setImporting(true); - setImportProgress(null); - const input = document.getElementById('xliff-upload'); - if (!input) return; - input.value = ''; - input.click(); - const file = await new Promise((resolve) => { - const onChange = () => { - input.removeEventListener('change', onChange); - const f = input.files && input.files[0]; - resolve(f); - }; - input.addEventListener('change', onChange); - }); - if (!file) return; - setStatus(`Importing: ${file.name}`); - const text = await file.text(); - const { client } = await import('../../../tina/__generated__/client'); - console.log('[debug-import] reading file', file.name, file.size); - const results = await xliffUtils.importXliffBundle(client, text, selectedLanguage, (p) => { - console.log('[debug-import] progress', p); - if (p && p.id) setStatus(`Import ${p.id}: ${p.status}${p.error ? ' - ' + p.error : ''}`); - if (p && p.progress !== undefined) setImportProgress(p.progress); - }); - console.log('[debug-import] results', results); - setStatus('Import complete'); - setImportProgress(100); - setTimeout(() => setImportProgress(null), 800); - setImporting(false); - await scanTranslations(); - } catch (err) { - console.error('[import] error', err); - setStatus(`Import error: ${err && err.message ? err.message : String(err)}`); - setImporting(false); - setImportProgress(null); - } - }; - - // (removed separate debug-upload handler) single Import button handles import - - const scanTranslations = async () => { - setLoading(true); - setError(null); - try { - // Build results container - const results = {}; - const { client } = await import('../../../tina/__generated__/client'); - - // Helper to normalize paths for comparison (strip extensions and index/readme) - const canonicalize = (p) => { - if (!p) return p; - let s = p.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); - return s; - }; - - // Fetch docs (source files) with pagination - let docsEdges = []; - let docsAfter = null; - while (true) { - const docsResult = await client.queries.docConnection({ sort: 'title', first: 100, after: docsAfter }); - const chunk = docsResult.data?.docConnection?.edges || []; - docsEdges = docsEdges.concat(chunk); - const pageInfo = docsResult.data?.docConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - docsAfter = pageInfo.endCursor; - } - const sourceMap = {}; // canonical -> node - for (const edge of docsEdges) { - const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; - // derive clean path by removing only a leading 'docs/' prefix - let clean = rel; - if (rel.startsWith('docs/')) { - clean = rel.replace(/^docs\//, ''); - } - // exclude generated API folder - if (clean.startsWith('api/')) continue; - const canonical = canonicalize(clean || rel); - sourceMap[canonical] = node; - } - - - - // Fetch snippets with pagination - let snippetsEdges = []; - let snippetsAfter = null; - while (true) { - const snippetsResult = await client.queries.snippetsConnection({ first: 100, after: snippetsAfter }); - const chunk = snippetsResult.data?.snippetsConnection?.edges || []; - snippetsEdges = snippetsEdges.concat(chunk); - const pageInfo = snippetsResult.data?.snippetsConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - snippetsAfter = pageInfo.endCursor; - } - const snippetSourceMap = {}; - for (const edge of snippetsEdges) { - const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; - const canonical = canonicalize(rel); - snippetSourceMap[canonical] = node; - } - - // Fetch translations and build map for the selected language with pagination - let i18nEdges = []; - let i18nAfter = null; - while (true) { - const i18nResult = await client.queries.i18nConnection({ sort: 'title', first: 100, after: i18nAfter }); - const chunk = i18nResult.data?.i18nConnection?.edges || []; - i18nEdges = i18nEdges.concat(chunk); - const pageInfo = i18nResult.data?.i18nConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - i18nAfter = pageInfo.endCursor; - } - // Build translation maps grouped by language - const translationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } - const snippetTranslationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } - for (const edge of i18nEdges) { - const node = edge.node; - const relPath = node._sys?.relativePath || node._sys?.filename || ''; - const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); - if (!m) continue; - const lang = m[1]; - const after = m[2]; - const prefix = 'docusaurus-plugin-content-docs/current/'; - if (after.startsWith('snippets/')) { - const snippetRel = after.replace(/^snippets\//, ''); - const canonical = canonicalize(snippetRel); - snippetTranslationsByLang[lang] = snippetTranslationsByLang[lang] || {}; - snippetTranslationsByLang[lang][canonical] = { node, originalPath: snippetRel, rawPath: snippetRel }; - continue; - } - if (!after.startsWith(prefix)) continue; - let cleanAfter = after.replace(new RegExp(`^${prefix}`), ''); - // Keep the raw path (before stripping docs/) for Tina API operations - const rawPath = cleanAfter; - // Strip leading 'docs/' to match source doc paths - if (cleanAfter.startsWith('docs/')) { - cleanAfter = cleanAfter.replace(/^docs\//, ''); - } - if (cleanAfter.startsWith('api/') || cleanAfter.startsWith('wiki/')) continue; - const canonical = canonicalize(cleanAfter); - - translationsByLang[lang] = translationsByLang[lang] || {}; - const translationsMap = translationsByLang[lang]; - - if (translationsMap[canonical]) { - const existing = translationsMap[canonical]; - const isExistingIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(existing.originalPath || ''); - const isNewIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(cleanAfter); - if (isExistingIndex && !isNewIndex) { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } else { - try { - const existingDate = existing.node?.lastmod ? new Date(existing.node.lastmod) : null; - const newDate = node?.lastmod ? new Date(node.lastmod) : null; - if (newDate && (!existingDate || newDate > existingDate)) { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } - } catch (e) { - // keep existing on errors - } - } - } else { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } - } - - // For each language, compare with source map and build results - const sourceKeys = new Set(Object.keys(sourceMap)); - // Pre-build a 'missing all' list so empty languages can be shown - const missingAll = []; - for (const key of sourceKeys) { - const src = sourceMap[key]; - const title = src.title || key; - missingAll.push({ file: `docs/${key}`, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - } - for (const lang of Object.keys(translationsByLang)) { - const translationsMap = translationsByLang[lang] || {}; - const translationKeys = new Set(Object.keys(translationsMap)); - - const missing = []; - const outdated = []; - const upToDate = []; - const orphaned = []; - - for (const key of sourceKeys) { - const src = sourceMap[key]; - const srcDate = src.lastmod ? new Date(src.lastmod) : null; - const title = src.title || key; - if (!translationKeys.has(key)) { - missing.push({ file: `docs/${key}`, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - continue; - } - const tr = translationsMap[key].node; - const trDate = tr.lastmod ? new Date(tr.lastmod) : null; - if (!srcDate && !trDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: 'No date', translationLastMod: 'No date', title }); - } else if (srcDate && !trDate) { - outdated.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: 'No date', title }); - } else if (!srcDate && trDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: 'No date', translationLastMod: tr.lastmod, title }); - } else { - if (trDate >= srcDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title }); - } else { - outdated.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title, daysBehind: Math.ceil((srcDate - trDate) / (1000*60*60*24)) }); - } - } - } - - for (const key of translationKeys) { - if (!sourceKeys.has(key)) { - const entry = translationsMap[key]; - const node = entry.node; - const orig = entry.rawPath || entry.originalPath || key; - orphaned.push({ file: `${lang}/docusaurus-plugin-content-docs/current/${orig}`, translationLastMod: node.lastmod || 'No date', title: node.title || orig }); - } - } - - results[lang] = { - missing, - outdated, - upToDate, - orphaned, - errors: [], - total: Object.keys(sourceMap).length - }; - } - - // Get supported languages from the imported docusaurus config, excluding - // the default locale and any English variants (en-*). - const supported = docusaurusData.languages?.supported || []; - const defaultLocale = docusaurusData.languages?.default || 'en'; - const langsFromConfig = supported - .filter(l => l.code !== defaultLocale && !l.code.startsWith('en')) - .map(l => ({ code: l.code, label: l.label })); - - for (const langEntry of langsFromConfig) { - const fsLang = langEntry.code; - if (!results[fsLang]) { - results[fsLang] = { - missing: missingAll.slice(), - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length - }; - } - } - - // If no translations found at all, ensure we still populate selectedLanguage key so UI remains consistent - if (Object.keys(results).length === 0) { - results[selectedLanguage] = { - missing: [], - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length - }; - } - - // Build snippet translation results for all languages - const snippetSourceKeys = new Set(Object.keys(snippetSourceMap)); - const missingAllSnippets = []; - for (const key of snippetSourceKeys) { - const src = snippetSourceMap[key]; - missingAllSnippets.push({ file: key, sourceLastMod: src.lastmod || 'No date', title: src.title || key, sourceNode: src }); - } - for (const lang of Object.keys(results)) { - const snTrMap = snippetTranslationsByLang[lang] || {}; - const snTrKeys = new Set(Object.keys(snTrMap)); - const snMissing = [], snOutdated = [], snUpToDate = [], snOrphaned = []; - for (const key of snippetSourceKeys) { - const src = snippetSourceMap[key]; - const srcDate = src.lastmod ? new Date(src.lastmod) : null; - const title = src.title || key; - if (!snTrKeys.has(key)) { - snMissing.push({ file: key, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - continue; - } - const tr = snTrMap[key].node; - const trDate = tr.lastmod ? new Date(tr.lastmod) : null; - if (!srcDate && !trDate) { - snUpToDate.push({ file: key, sourceLastMod: 'No date', translationLastMod: 'No date', title }); - } else if (srcDate && !trDate) { - snOutdated.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: 'No date', title }); - } else if (!srcDate && trDate) { - snUpToDate.push({ file: key, sourceLastMod: 'No date', translationLastMod: tr.lastmod, title }); - } else { - if (trDate >= srcDate) { - snUpToDate.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title }); - } else { - snOutdated.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title, daysBehind: Math.ceil((srcDate - trDate) / (1000 * 60 * 60 * 24)) }); - } - } - } - for (const key of snTrKeys) { - if (!snippetSourceKeys.has(key)) { - const entry = snTrMap[key]; - const node = entry.node; - const orig = entry.rawPath || entry.originalPath || key; - snOrphaned.push({ file: `${lang}/snippets/${orig}`, translationLastMod: node.lastmod || 'No date', title: node.title || orig }); - } - } - results[lang].snippets = { missing: snMissing, outdated: snOutdated, upToDate: snUpToDate, orphaned: snOrphaned, total: snippetSourceKeys.size }; - } - // Handle any snippet-only languages not yet in results - for (const lang of Object.keys(snippetTranslationsByLang)) { - if (!results[lang]) { - results[lang] = { - missing: missingAll.slice(), - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length, - snippets: { - missing: missingAllSnippets.slice(), - outdated: [], - upToDate: [], - orphaned: [], - total: snippetSourceKeys.size - } - }; - } - } - - // Ensure selectedLanguage is present in results (pick first available if not) - const langsFound = Object.keys(results); - if (langsFound.length > 0 && !results[selectedLanguage]) { - setSelectedLanguage(langsFound[0]); - } - - setTranslationData(results); - } catch (error) { - console.error('Error scanning translations:', error); - setError(`Failed to scan translations: ${error.message}`); - } finally { - setLoading(false); - } - }; - - - - const formatDate = (dateString) => { - try { - return new Date(dateString).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric' - }); - } catch (error) { - return dateString; - } - }; - - const getStatusColor = (status) => { - switch (status) { - case 'outdated': return '#f59e0b'; - case 'missing': return '#ff6b6b'; - case 'upToDate': return '#2ed573'; - case 'orphaned': return '#9c88ff'; - default: return '#747d8c'; - } - }; - - const getTotalCounts = () => { - if (!translationData) return {}; - - return Object.keys(translationData).reduce((acc, lang) => { - const data = translationData[lang]; - const sn = data.snippets || { missing: [], outdated: [], upToDate: [], orphaned: [], total: 0 }; - acc[lang] = { - total: (data.total || (data.missing.length + data.outdated.length + data.upToDate.length)) + (sn.total || 0), - missing: data.missing.length + sn.missing.length, - outdated: data.outdated.length + sn.outdated.length, - upToDate: data.upToDate.length + sn.upToDate.length, - orphaned: data.orphaned.length + sn.orphaned.length, - errors: data.errors.length - }; - return acc; - }, {}); - }; - - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!translationData && !loading && !error) { - return ( -
-
-
- - - - - - - -

- Translation Dashboard -

-
- -
-
- ); - } - - if (loading) { - return ( -
-
-
- Loading Dashboard -
-
- Scanning translations... -
- - {/* Progress Bar for Loading */} -
-
-
-
- -
- ); - } - - if (error) { - return ( -
-
-
- Error: {error} -
- -
-
- ); - } - - if (!translationData) { - return ( -
-
- No translation data available -
-
- ); - } - - const totalCounts = getTotalCounts(); - const languages = Object.keys(translationData); - - return ( -
-
-
- - - - - - - -

- Translation Dashboard -

-
-
- - - - - - - {/* Debug import now runs immediately when a file is selected via Import XLIFF */} - -
-
- {status &&
{status}
} - - {/* Progress Bars for Async Operations */} - {addProgress !== null && ( -
-
- Adding Missing Topics: {addProgress}% -
-
-
-
-
- )} - - {importProgress !== null && ( -
-
- Importing XLIFF: {importProgress}% -
-
-
-
-
- )} - - {loading && ( -
-
- Scanning translations... -
-
-
-
-
- )} - - - - {/* Translation Statistics Cards */} -
- {(() => { - const counts = totalCounts[selectedLanguage]; - if (!counts) return null; - - return [ - { - label: 'Up to Date', - value: counts.upToDate, - icon: ( - - - - ), - bgColor: 'bg-green-100', - iconColor: 'text-green-600', - textColor: 'text-green-600' - }, - { - label: 'Outdated', - value: counts.outdated, - icon: ( - - - - - ), - bgColor: 'bg-orange-100', - iconColor: 'text-orange-600', - textColor: 'text-orange-600' - }, - { - label: 'Missing', - value: counts.missing, - icon: ( - - - - - - ), - bgColor: 'bg-red-100', - iconColor: 'text-red-600', - textColor: 'text-red-600' - }, - { - label: 'Orphaned', - value: counts.orphaned, - icon: ( - - - - - ), - bgColor: 'bg-purple-100', - iconColor: 'text-purple-600', - textColor: 'text-purple-600' - } - ].map((stat, index) => ( -
-
-
{stat.icon}
-
-
-

{stat.label}

-

{stat.value}

-
-
- )); - })()} -
- - {/* Language Selection */} -
-
- - -
-
- - {/* Detailed View */} - {(() => { - const data = translationData[selectedLanguage]; - if (!data) return null; - - return ( -
- - {/* Missing Files */} - {data.missing.length > 0 && ( -
-

- - - - - Missing Translations ({data.missing.length}) -

-
- {data.missing.map((item, index) => ( -
-
- {item.title} -
- {item.file} -
-
-
- Source: {formatDate(item.sourceLastMod)} -
-
- ))} -
-
- )} - - {/* Outdated Files */} - {data.outdated.length > 0 && ( -
-

- - - - - Outdated Translations ({data.outdated.length}) -

-
- {data.outdated.map((item, index) => ( -
-
- {item.title} - -
-
- {item.file} - Source: {formatDate(item.sourceLastMod)} -
-
- {item.daysBehind ? `${item.daysBehind} days behind` : ''} - Translation: {formatDate(item.translationLastMod)} -
-
- ))} -
-
- )} - - {/* Up to Date Files */} - {data.upToDate.length > 0 && selectedLanguage !== 'all' && ( -
-

- - - - Up to Date Translations ({data.upToDate.length}) -

-
- {data.upToDate.map((item, index) => ( -
-
- {item.title} -
- {item.file} -
-
-
- {formatDate(item.translationLastMod)} -
-
- ))} -
-
- )} - - {/* Orphaned Files */} - {data.orphaned.length > 0 && ( -
-

- - - - - Orphan Topics ({data.orphaned.length}) -

-
- {data.orphaned.map((item, index) => ( -
-
- {item.title} -
- {item.file} -
-
- Translation exists but no source file found -
-
-
- Translation: {formatDate(item.translationLastMod)} -
-
- ))} -
-
- )} - - {/* Errors */} - {data.errors.length > 0 && ( -
-

- - - - - - Errors ({data.errors.length}) -

-
- {data.errors.map((item, index) => ( -
-
{item.file}
-
{item.error}
-
- ))} -
-
- )} - - {/* Snippets Section */} - {data.snippets && data.snippets.total > 0 && ( -
-

- - - - - - - - Snippets -

- - {/* Missing Snippets */} - {data.snippets.missing.length > 0 && ( -
-

- - - - - Missing Snippet Translations ({data.snippets.missing.length}) -

-
- {data.snippets.missing.map((item, index) => ( -
-
- {item.title} -
{item.file}
-
-
- ))} -
-
- )} - - {/* Outdated Snippets */} - {data.snippets.outdated.length > 0 && ( -
-

- - - - - Outdated Snippet Translations ({data.snippets.outdated.length}) -

-
- {data.snippets.outdated.map((item, index) => ( -
-
- {item.title} - -
-
- {item.file} - Source: {formatDate(item.sourceLastMod)} -
-
- {item.daysBehind ? `${item.daysBehind} days behind` : ''} - Translation: {formatDate(item.translationLastMod)} -
-
- ))} -
-
- )} - - {/* Up to Date Snippets */} - {data.snippets.upToDate.length > 0 && ( -
-

- - - - Up to Date Snippet Translations ({data.snippets.upToDate.length}) -

-
- {data.snippets.upToDate.map((item, index) => ( -
-
- {item.title} -
{item.file}
-
-
{formatDate(item.translationLastMod)}
-
- ))} -
-
- )} - - {/* Orphaned Snippets */} - {data.snippets.orphaned.length > 0 && ( -
-

- - - - - Orphan Snippets ({data.snippets.orphaned.length}) -

-
- {data.snippets.orphaned.map((item, index) => ( -
-
- {item.title} -
{item.file}
-
Translation exists but no source snippet found
-
-
Translation: {formatDate(item.translationLastMod)}
-
- ))} -
-
- )} -
- )} -
- ); - })()} -
- ); -}; - -export default TranslationDashboard; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; +import docusaurusData from "../../../config/docusaurus/index.json"; +import * as xliffUtils from "../../utils/xliff"; + +const TranslationDashboard = () => { + const [status, setStatus] = useState(""); + // Delete all orphan topics + const handleDeleteOrphanTopics = async () => { + setStatus(""); + try { + const { client } = await import("../../../tina/__generated__/client"); + const lang = selectedLanguage; + const docOrphaned = translationData?.[lang] + ? translationData[lang].orphaned + : []; + const snippetOrphaned = translationData?.[lang] + ? translationData[lang].snippets?.orphaned || [] + : []; + const orphaned = [...docOrphaned, ...snippetOrphaned]; + for (const item of orphaned) { + await client.request({ + query: ` + mutation DeleteI18n($collection: String!, $relativePath: String!) { + deleteDocument(collection: $collection, relativePath: $relativePath) { + ... on I18n { + id + } + } + } + `, + variables: { + collection: "i18n", + relativePath: item.file, + }, + }); + } + setStatus(`Deleted ${orphaned.length} orphan topics for ${lang}`); + await scanTranslations(); + } catch (err) { + setStatus(`Error: ${err.message}`); + } + }; + + // Add all missing topics + const handleAddMissingTopics = async () => { + setStatus(""); + try { + const { client } = await import("../../../tina/__generated__/client"); + const lang = selectedLanguage; + const missingDocs = translationData?.[lang] + ? translationData[lang].missing + : []; + const missingSnippets = translationData?.[lang] + ? translationData[lang].snippets?.missing || [] + : []; + const missing = [ + ...missingDocs.map((item) => ({ ...item, _isSnippet: false })), + ...missingSnippets.map((item) => ({ ...item, _isSnippet: true })), + ]; + if (!missing || missing.length === 0) { + setStatus("No missing topics to add"); + return; + } + setAdding(true); + setAddProgress(0); + for (const [idx, item] of missing.entries()) { + // copy full metadata and body from sourceNode when available + const sourceNode = item.sourceNode || null; + let relPath; + if (item._isSnippet) { + const baseFile = item.file; + const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); + relPath = `${lang}/snippets/${baseFile}${hasExt ? "" : ".mdx"}`; + } else { + const baseFile = item.file.replace(/^docs\//, ""); + const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); + relPath = `${lang}/docusaurus-plugin-content-docs/current/${baseFile}${hasExt ? "" : ".mdx"}`; + } + const paramsBody = {}; + if (sourceNode) { + paramsBody.title = sourceNode.title || item.title; + if (sourceNode.body) paramsBody.body = sourceNode.body; + if (item._isSnippet) { + if (sourceNode.description) + paramsBody.description = sourceNode.description; + } else { + if (sourceNode.modifiedBy) + paramsBody.modifiedBy = sourceNode.modifiedBy; + if (sourceNode.help !== undefined) + paramsBody.help = sourceNode.help; + if (sourceNode.slug) paramsBody.slug = sourceNode.slug; + if (sourceNode.tags) paramsBody.tags = sourceNode.tags; + if (sourceNode.draft !== undefined) + paramsBody.draft = sourceNode.draft; + if (sourceNode.review !== undefined) + paramsBody.review = sourceNode.review; + if (sourceNode.translate !== undefined) + paramsBody.translate = sourceNode.translate; + if (sourceNode.approved !== undefined) + paramsBody.approved = sourceNode.approved; + if (sourceNode.published !== undefined) + paramsBody.published = sourceNode.published; + if (sourceNode.unlisted !== undefined) + paramsBody.unlisted = sourceNode.unlisted; + } + } else { + paramsBody.title = item.title; + } + // ensure created translations start with required workflow metadata + paramsBody.draft = false; + paramsBody.review = false; + paramsBody.translate = true; + paramsBody.approved = false; + paramsBody.published = false; + paramsBody.unlisted = true; + // set lastmod to one day earlier than source (or yesterday) + let lastmodSource = null; + if (sourceNode?.lastmod) { + lastmodSource = new Date(sourceNode.lastmod); + } else if (item.sourceLastMod && item.sourceLastMod !== "No date") { + try { + const parsed = new Date(item.sourceLastMod); + if (!Number.isNaN(parsed.getTime())) lastmodSource = parsed; + } catch (_e) { + // ignore parse errors + } + } + paramsBody.lastmod = lastmodSource + ? new Date(lastmodSource.getTime() - 1000).toISOString() + : new Date(Date.now() - 1000).toISOString(); + + await client.request({ + query: ` + mutation CreateI18n($collection: String!, $relativePath: String!, $params: DocumentMutation!) { + createDocument(collection: $collection, relativePath: $relativePath, params: $params) { + ... on I18n { + id + } + } + } + `, + variables: { + collection: "i18n", + relativePath: relPath, + params: { i18n: paramsBody }, + }, + }); + + // update progress + try { + const pct = + missing.length > 0 + ? Math.round(((idx + 1) / missing.length) * 100) + : 100; + setAddProgress(pct); + setStatus( + `Adding ${idx + 1}/${missing.length} translations (${pct}%)` + ); + } catch (_e) { + // ignore progress errors + } + } + setStatus(`Added ${missing.length} missing topics for ${lang}`); + await scanTranslations(); + setAddProgress(100); + setTimeout(() => setAddProgress(null), 800); + setAdding(false); + } catch (err) { + setStatus(`Error: ${err.message}`); + setAdding(false); + setAddProgress(null); + } + }; + + // Edit out-of-date doc + const handleEditOutOfDateDoc = (file) => { + const cleanFile = file + .replace(/^docs\//, "") + .replace(/\.mdx$/, "") + .replace(/\.md$/, ""); + window.open( + `/admin#/collections/edit/i18n/${selectedLanguage}/docusaurus-plugin-content-docs/current/${cleanFile}`, + "_blank" + ); + }; + + // Edit out-of-date snippet + const handleEditOutOfDateSnippet = (file) => { + const cleanFile = file.replace(/\.mdx$/, "").replace(/\.md$/, ""); + window.open( + `/admin#/collections/edit/i18n/${selectedLanguage}/snippets/${cleanFile}`, + "_blank" + ); + }; + const [translationData, setTranslationData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [importing, setImporting] = useState(false); + const [importProgress, setImportProgress] = useState(null); + const [adding, setAdding] = useState(false); + const [addProgress, setAddProgress] = useState(null); + const [selectedLanguage, setSelectedLanguage] = useState("fr"); + + // Handle Import button: open file picker and run verbose GraphQL import + const handleImportClick = async () => { + try { + setImporting(true); + setImportProgress(null); + const input = document.getElementById("xliff-upload"); + if (!input) return; + input.value = ""; + input.click(); + const file = await new Promise((resolve) => { + const onChange = () => { + input.removeEventListener("change", onChange); + const f = input.files?.[0]; + resolve(f); + }; + input.addEventListener("change", onChange); + }); + if (!file) return; + setStatus(`Importing: ${file.name}`); + const text = await file.text(); + const { client } = await import("../../../tina/__generated__/client"); + const _results = await xliffUtils.importXliffBundle( + client, + text, + selectedLanguage, + (p) => { + if (p?.id) + setStatus( + `Import ${p.id}: ${p.status}${p.error ? ` - ${p.error}` : ""}` + ); + if (p && p.progress !== undefined) setImportProgress(p.progress); + } + ); + setStatus("Import complete"); + setImportProgress(100); + setTimeout(() => setImportProgress(null), 800); + setImporting(false); + await scanTranslations(); + } catch (err) { + setStatus(`Import error: ${err?.message ? err.message : String(err)}`); + setImporting(false); + setImportProgress(null); + } + }; + + // (removed separate debug-upload handler) single Import button handles import + + const scanTranslations = async () => { + setLoading(true); + setError(null); + try { + // Build results container + const results = {}; + const { client } = await import("../../../tina/__generated__/client"); + + // Helper to normalize paths for comparison (strip extensions and index/readme) + const canonicalize = (p) => { + if (!p) return p; + let s = p.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); + return s; + }; + + // Fetch docs (source files) with pagination + let docsEdges = []; + let docsAfter = null; + while (true) { + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 100, + after: docsAfter, + }); + const chunk = docsResult.data?.docConnection?.edges || []; + docsEdges = docsEdges.concat(chunk); + const pageInfo = docsResult.data?.docConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + docsAfter = pageInfo.endCursor; + } + const sourceMap = {}; // canonical -> node + for (const edge of docsEdges) { + const node = edge.node; + const rel = node._sys?.relativePath || node._sys?.filename || ""; + // derive clean path by removing only a leading 'docs/' prefix + let clean = rel; + if (rel.startsWith("docs/")) { + clean = rel.replace(/^docs\//, ""); + } + // exclude generated API folder + if (clean.startsWith("api/")) continue; + const canonical = canonicalize(clean || rel); + sourceMap[canonical] = node; + } + + // Fetch snippets with pagination + let snippetsEdges = []; + let snippetsAfter = null; + while (true) { + const snippetsResult = await client.queries.snippetsConnection({ + first: 100, + after: snippetsAfter, + }); + const chunk = snippetsResult.data?.snippetsConnection?.edges || []; + snippetsEdges = snippetsEdges.concat(chunk); + const pageInfo = snippetsResult.data?.snippetsConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + snippetsAfter = pageInfo.endCursor; + } + const snippetSourceMap = {}; + for (const edge of snippetsEdges) { + const node = edge.node; + const rel = node._sys?.relativePath || node._sys?.filename || ""; + const canonical = canonicalize(rel); + snippetSourceMap[canonical] = node; + } + + // Fetch translations and build map for the selected language with pagination + let i18nEdges = []; + let i18nAfter = null; + while (true) { + const i18nResult = await client.queries.i18nConnection({ + sort: "title", + first: 100, + after: i18nAfter, + }); + const chunk = i18nResult.data?.i18nConnection?.edges || []; + i18nEdges = i18nEdges.concat(chunk); + const pageInfo = i18nResult.data?.i18nConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + i18nAfter = pageInfo.endCursor; + } + // Build translation maps grouped by language + const translationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } + const snippetTranslationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } + for (const edge of i18nEdges) { + const node = edge.node; + const relPath = node._sys?.relativePath || node._sys?.filename || ""; + const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); + if (!m) continue; + const lang = m[1]; + const after = m[2]; + const prefix = "docusaurus-plugin-content-docs/current/"; + if (after.startsWith("snippets/")) { + const snippetRel = after.replace(/^snippets\//, ""); + const canonical = canonicalize(snippetRel); + snippetTranslationsByLang[lang] = + snippetTranslationsByLang[lang] || {}; + snippetTranslationsByLang[lang][canonical] = { + node, + originalPath: snippetRel, + rawPath: snippetRel, + }; + continue; + } + if (!after.startsWith(prefix)) continue; + let cleanAfter = after.replace(new RegExp(`^${prefix}`), ""); + // Keep the raw path (before stripping docs/) for Tina API operations + const rawPath = cleanAfter; + // Strip leading 'docs/' to match source doc paths + if (cleanAfter.startsWith("docs/")) { + cleanAfter = cleanAfter.replace(/^docs\//, ""); + } + if (cleanAfter.startsWith("api/") || cleanAfter.startsWith("wiki/")) + continue; + const canonical = canonicalize(cleanAfter); + + translationsByLang[lang] = translationsByLang[lang] || {}; + const translationsMap = translationsByLang[lang]; + + if (translationsMap[canonical]) { + const existing = translationsMap[canonical]; + const isExistingIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test( + existing.originalPath || "" + ); + const isNewIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(cleanAfter); + if (isExistingIndex && !isNewIndex) { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } else { + try { + const existingDate = existing.node?.lastmod + ? new Date(existing.node.lastmod) + : null; + const newDate = node?.lastmod ? new Date(node.lastmod) : null; + if (newDate && (!existingDate || newDate > existingDate)) { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } + } catch (_e) { + // keep existing on errors + } + } + } else { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } + } + + // For each language, compare with source map and build results + const sourceKeys = new Set(Object.keys(sourceMap)); + // Pre-build a 'missing all' list so empty languages can be shown + const missingAll = []; + for (const key of sourceKeys) { + const src = sourceMap[key]; + const title = src.title || key; + missingAll.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + } + for (const lang of Object.keys(translationsByLang)) { + const translationsMap = translationsByLang[lang] || {}; + const translationKeys = new Set(Object.keys(translationsMap)); + + const missing = []; + const outdated = []; + const upToDate = []; + const orphaned = []; + + for (const key of sourceKeys) { + const src = sourceMap[key]; + const srcDate = src.lastmod ? new Date(src.lastmod) : null; + const title = src.title || key; + if (!translationKeys.has(key)) { + missing.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + continue; + } + const tr = translationsMap[key].node; + const trDate = tr.lastmod ? new Date(tr.lastmod) : null; + if (!srcDate && !trDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: "No date", + translationLastMod: "No date", + title, + }); + } else if (srcDate && !trDate) { + outdated.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: "No date", + title, + }); + } else if (!srcDate && trDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: "No date", + translationLastMod: tr.lastmod, + title, + }); + } else { + if (trDate >= srcDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + }); + } else { + outdated.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + daysBehind: Math.ceil( + (srcDate - trDate) / (1000 * 60 * 60 * 24) + ), + }); + } + } + } + + for (const key of translationKeys) { + if (!sourceKeys.has(key)) { + const entry = translationsMap[key]; + const node = entry.node; + const orig = entry.rawPath || entry.originalPath || key; + orphaned.push({ + file: `${lang}/docusaurus-plugin-content-docs/current/${orig}`, + translationLastMod: node.lastmod || "No date", + title: node.title || orig, + }); + } + } + + results[lang] = { + missing, + outdated, + upToDate, + orphaned, + errors: [], + total: Object.keys(sourceMap).length, + }; + } + + // Get supported languages from the imported docusaurus config, excluding + // the default locale and any English variants (en-*). + const supported = docusaurusData.languages?.supported || []; + const defaultLocale = docusaurusData.languages?.default || "en"; + const langsFromConfig = supported + .filter((l) => l.code !== defaultLocale && !l.code.startsWith("en")) + .map((l) => ({ code: l.code, label: l.label })); + + for (const langEntry of langsFromConfig) { + const fsLang = langEntry.code; + if (!results[fsLang]) { + results[fsLang] = { + missing: missingAll.slice(), + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + }; + } + } + + // If no translations found at all, ensure we still populate selectedLanguage key so UI remains consistent + if (Object.keys(results).length === 0) { + results[selectedLanguage] = { + missing: [], + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + }; + } + + // Build snippet translation results for all languages + const snippetSourceKeys = new Set(Object.keys(snippetSourceMap)); + const missingAllSnippets = []; + for (const key of snippetSourceKeys) { + const src = snippetSourceMap[key]; + missingAllSnippets.push({ + file: key, + sourceLastMod: src.lastmod || "No date", + title: src.title || key, + sourceNode: src, + }); + } + for (const lang of Object.keys(results)) { + const snTrMap = snippetTranslationsByLang[lang] || {}; + const snTrKeys = new Set(Object.keys(snTrMap)); + const snMissing = [], + snOutdated = [], + snUpToDate = [], + snOrphaned = []; + for (const key of snippetSourceKeys) { + const src = snippetSourceMap[key]; + const srcDate = src.lastmod ? new Date(src.lastmod) : null; + const title = src.title || key; + if (!snTrKeys.has(key)) { + snMissing.push({ + file: key, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + continue; + } + const tr = snTrMap[key].node; + const trDate = tr.lastmod ? new Date(tr.lastmod) : null; + if (!srcDate && !trDate) { + snUpToDate.push({ + file: key, + sourceLastMod: "No date", + translationLastMod: "No date", + title, + }); + } else if (srcDate && !trDate) { + snOutdated.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: "No date", + title, + }); + } else if (!srcDate && trDate) { + snUpToDate.push({ + file: key, + sourceLastMod: "No date", + translationLastMod: tr.lastmod, + title, + }); + } else { + if (trDate >= srcDate) { + snUpToDate.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + }); + } else { + snOutdated.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + daysBehind: Math.ceil( + (srcDate - trDate) / (1000 * 60 * 60 * 24) + ), + }); + } + } + } + for (const key of snTrKeys) { + if (!snippetSourceKeys.has(key)) { + const entry = snTrMap[key]; + const node = entry.node; + const orig = entry.rawPath || entry.originalPath || key; + snOrphaned.push({ + file: `${lang}/snippets/${orig}`, + translationLastMod: node.lastmod || "No date", + title: node.title || orig, + }); + } + } + results[lang].snippets = { + missing: snMissing, + outdated: snOutdated, + upToDate: snUpToDate, + orphaned: snOrphaned, + total: snippetSourceKeys.size, + }; + } + // Handle any snippet-only languages not yet in results + for (const lang of Object.keys(snippetTranslationsByLang)) { + if (!results[lang]) { + results[lang] = { + missing: missingAll.slice(), + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + snippets: { + missing: missingAllSnippets.slice(), + outdated: [], + upToDate: [], + orphaned: [], + total: snippetSourceKeys.size, + }, + }; + } + } + + // Ensure selectedLanguage is present in results (pick first available if not) + const langsFound = Object.keys(results); + if (langsFound.length > 0 && !results[selectedLanguage]) { + setSelectedLanguage(langsFound[0]); + } + + setTranslationData(results); + } catch (error) { + setError(`Failed to scan translations: ${error.message}`); + } finally { + setLoading(false); + } + }; + + const formatDate = (dateString) => { + try { + return new Date(dateString).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + } catch (_error) { + return dateString; + } + }; + + const _getStatusColor = (status) => { + switch (status) { + case "outdated": + return "#f59e0b"; + case "missing": + return "#ff6b6b"; + case "upToDate": + return "#2ed573"; + case "orphaned": + return "#9c88ff"; + default: + return "#747d8c"; + } + }; + + const getTotalCounts = () => { + if (!translationData) return {}; + + return Object.keys(translationData).reduce((acc, lang) => { + const data = translationData[lang]; + const sn = data.snippets || { + missing: [], + outdated: [], + upToDate: [], + orphaned: [], + total: 0, + }; + acc[lang] = { + total: + (data.total || + data.missing.length + data.outdated.length + data.upToDate.length) + + (sn.total || 0), + missing: data.missing.length + sn.missing.length, + outdated: data.outdated.length + sn.outdated.length, + upToDate: data.upToDate.length + sn.upToDate.length, + orphaned: data.orphaned.length + sn.orphaned.length, + errors: data.errors.length, + }; + return acc; + }, {}); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!translationData && !loading && !error) { + return ( +
+
+
+ + + + + + + +

+ Translation Dashboard +

+
+ +
+
+ ); + } + + if (loading) { + return ( +
+
+
+ Loading Dashboard +
+
+ Scanning translations... +
+ + {/* Progress Bar for Loading */} +
+
+
+
+ +
+ ); + } + + if (error) { + return ( +
+
+
+ Error: {error} +
+ +
+
+ ); + } + + if (!translationData) { + return ( +
+
+ No translation data available +
+
+ ); + } + + const totalCounts = getTotalCounts(); + const languages = Object.keys(translationData); + + return ( +
+
+
+ + + + + + + +

+ Translation Dashboard +

+
+
+ + + + + + + {/* Debug import now runs immediately when a file is selected via Import XLIFF */} +
+
+ {status && ( +
{status}
+ )} + + {/* Progress Bars for Async Operations */} + {addProgress !== null && ( +
+
+ Adding Missing Topics: {addProgress}% +
+
+
+
+
+ )} + + {importProgress !== null && ( +
+
+ Importing XLIFF: {importProgress}% +
+
+
+
+
+ )} + + {loading && ( +
+
+ Scanning translations... +
+
+
+
+
+ )} + + + + {/* Translation Statistics Cards */} +
+ {(() => { + const counts = totalCounts[selectedLanguage]; + if (!counts) return null; + + return [ + { + label: "Up to Date", + value: counts.upToDate, + icon: ( + + + + ), + bgColor: "bg-green-100", + iconColor: "text-green-600", + textColor: "text-green-600", + }, + { + label: "Outdated", + value: counts.outdated, + icon: ( + + + + + ), + bgColor: "bg-orange-100", + iconColor: "text-orange-600", + textColor: "text-orange-600", + }, + { + label: "Missing", + value: counts.missing, + icon: ( + + + + + + ), + bgColor: "bg-red-100", + iconColor: "text-red-600", + textColor: "text-red-600", + }, + { + label: "Orphaned", + value: counts.orphaned, + icon: ( + + + + + ), + bgColor: "bg-purple-100", + iconColor: "text-purple-600", + textColor: "text-purple-600", + }, + ].map((stat, index) => ( +
+
+
{stat.icon}
+
+
+

+ {stat.label} +

+

+ {stat.value} +

+
+
+ )); + })()} +
+ + {/* Language Selection */} +
+
+ + +
+
+ + {/* Detailed View */} + {(() => { + const data = translationData[selectedLanguage]; + if (!data) return null; + + return ( +
+ {/* Missing Files */} + {data.missing.length > 0 && ( +
+

+ + + + + Missing Translations ({data.missing.length}) +

+
+ {data.missing.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+
+ Source: {formatDate(item.sourceLastMod)} +
+
+ ))} +
+
+ )} + + {/* Outdated Files */} + {data.outdated.length > 0 && ( +
+

+ + + + + Outdated Translations ({data.outdated.length}) +

+
+ {data.outdated.map((item, index) => ( +
+
+ {item.title} + +
+
+ {item.file} + Source: {formatDate(item.sourceLastMod)} +
+
+ + {item.daysBehind + ? `${item.daysBehind} days behind` + : ""} + + + Translation: {formatDate(item.translationLastMod)} + +
+
+ ))} +
+
+ )} + + {/* Up to Date Files */} + {data.upToDate.length > 0 && selectedLanguage !== "all" && ( +
+

+ + + + Up to Date Translations ({data.upToDate.length}) +

+
+ {data.upToDate.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+
+ {formatDate(item.translationLastMod)} +
+
+ ))} +
+
+ )} + + {/* Orphaned Files */} + {data.orphaned.length > 0 && ( +
+

+ + + + + Orphan Topics ({data.orphaned.length}) +

+
+ {data.orphaned.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+ Translation exists but no source file found +
+
+
+ Translation: {formatDate(item.translationLastMod)} +
+
+ ))} +
+
+ )} + + {/* Errors */} + {data.errors.length > 0 && ( +
+

+ + + + + + Errors ({data.errors.length}) +

+
+ {data.errors.map((item, index) => ( +
+
+ {item.file} +
+
+ {item.error} +
+
+ ))} +
+
+ )} + + {/* Snippets Section */} + {data.snippets && data.snippets.total > 0 && ( +
+

+ + + + + + + + Snippets +

+ + {/* Missing Snippets */} + {data.snippets.missing.length > 0 && ( +
+

+ + + + + Missing Snippet Translations ( + {data.snippets.missing.length}) +

+
+ {data.snippets.missing.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+
+ ))} +
+
+ )} + + {/* Outdated Snippets */} + {data.snippets.outdated.length > 0 && ( +
+

+ + + + + Outdated Snippet Translations ( + {data.snippets.outdated.length}) +

+
+ {data.snippets.outdated.map((item, index) => ( +
+
+ + {item.title} + + +
+
+ {item.file} + + Source: {formatDate(item.sourceLastMod)} + +
+
+ + {item.daysBehind + ? `${item.daysBehind} days behind` + : ""} + + + Translation: {formatDate(item.translationLastMod)} + +
+
+ ))} +
+
+ )} + + {/* Up to Date Snippets */} + {data.snippets.upToDate.length > 0 && ( +
+

+ + + + Up to Date Snippet Translations ( + {data.snippets.upToDate.length}) +

+
+ {data.snippets.upToDate.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+
+ {formatDate(item.translationLastMod)} +
+
+ ))} +
+
+ )} + + {/* Orphaned Snippets */} + {data.snippets.orphaned.length > 0 && ( +
+

+ + + + + Orphan Snippets ({data.snippets.orphaned.length}) +

+
+ {data.snippets.orphaned.map((item, index) => ( +
+
+ {item.title} +
+ {item.file} +
+
+ Translation exists but no source snippet found +
+
+
+ Translation: {formatDate(item.translationLastMod)} +
+
+ ))} +
+
+ )} +
+ )} +
+ ); + })()} +
+ ); +}; + +export default TranslationDashboard; diff --git a/src/components/Dashboard/template.jsx b/src/components/Dashboard/template.jsx index c691933e..c2818611 100644 --- a/src/components/Dashboard/template.jsx +++ b/src/components/Dashboard/template.jsx @@ -1,144 +1,152 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React from 'react'; -import Dashboard1 from './Dashboard1'; -import MediaDashboard from './MediaDashboard'; -import TranslationDashboard from './TranslationDashboard'; -import BrokenLinksDashboard from './BrokenLinksDashboard'; -import ContentReuseDashboard from './ContentReuseDashboard'; -import StatusBar from './StatusBar'; -import HelpButton from '../HelpButton'; -//. import DocumentMutationDashboard from './DocumentMutationDashboard'; - -export const DashboardsCollection = { - name: "dashboards", - label: "Dashboards", - path: "static/dashboards", - format: "json", - ui: { - allowedActions: { - create: false, - delete: false, - }, - }, - fields: [ - { - type: "boolean", - name: "statusBar", - label: "", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - { - type: "boolean", - name: "help", - label: "Help", - required: false, - ui: { - component: (props) => ( - - ), - }, - }, - { - type: "boolean", - name: "dashboard1", - label: "Content Overview", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - { - type: "boolean", - name: "contentReuseDashboard", - label: "Content Reuse Overview", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - { - type: "boolean", - name: "mediaDashboard", - label: "Media Library", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - { - type: "boolean", - name: "translationDashboard", - label: "Translation Status", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - { - type: "boolean", - name: "brokenLinksDashboard", - label: "Broken Links", - required: false, - ui: { - component: (props) => ( -
- -
- ), - }, - }, - - // { - // type: "boolean", - // name: "documentMutationDashboard", - // label: "Document Mutations", - // required: false, - // ui: { - // component: (props) => ( - // - // ), - // }, - // }, - ], -}; - -export { Dashboard1, MediaDashboard, TranslationDashboard, BrokenLinksDashboard, StatusBar }; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from "react"; +import HelpButton from "../HelpButton"; +import BrokenLinksDashboard from "./BrokenLinksDashboard"; +import ContentReuseDashboard from "./ContentReuseDashboard"; +import Dashboard1 from "./Dashboard1"; +import MediaDashboard from "./MediaDashboard"; +import StatusBar from "./StatusBar"; +import TranslationDashboard from "./TranslationDashboard"; +//. import DocumentMutationDashboard from './DocumentMutationDashboard'; + +export const DashboardsCollection = { + name: "dashboards", + label: "Dashboards", + path: "static/dashboards", + format: "json", + ui: { + allowedActions: { + create: false, + delete: false, + }, + }, + fields: [ + { + type: "boolean", + name: "statusBar", + label: "", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + { + type: "boolean", + name: "help", + label: "Help", + required: false, + ui: { + component: (props) => ( + + ), + }, + }, + { + type: "boolean", + name: "dashboard1", + label: "Content Overview", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + { + type: "boolean", + name: "contentReuseDashboard", + label: "Content Reuse Overview", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + { + type: "boolean", + name: "mediaDashboard", + label: "Media Library", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + { + type: "boolean", + name: "translationDashboard", + label: "Translation Status", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + { + type: "boolean", + name: "brokenLinksDashboard", + label: "Broken Links", + required: false, + ui: { + component: (_props) => ( +
+ +
+ ), + }, + }, + + // { + // type: "boolean", + // name: "documentMutationDashboard", + // label: "Document Mutations", + // required: false, + // ui: { + // component: (props) => ( + // + // ), + // }, + // }, + ], +}; + +export { + BrokenLinksDashboard, + Dashboard1, + MediaDashboard, + StatusBar, + TranslationDashboard, +}; diff --git a/src/components/Features/template.jsx b/src/components/Features/template.jsx index 3e287e23..97b15ff7 100644 --- a/src/components/Features/template.jsx +++ b/src/components/Features/template.jsx @@ -1,3 +1,4 @@ +import React from "react"; /** * Copyright (c) Source Solutions, Inc. * @@ -5,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -import React from "react"; - export const FeaturesBlockTemplate = { name: "features", label: "Features", diff --git a/src/components/Figure/index.jsx b/src/components/Figure/index.jsx index c6a00792..6fe17052 100644 --- a/src/components/Figure/index.jsx +++ b/src/components/Figure/index.jsx @@ -5,7 +5,63 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; + +// Depends on nothing, so it lives at module scope rather than being rebuilt on +// every render. +const lightboxStyles = { + overlay: { + position: "fixed", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "rgba(0, 0, 0, 0.8)", + display: "flex", + alignItems: "center", + justifyContent: "center", + zIndex: 9999, + cursor: "pointer", + border: "none", + padding: 0, + }, + content: { + maxWidth: "90vw", + maxHeight: "90vh", + position: "relative", + }, + image: { + maxWidth: "100%", + maxHeight: "100%", + objectFit: "contain", + }, + closeButton: { + position: "absolute", + top: "-40px", + right: "0", + color: "white", + fontSize: "24px", + cursor: "pointer", + background: "none", + border: "none", + padding: "8px", + }, + caption: { + color: "white", + textAlign: "center", + marginTop: "10px", + fontSize: "14px", + }, + thumbnailButton: { + background: "none", + border: "none", + padding: 0, + cursor: "pointer", + display: "inline", + font: "inherit", + color: "inherit", + }, +}; const Figure = ({ img, caption, size, hideCaption = false, align }) => { const [isLightboxOpen, setIsLightboxOpen] = useState(false); @@ -24,77 +80,74 @@ const Figure = ({ img, caption, size, hideCaption = false, align }) => { return "center"; }; - const lightboxStyles = { - overlay: { - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0, 0, 0, 0.8)", - display: "flex", - alignItems: "center", - justifyContent: "center", - zIndex: 9999, - cursor: "pointer", - }, - content: { - maxWidth: "90vw", - maxHeight: "90vh", - position: "relative", - }, - image: { - maxWidth: "100%", - maxHeight: "100%", - objectFit: "contain", - }, - closeButton: { - position: "absolute", - top: "-40px", - right: "0", - color: "white", - fontSize: "24px", - cursor: "pointer", - background: "none", - border: "none", - padding: "8px", - }, - caption: { - color: "white", - textAlign: "center", - marginTop: "10px", - fontSize: "14px", - }, - }; + // Close on Escape and lock background scrolling while the lightbox is open. + useEffect(() => { + if (!isLightboxOpen) return; + + const onKeyDown = (e) => { + if (e.key === "Escape") setIsLightboxOpen(false); + }; + document.addEventListener("keydown", onKeyDown); + + const previousOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + + return () => { + document.removeEventListener("keydown", onKeyDown); + document.body.style.overflow = previousOverflow; + }; + }, [isLightboxOpen]); + + // An image with no caption would otherwise render with no alt text at all. + const altText = caption || "Figure"; return ( <>
- {caption} + aria-label={`Enlarge image: ${altText}`} + style={{ ...lightboxStyles.thumbnailButton, width: imageWidth }} + > + {altText} + {!hideCaption &&
{caption}
}
{isLightboxOpen && ( -
+ // biome-ignore lint/a11y/noStaticElementInteractions: click-to-dismiss backdrop; Escape and the close button provide the keyboard path +
e.stopPropagation()} + role="dialog" + aria-modal="true" + aria-label={altText} > - {caption} + {altText} {caption &&
{caption}
}
diff --git a/src/components/Figure/template.jsx b/src/components/Figure/template.jsx index 5d52a98c..756cd0d4 100644 --- a/src/components/Figure/template.jsx +++ b/src/components/Figure/template.jsx @@ -32,13 +32,15 @@ export const FigureBlockTemplate = { name: "size", label: "Size (%)", type: "number", - description: "Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)", + description: + "Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)", }, { name: "align", label: "Alignment", type: "string", - description: "Align the image left or right (only applies when size is less than 100)", + description: + "Align the image left or right (only applies when size is less than 100)", options: [ { value: "left", label: "Left" }, { value: "center", label: "Center" }, diff --git a/src/components/Footnote/FootnotesList.jsx b/src/components/Footnote/FootnotesList.jsx index d82faa6b..45431f44 100644 --- a/src/components/Footnote/FootnotesList.jsx +++ b/src/components/Footnote/FootnotesList.jsx @@ -12,33 +12,18 @@ const FootnotesList = () => { const context = useContext(FootnotesContext); const [footnotes, setFootnotes] = useState([]); + // As in Footnote/index.jsx, the context default always supplies these, so the + // former window.globalFootnotes fallbacks were unreachable. useEffect(() => { - if (context?.footnotes) { - // Use context footnotes if available - setFootnotes(context.footnotes); - } else if (typeof window !== "undefined" && window.globalFootnotes) { - // Fallback to global footnotes - setFootnotes(window.globalFootnotes); - } else { - setFootnotes([]); - } - }, [context?.footnotes]); + setFootnotes(context.footnotes); + }, [context.footnotes]); // Clear footnotes when component unmounts (page navigation) useEffect(() => { - if (context?.clearFootnotes) { - return () => { - context.clearFootnotes(); - }; - } - // Clear global footnotes return () => { - if (typeof window !== "undefined") { - window.globalFootnotes = []; - window.globalFootnoteMap = new Map(); - } + context.clearFootnotes(); }; - }, [context?.clearFootnotes]); + }, [context.clearFootnotes]); if (!footnotes || footnotes.length === 0) { return null; diff --git a/src/components/Footnote/FootnotesProvider.jsx b/src/components/Footnote/FootnotesProvider.jsx index 69c26567..0374b89e 100644 --- a/src/components/Footnote/FootnotesProvider.jsx +++ b/src/components/Footnote/FootnotesProvider.jsx @@ -5,7 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -import React, { createContext, useCallback, useRef, useState } from "react"; +import React, { + createContext, + useCallback, + useMemo, + useRef, + useState, +} from "react"; import { generateFootnoteKey } from "./utils"; // Create context with default values @@ -48,15 +54,22 @@ export const FootnotesProvider = ({ children }) => { footnoteCountRef.current = 0; }, []); - const value = { - footnotes, - addFootnote, - clearFootnotes, - getFootnoteNumber: (content) => { - const contentKey = generateFootnoteKey(content); - return footnoteMapRef.current.get(contentKey); - }, - }; + const getFootnoteNumber = useCallback((content) => { + const contentKey = generateFootnoteKey(content); + return footnoteMapRef.current.get(contentKey); + }, []); + + // Memoised: rebuilding this object every render re-rendered every consumer + // and defeated the useCallback wrappers above it. + const value = useMemo( + () => ({ + footnotes, + addFootnote, + clearFootnotes, + getFootnoteNumber, + }), + [footnotes, addFootnote, clearFootnotes, getFootnoteNumber] + ); return ( diff --git a/src/components/Footnote/index.jsx b/src/components/Footnote/index.jsx index 7102928d..d6442381 100644 --- a/src/components/Footnote/index.jsx +++ b/src/components/Footnote/index.jsx @@ -7,45 +7,17 @@ import React, { useContext, useEffect, useState } from "react"; import { FootnotesContext } from "./FootnotesProvider"; -import { generateFootnoteKey } from "./utils"; const Footnote = ({ children }) => { const context = useContext(FootnotesContext); const [footnoteNumber, setFootnoteNumber] = useState(null); + // FootnotesContext is created with a default value that already provides + // addFootnote, so this is always defined — the previous window.globalFootnotes + // fallback below it was unreachable and has been removed. useEffect(() => { - // Safely convert content to string for comparison - const contentKey = generateFootnoteKey(children); - - if (context?.addFootnote) { - // Use context if available - const number = context.addFootnote(children); - setFootnoteNumber(number); - } else { - // Fallback to global state - if (typeof window !== "undefined") { - if (!window.globalFootnotes) window.globalFootnotes = []; - if (!window.globalFootnoteMap) window.globalFootnoteMap = new Map(); - - if (window.globalFootnoteMap.has(contentKey)) { - const number = window.globalFootnoteMap.get(contentKey); - setFootnoteNumber(number); - } else { - const newNumber = window.globalFootnotes.length + 1; - window.globalFootnotes.push({ - number: newNumber, - content: children, - key: contentKey, - }); - window.globalFootnoteMap.set(contentKey, newNumber); - setFootnoteNumber(newNumber); - } - } else { - // Server-side rendering fallback - setFootnoteNumber(1); - } - } - }, [children, context?.addFootnote]); + setFootnoteNumber(context.addFootnote(children)); + }, [children, context.addFootnote]); const handleClick = (e) => { e.preventDefault(); diff --git a/src/components/Footnote/utils.jsx b/src/components/Footnote/utils.jsx index f5670d0f..cf2c138d 100644 --- a/src/components/Footnote/utils.jsx +++ b/src/components/Footnote/utils.jsx @@ -24,7 +24,7 @@ export const generateFootnoteKey = (content) => { } if (typeof content === "object" && content !== null) { // For objects, try to stringify safely - return JSON.stringify(content, (key, value) => { + return JSON.stringify(content, (_key, value) => { if (typeof value === "object" && value !== null) { // Skip React internal properties that can cause circular references if (value._owner || value._store || value._source || value._self) { @@ -39,8 +39,8 @@ export const generateFootnoteKey = (content) => { }); } return String(content); - } catch (error) { - return `fallback-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + } catch { + return `fallback-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`; } }; diff --git a/src/components/GlossaryTerm/index.jsx b/src/components/GlossaryTerm/index.jsx index 5b95b5e6..700a9293 100644 --- a/src/components/GlossaryTerm/index.jsx +++ b/src/components/GlossaryTerm/index.jsx @@ -57,11 +57,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { // Add debug mode - uncomment next line to force touch mode for testing // return true; // TEMPORARY: Force touch mode for testing - return ( - "ontouchstart" in window || - navigator.maxTouchPoints > 0 || - navigator.msMaxTouchPoints > 0 - ); + return "ontouchstart" in window || navigator.maxTouchPoints > 0; }; setIsTouchDevice(checkTouchDevice()); @@ -94,52 +90,6 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { } }, [showDefinition, isTouchDevice]); - // Position the definition box to avoid screen overflow - const getDefinitionStyle = () => { - if (!termRef.current || !showDefinition) return {}; - - const termRect = termRef.current.getBoundingClientRect(); - const viewportWidth = window.innerWidth; - const viewportHeight = window.innerHeight; - - // Default positioning below the term - let top = termRect.bottom + 8; - let left = termRect.left; - - // Estimated definition box width (will be adjusted by CSS max-width) - const estimatedWidth = Math.min(300, viewportWidth - 20); - - // Check if definition would overflow right edge - if (left + estimatedWidth > viewportWidth - 10) { - left = viewportWidth - estimatedWidth - 10; - } - - // Check if definition would overflow left edge - if (left < 10) { - left = 10; - } - - // Check if definition would overflow bottom edge - // Estimate height as roughly 100px (will be adjusted by content) - const estimatedHeight = 100; - if (top + estimatedHeight > viewportHeight - 10) { - // Position above the term instead - top = termRect.top - estimatedHeight - 8; - - // If still overflowing top, position at top of viewport - if (top < 10) { - top = 10; - } - } - - return { - position: "fixed", - top: `${top}px`, - left: `${left}px`, - zIndex: 2147483647, // Maximum z-index value - }; - }; - const handleTermClick = () => { if (isTouchDevice) { setShowDefinition(!showDefinition); @@ -212,9 +162,15 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { }; const { term, definition } = getTermData(); - - // Create the definition box component - const DefinitionBox = () => { + const displayTerm = + initcap && term !== "TERM NOT FOUND" + ? term.charAt(0).toUpperCase() + term.slice(1) + : term; + + // Rendered inline rather than declared as a component: a component defined + // in the render body gets a new identity every render, which made React + // unmount and remount the popup continuously while it was open. + const renderDefinitionBox = () => { if (!termRef.current) return null; const termRect = termRef.current.getBoundingClientRect(); @@ -261,6 +217,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { return (
{ color: textColor, }} > - {initcap && term !== "TERM NOT FOUND" - ? term.charAt(0).toUpperCase() + term.slice(1) - : term} + {displayTerm}
{definition}
@@ -301,10 +256,18 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { return ( <> - { onClick={handleTermClick} onTouchStart={isTouchDevice ? (e) => e.stopPropagation() : undefined} > - {initcap && term !== "TERM NOT FOUND" - ? term.charAt(0).toUpperCase() + term.slice(1) - : term} - + {displayTerm} + {isTouchDevice && showDefinition && @@ -335,7 +296,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { zIndex: "999999999", }} > - + {renderDefinitionBox()}
, portalElement )} diff --git a/src/components/HelpButton/index.jsx b/src/components/HelpButton/index.jsx index 81b3e523..0533dabd 100644 --- a/src/components/HelpButton/index.jsx +++ b/src/components/HelpButton/index.jsx @@ -99,14 +99,14 @@ export default function HelpButton({ url }) { const unwantedLinks = document.querySelectorAll( 'a[href="#/collections/generated/~"], a[href="#/collections/media/~"]' ); - unwantedLinks.forEach((link) => { + for (const link of unwantedLinks) { const li = link.closest("li"); if (li) { li.remove(); } else { link.remove(); } - }); + } }; // Inject custom TinaCMS styles @@ -189,8 +189,9 @@ export default function HelpButton({ url }) { // which bypasses beforeunload (e.g. TinaCMS left nav links). const originalPushState = history.pushState.bind(history); const originalReplaceState = history.replaceState.bind(history); - const guardNavigation = (original) => - function (...args) { + const guardNavigation = + (original) => + (...args) => { if (hasUnsavedChanges()) { const confirmed = window.confirm( "You have unsaved changes. Leave without saving?" @@ -207,23 +208,24 @@ export default function HelpButton({ url }) { window.location.hostname === "127.0.0.1" ) { const autoSaveTimeout = setTimeout(() => { - autoSaveInterval = setInterval(() => { - if (isNewDocumentPage()) return; - const saveBtn = Array.from(document.querySelectorAll("button")).find( - (b) => - b.textContent?.trim() === "Save" && - !b.disabled && - b.offsetParent !== null - ); - if (saveBtn) { - saveBtn.click(); - lastAutoSaveAt = Date.now(); - console.log( - `[TinaCMS Auto-Save] Saved at ${new Date().toLocaleTimeString()}` + autoSaveInterval = setInterval( + () => { + if (isNewDocumentPage()) return; + const saveBtn = Array.from( + document.querySelectorAll("button") + ).find( + (b) => + b.textContent?.trim() === "Save" && + !b.disabled && + b.offsetParent !== null ); - } - }, 5 * 60 * 1000); - console.log("[TinaCMS Auto-Save] Active — checking every 5m (local only, skips new documents)"); + if (saveBtn) { + saveBtn.click(); + lastAutoSaveAt = Date.now(); + } + }, + 5 * 60 * 1000 + ); }, 3000); return () => { @@ -245,7 +247,7 @@ export default function HelpButton({ url }) { history.pushState = originalPushState; history.replaceState = originalReplaceState; }; - }, []); + }, [url]); return null; } diff --git a/src/components/Hero/template.jsx b/src/components/Hero/template.jsx index 64f5ab63..a30114bf 100644 --- a/src/components/Hero/template.jsx +++ b/src/components/Hero/template.jsx @@ -1,3 +1,4 @@ +import React from "react"; /** * Copyright (c) Source Solutions, Inc. * @@ -5,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -import React from "react"; - export const HeroBlockTemplate = { name: "hero", label: "Hero", diff --git a/src/components/Passthrough/index.jsx b/src/components/Passthrough/index.jsx index 4d3cbcfe..05653d84 100644 --- a/src/components/Passthrough/index.jsx +++ b/src/components/Passthrough/index.jsx @@ -10,8 +10,8 @@ import Markdown from "react-markdown"; import rehypeKatex from "rehype-katex"; import rehypeRaw from "rehype-raw"; import remarkBreaks from "remark-breaks"; -import remarkMath from "remark-math"; import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; import "katex/dist/katex.min.css"; // Import KaTeX CSS // Import available components that can be used in JSX @@ -23,62 +23,66 @@ import ColorGenerator from "@site/src/components/ColorGenerator"; * @param {string} string - The content to render * @param {string} type - The content type: 'jsx', 'html', 'markdown', 'code', or 'auto' (default) */ -const Passthrough = ({ summary, string, type }) => { - // Custom input renderer to make task list checkboxes interactive - const CustomInput = ({ disabled, style, ...props }) => { - // Remove disabled attribute from task list checkboxes and add readOnly - if (props.type === "checkbox") { - return ; - } - return ; - }; +const Passthrough = ({ string, type }) => { + // Custom input renderer to make task list checkboxes interactive + const CustomInput = ({ disabled, style, ...props }) => { + // Remove disabled attribute from task list checkboxes and add readOnly + if (props.type === "checkbox") { + return ; + } + return ; + }; - // Custom ul renderer with static CSS-only indentation - const CustomUl = ({ className, children, ...props }) => { - const isTaskList = className?.includes('contains-task-list'); - - if (isTaskList) { - return ( -
    - {children} -
- ); - } - - return ( -
    - {children} -
- ); - }; + // Custom ul renderer with static CSS-only indentation + const CustomUl = ({ className, children, ...props }) => { + const isTaskList = className?.includes("contains-task-list"); - // Custom li renderer with proper task list styling - const CustomLi = ({ className, children, ...props }) => { - const isTaskListItem = className?.includes('task-list-item'); - + if (isTaskList) { return ( -
  • {children} -
  • + ); - }; + } + + return ( +
      + {children} +
    + ); + }; + + // Custom li renderer with proper task list styling + const CustomLi = ({ className, children, ...props }) => { + const isTaskListItem = className?.includes("task-list-item"); + + return ( +
  • + {children} +
  • + ); + }; if (!string) return null; - + // Process ^ symbols for indentation (each ^ = 2 spaces) const processedString = string.replace(/\^/g, " "); diff --git a/src/components/RelatedTopics/index.jsx b/src/components/RelatedTopics/index.jsx index 7c54a6be..8a020d7e 100644 --- a/src/components/RelatedTopics/index.jsx +++ b/src/components/RelatedTopics/index.jsx @@ -5,12 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import { useLocation } from "@docusaurus/router"; -import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Link from "@docusaurus/Link"; -import React from "react"; +import { useLocation } from "@docusaurus/router"; // Import the generated static metadata import docsMetadata from "@site/src/data/docs-metadata.json"; +import React from "react"; /** * RelatedTopics component for Tina CMS @@ -26,19 +25,21 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Get current page metadata from static data const getCurrentPageMetadata = () => { const currentPath = location.pathname; - + // Remove /docs prefix if present to match metadata format - const normalizedPath = currentPath.startsWith('/docs') - ? currentPath.replace('/docs', '') + const normalizedPath = currentPath.startsWith("/docs") + ? currentPath.replace("/docs", "") : currentPath; - + // Find current page in static docs metadata - const currentDoc = docsMetadata.find(doc => { + const currentDoc = docsMetadata.find((doc) => { // Handle different path variations const docPath = doc.path; - return docPath === normalizedPath || - docPath === normalizedPath.replace(/\/$/, '') || - `${docPath}/` === normalizedPath; + return ( + docPath === normalizedPath || + docPath === normalizedPath.replace(/\/$/, "") || + `${docPath}/` === normalizedPath + ); }); return currentDoc; @@ -46,26 +47,33 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Calculate tag similarity between two arrays of tags const calculateSimilarity = (currentTags, otherTags) => { - if (!currentTags || !otherTags || !currentTags.length || !otherTags.length) { + if ( + !currentTags || + !otherTags || + !currentTags.length || + !otherTags.length + ) { return 0; } const currentTagsSet = new Set(currentTags); const otherTagsSet = new Set(otherTags); - + // Calculate intersection - const intersection = new Set([...currentTagsSet].filter(tag => otherTagsSet.has(tag))); - + const intersection = new Set( + [...currentTagsSet].filter((tag) => otherTagsSet.has(tag)) + ); + // Calculate union const union = new Set([...currentTagsSet, ...otherTagsSet]); - + // Jaccard similarity coefficient return intersection.size / union.size; }; // Get related topics based on tag similarity const getRelatedTopics = (currentDoc) => { - if (!currentDoc || !currentDoc.tags) { + if (!currentDoc?.tags) { return []; } @@ -74,17 +82,15 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Find related docs const relatedDocs = docsMetadata - .filter(doc => { + .filter((doc) => { // Exclude current document and docs without tags - return doc.path !== currentPath && - doc.tags && - Array.isArray(doc.tags); + return doc.path !== currentPath && doc.tags && Array.isArray(doc.tags); }) - .map(doc => ({ + .map((doc) => ({ ...doc, - similarity: calculateSimilarity(currentTags, doc.tags) + similarity: calculateSimilarity(currentTags, doc.tags), })) - .filter(doc => doc.similarity > 0) // Only include docs with some similarity + .filter((doc) => doc.similarity > 0) // Only include docs with some similarity .sort((a, b) => { // Sort by similarity first, then by title for consistent ordering if (b.similarity !== a.similarity) { @@ -98,8 +104,8 @@ const RelatedTopics = ({ maxResults = 5 }) => { }; const currentDoc = getCurrentPageMetadata(); - - if (!currentDoc || !currentDoc.tags) { + + if (!currentDoc?.tags) { return null; } @@ -115,12 +121,11 @@ const RelatedTopics = ({ maxResults = 5 }) => {
      {relatedTopics.map((topic, index) => (
    • - - {topic.title} - + {topic.title} {topic.description && ( - {" – "}{topic.description} + {" – "} + {topic.description} )}
    • @@ -130,4 +135,4 @@ const RelatedTopics = ({ maxResults = 5 }) => { ); }; -export default RelatedTopics; \ No newline at end of file +export default RelatedTopics; diff --git a/src/components/RelatedTopics/template.jsx b/src/components/RelatedTopics/template.jsx index 08bbc8bd..8dd3bb5a 100644 --- a/src/components/RelatedTopics/template.jsx +++ b/src/components/RelatedTopics/template.jsx @@ -12,8 +12,8 @@ export const RelatedTopicsBlockTemplate = { ui: { itemProps: (item) => { const maxResults = item?.maxResults || 5; - return { - label: `Related Topics (max: ${maxResults})` + return { + label: `Related Topics (max: ${maxResults})`, }; }, }, @@ -32,4 +32,4 @@ export const RelatedTopicsBlockTemplate = { }, }, ], -}; \ No newline at end of file +}; diff --git a/src/components/Settings/template.jsx b/src/components/Settings/template.jsx index 2d77d750..0fc61d82 100644 --- a/src/components/Settings/template.jsx +++ b/src/components/Settings/template.jsx @@ -7,32 +7,15 @@ import React from "react"; import { ImageField, ReferenceField, TextField } from "tinacms"; -import docusaurusData from "../../../config/docusaurus/index.json"; import CollapsibleField from "../CollapsibleField"; import HelpButton from "../HelpButton"; -// Function to create language options from config data -function createLanguageOptions(configData = docusaurusData) { - const supportedLanguages = configData.languages?.supported || [ - { code: "en", label: "English" }, - ]; - - return supportedLanguages.map((langObj) => { - return { - value: langObj.code, - label: `${langObj.label} (${langObj.code})`, - }; - }); -} - -const languageOptions = createLanguageOptions(); - const WarningIcon = (props) => { return ( { const RestartWarning = () => { return ( -

      +

      @@ -55,10 +38,37 @@ const RestartWarning = () => { after saving (local development only).
      -

      +
      ); }; +// Navbar item fields live inside an object list, so each component receives a +// `field.name` such as "navbar.items.3.docLink". Which of the link-detail +// fields is shown depends on the sibling `link` value on the same item. +// (`doc` intentionally shows two: the reference picker and the anchor id.) +const showWhenLinkIs = (expected, Field) => (props) => { + const link = React.useMemo(() => { + const fieldName = props.field.name; + const parentPath = + fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; + // Guarded walk: an incomplete path used to throw and take the whole + // settings form down. + const parent = parentPath + .split(".") + .reduce( + (o, key) => (o == null ? undefined : o[key]), + props.tinaForm.values + ); + return parent?.link; + }, [props.tinaForm.values, props.field.name]); + + if (link !== expected) { + return null; + } + + return Field(props); +}; + const NavbarItemFields = [ { name: "label", @@ -120,23 +130,7 @@ const NavbarItemFields = [ type: "reference", collections: ["doc"], ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "doc") { - return null; - } - - return ReferenceField(props); - }, + component: showWhenLinkIs("doc", ReferenceField), }, }, { @@ -145,23 +139,7 @@ const NavbarItemFields = [ type: "reference", collections: ["pages"], ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "page") { - return null; - } - - return ReferenceField(props); - }, + component: showWhenLinkIs("page", ReferenceField), }, }, { @@ -169,23 +147,7 @@ const NavbarItemFields = [ label: "URL", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "external") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("external", TextField), }, }, { @@ -193,23 +155,7 @@ const NavbarItemFields = [ label: "Manual Path", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "manualPath") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("manualPath", TextField), }, }, { @@ -217,23 +163,7 @@ const NavbarItemFields = [ label: "Document ID", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "doc") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("doc", TextField), }, }, { diff --git a/src/components/Snippet/index.jsx b/src/components/Snippet/index.jsx index 74b4b6d1..df83f7a2 100644 --- a/src/components/Snippet/index.jsx +++ b/src/components/Snippet/index.jsx @@ -32,14 +32,14 @@ const Snippet = ({ filepath }) => { ); } if (isMounted) setSnippetMDX(() => mod.default); - } catch (e) { + } catch (_e) { try { const mod = await import( /* webpackInclude: /\.mdx$/ */ `@site/reuse/snippets/${filepath}` ); if (isMounted) setSnippetMDX(() => mod.default); - } catch (e2) { + } catch (_e2) { if (isMounted) setError("Error: Snippet not found."); } } diff --git a/src/components/StatusField/index.jsx b/src/components/StatusField/index.jsx index f2d0bd4a..aede97a6 100644 --- a/src/components/StatusField/index.jsx +++ b/src/components/StatusField/index.jsx @@ -8,7 +8,7 @@ import React from "react"; import { wrapFieldsWithMeta } from "tinacms"; -const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { +const StatusField = wrapFieldsWithMeta(({ tinaForm }) => { // All boolean field names involved in the workflow const allBooleans = [ "draft", @@ -21,16 +21,65 @@ const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { // Each workflow status maps to exactly which booleans should be true const statusMap = { - draft: { draft: true, review: false, translate: false, approved: false, published: false, unlisted: false }, - review: { draft: false, review: true, translate: false, approved: false, published: false, unlisted: true }, - translate: { draft: false, review: false, translate: true, approved: false, published: false, unlisted: true }, - approved: { draft: false, review: false, translate: false, approved: true, published: true, unlisted: false }, - published: { draft: false, review: false, translate: false, approved: false, published: true, unlisted: false }, - unlisted: { draft: false, review: false, translate: false, approved: false, published: false, unlisted: true }, + draft: { + draft: true, + review: false, + translate: false, + approved: false, + published: false, + unlisted: false, + }, + review: { + draft: false, + review: true, + translate: false, + approved: false, + published: false, + unlisted: true, + }, + translate: { + draft: false, + review: false, + translate: true, + approved: false, + published: false, + unlisted: true, + }, + approved: { + draft: false, + review: false, + translate: false, + approved: true, + published: true, + unlisted: false, + }, + published: { + draft: false, + review: false, + translate: false, + approved: false, + published: true, + unlisted: false, + }, + unlisted: { + draft: false, + review: false, + translate: false, + approved: false, + published: false, + unlisted: true, + }, }; // The UI options in display order - const statusOptions = ["draft", "review", "translate", "approved", "published", "unlisted"]; + const statusOptions = [ + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", + ]; // Determine which single workflow status is currently active based on the boolean combination const getCurrentStatus = () => { @@ -41,7 +90,14 @@ const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { // Match against statusMap in reverse-priority order (most specific first) // Order matters: approved (published+approved) must be checked before published (published only) - const checkOrder = ["review", "translate", "approved", "published", "unlisted", "draft"]; + const checkOrder = [ + "review", + "translate", + "approved", + "published", + "unlisted", + "draft", + ]; for (const status of checkOrder) { const expected = statusMap[status]; const match = allBooleans.every((b) => !!expected[b] === !!vals[b]); diff --git a/src/components/TagsField/index.jsx b/src/components/TagsField/index.jsx index ae978bee..809f84e0 100644 --- a/src/components/TagsField/index.jsx +++ b/src/components/TagsField/index.jsx @@ -8,14 +8,18 @@ import React, { useMemo, useState } from "react"; import { wrapFieldsWithMeta } from "tinacms"; -const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { +// Module-level constants: `field.options || []` produced a fresh array identity +// on every render, so the memos below never hit their cache. +const NO_TAGS = []; + +const TagsField = wrapFieldsWithMeta(({ input, field }) => { const [searchTerm, setSearchTerm] = useState(""); const [isOpen, setIsOpen] = useState(false); const [expandedNodes, setExpandedNodes] = useState(new Set()); const [viewMode, setViewMode] = useState("search"); // 'tree' or 'search' - const allTags = field.options || []; - const selectedTags = input.value || []; + const allTags = field.options || NO_TAGS; + const selectedTags = input.value || NO_TAGS; // Build tree structure from tags const tagTree = useMemo(() => { @@ -35,8 +39,6 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { name: part, fullPath: path, children: {}, - isLeaf: index === parts.length - 1, - level: index, }; } @@ -69,6 +71,20 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { return groups; }, [filteredTags]); + // Top-level segments present in the taxonomy, most-used first. Previously a + // hardcoded list carried over from one specific site's tags. + const popularCategories = useMemo(() => { + const counts = new Map(); + for (const tag of allTags) { + const top = tag.split("_")[0]; + if (top) counts.set(top, (counts.get(top) || 0) + 1); + } + return [...counts.entries()] + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + .slice(0, 5) + .map(([name]) => name); + }, [allTags]); + // Get all parent paths for a given tag const getParentPaths = (tagPath) => { const parts = tagPath.split("_"); @@ -330,25 +346,28 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { Popular Tags
      - {["customers", "teams", "a3-features", "components", "regions"] - .filter((tag) => allTags.some((t) => t.startsWith(tag))) - .map((category) => ( - - ))} + {popularCategories.map((category) => ( + + ))}
    )} {/* Click outside handler for search mode */} {viewMode === "search" && isOpen && ( -
    setIsOpen(false)} /> +
    ); diff --git a/src/css/custom.css b/src/css/custom.css index 1eca1a6d..16c21f0b 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -732,9 +732,6 @@ h6, } } -/* Mermaid Zoom Functionality */ -@import "../theme/Mermaid/mermaid-zoom.css"; - /* Ordered list styling */ ol { list-style-type: decimal; /* First level: 1, 2, 3, ... */ @@ -819,7 +816,6 @@ main s, transform: rotate(45deg); } - /* * Merge consecutive lists separated by ConditionalText components. * Also handle cases where empty elements are between lists diff --git a/src/data/docs-metadata.json b/src/data/docs-metadata.json index 2cfd31b9..7e98ef4e 100644 --- a/src/data/docs-metadata.json +++ b/src/data/docs-metadata.json @@ -93,7 +93,7 @@ ], "path": "/cli", "filePath": "cli.mdx", - "lastmod": "2026-06-01T00:00:00.000Z" + "lastmod": "2026-07-07T00:00:00.000Z" }, { "title": "Code blocks and snippets", @@ -366,7 +366,7 @@ ], "path": "/installation", "filePath": "installation.mdx", - "lastmod": "2026-06-01T00:00:00.000Z" + "lastmod": "2026-07-07T00:00:00.000Z" }, { "title": "Internationalization", diff --git a/src/pages/404.js b/src/pages/404.js index e1690735..90f62369 100644 --- a/src/pages/404.js +++ b/src/pages/404.js @@ -5,41 +5,48 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useEffect} from 'react'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import Layout from '@theme/Layout'; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import Layout from "@theme/Layout"; +import React, { useEffect } from "react"; export default function NotFound() { - const {i18n} = useDocusaurusContext(); + const { i18n } = useDocusaurusContext(); useEffect(() => { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; const tryFallback = async () => { - const {pathname, search, hash} = window.location; - const parts = pathname.split('/').filter(Boolean); + const { pathname, search, hash } = window.location; + const parts = pathname.split("/").filter(Boolean); if (!parts.length) return; const first = parts[0]; - if (!i18n || !i18n.locales || !i18n.locales.includes(first)) return; + if (!i18n?.locales?.includes(first)) return; if (first === i18n.defaultLocale) return; // Remove locale prefix to build default-locale path parts.shift(); - let fallbackPath = '/' + parts.join('/'); - if (fallbackPath === '/') fallbackPath = '/'; + let fallbackPath = `/${parts.join("/")}`; + if (fallbackPath === "/") fallbackPath = "/"; - const tryUrls = [fallbackPath, `${fallbackPath}.html`, `${fallbackPath}/index.html`]; + const tryUrls = [ + fallbackPath, + `${fallbackPath}.html`, + `${fallbackPath}/index.html`, + ]; for (const url of tryUrls) { try { - const res = await fetch(url, {method: 'GET', credentials: 'same-origin'}); + const res = await fetch(url, { + method: "GET", + credentials: "same-origin", + }); if (res && res.status === 200) { // Redirect to the URL that exists (preserve search + hash) window.location.replace(url + search + hash); return; } - } catch (e) { + } catch (_e) { // ignore network errors } } @@ -50,9 +57,12 @@ export default function NotFound() { return ( -
    +

    404 — Page not found

    -

    The page you requested does not exist in this language. Trying the default language...

    +

    + The page you requested does not exist in this language. Trying the + default language... +

    ); diff --git a/src/plugins/blog-date-filter.js b/src/plugins/blog-date-filter.js index 18802452..1a2dd8ba 100644 --- a/src/plugins/blog-date-filter.js +++ b/src/plugins/blog-date-filter.js @@ -1,6 +1,6 @@ -const fs = require('fs'); -const path = require('path'); -const matter = require('gray-matter'); +const fs = require("node:fs"); +const path = require("node:path"); +const matter = require("gray-matter"); /** * Get list of future-dated blog files that should be excluded @@ -9,75 +9,71 @@ const matter = require('gray-matter'); */ function getFutureDatedBlogFiles(blogDir) { const futureDatedFiles = []; - + // Only exclude future-dated files in production builds // Allow them in development for preview purposes - const isProduction = process.env.NODE_ENV === 'production'; - + const isProduction = process.env.NODE_ENV === "production"; + if (!isProduction) { - console.log('šŸš€ Development mode: Including future-dated blog posts for preview'); - return []; // Return empty array in development - include all posts + // Development: include all posts so future-dated drafts stay previewable + return []; } - + try { if (!fs.existsSync(blogDir)) { - console.warn(`Blog directory ${blogDir} does not exist`); return []; } const currentDate = new Date(); - const currentDateString = currentDate.toISOString().split('T')[0]; // YYYY-MM-DD format + const currentDateString = currentDate.toISOString().split("T")[0]; // YYYY-MM-DD format // Read all blog files - const allFiles = fs.readdirSync(blogDir) - .filter(file => file.endsWith('.md') || file.endsWith('.mdx')) - .filter(file => !file.startsWith('.')); + const allFiles = fs + .readdirSync(blogDir) + .filter((file) => file.endsWith(".md") || file.endsWith(".mdx")) + .filter((file) => !file.startsWith(".")); for (const file of allFiles) { try { const fullPath = path.join(blogDir, file); - const fileContent = fs.readFileSync(fullPath, 'utf8'); + const fileContent = fs.readFileSync(fullPath, "utf8"); const { data: frontmatter } = matter(fileContent); - + if (!frontmatter.date) { continue; // Skip files without dates } - + let postDateString; - + // Handle different date formats if (frontmatter.date instanceof Date) { - postDateString = frontmatter.date.toISOString().split('T')[0]; - } else if (typeof frontmatter.date === 'string') { + postDateString = frontmatter.date.toISOString().split("T")[0]; + } else if (typeof frontmatter.date === "string") { // Try to parse the date string const parsedDate = new Date(frontmatter.date); - if (!isNaN(parsedDate.getTime())) { - postDateString = parsedDate.toISOString().split('T')[0]; + if (!Number.isNaN(parsedDate.getTime())) { + postDateString = parsedDate.toISOString().split("T")[0]; } else { // Assume YYYY-MM-DD format if parsing fails - postDateString = frontmatter.date.split('T')[0]; + postDateString = frontmatter.date.split("T")[0]; } } - + // Add to exclude list if post date is in the future if (postDateString && postDateString > currentDateString) { futureDatedFiles.push(file); - console.log(`šŸ“… Excluding future-dated blog post: ${file} (date: ${postDateString})`); } - - } catch (error) { - console.warn(`Error checking blog post date for ${file}:`, error.message); + } catch { // Skip files with parsing errors (don't exclude them) } } - - } catch (error) { - console.warn(`Error reading blog directory ${blogDir}:`, error.message); + } catch { + // Unreadable blog directory: exclude nothing } return futureDatedFiles; } module.exports = { - getFutureDatedBlogFiles -}; \ No newline at end of file + getFutureDatedBlogFiles, +}; diff --git a/src/theme/template.jsx b/src/theme/template.jsx index b0c45e21..11ba1e5b 100644 --- a/src/theme/template.jsx +++ b/src/theme/template.jsx @@ -6,8 +6,6 @@ */ import React from "react"; -import codeFiles from "../../reuse/code-files.json"; -import { slugify } from "../../scripts/util"; import { CodeSnippetBlockTemplate } from "../components/CodeSnippet/template"; import { CommentBlockTemplate } from "../components/Comment/template"; import { ConditionalTextBlockTemplate } from "../components/ConditionalText/template"; @@ -145,21 +143,11 @@ const TruncateTemplate = { ], }; -// Get the last segment of the path as the slug -const usePageSlug = () => { - if (typeof window === "undefined") return ""; - const path = window.location.pathname; - const segments = path.split("/").filter(Boolean); - return segments[segments.length - 1] || ""; -}; - -const slug = usePageSlug(); - const ContextHelpTemplate = { name: "a", label: "Context Help", ui: { - itemProps: (item, slug) => { + itemProps: (item) => { return { label: item?.title }; }, }, @@ -178,7 +166,7 @@ const TabsTemplate = { name: "Tabs", label: "Tabs", ui: { - itemProps: (item) => { + itemProps: (_item) => { return { label: "Tabs" }; }, }, diff --git a/src/utils/editorIdentity.js b/src/utils/editorIdentity.js index fa3b90de..7d269039 100644 --- a/src/utils/editorIdentity.js +++ b/src/utils/editorIdentity.js @@ -17,7 +17,7 @@ function decodeJwtPayload(token) { const [, payload] = token.split("."); // atob works in browsers; guard against Unicode issues if needed return JSON.parse(atob(payload)); - } catch (e) { + } catch (_e) { return null; } } @@ -76,7 +76,11 @@ export async function getEditorIdentity() { if (gitLocal) return gitLocal; // 3) Env-provided local user - if (typeof process !== "undefined" && process.env && process.env.NEXT_PUBLIC_LOCAL_USER) { + if ( + typeof process !== "undefined" && + process.env && + process.env.NEXT_PUBLIC_LOCAL_USER + ) { return process.env.NEXT_PUBLIC_LOCAL_USER; } diff --git a/src/utils/themeUtils.js b/src/utils/themeUtils.js index 03a72bd5..2746eab6 100644 --- a/src/utils/themeUtils.js +++ b/src/utils/themeUtils.js @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require("fs"); -const path = require("path"); +const fs = require("node:fs"); +const path = require("node:path"); /** * Generate CSS variables from theme configuration @@ -119,10 +119,12 @@ function updateThemeCSS() { // Write CSS file fs.writeFileSync(cssPath, css); - - console.log("Theme CSS updated successfully!"); } catch (error) { - console.error("Error updating theme CSS:", error); + // Let the caller (scripts/update-theme-css.js) report and set the exit + // code — swallowing this here made the script print success on failure. + throw new Error(`Failed to update theme CSS: ${error.message}`, { + cause: error, + }); } } diff --git a/src/utils/xliff.js b/src/utils/xliff.js index 0c414a09..52176f56 100644 --- a/src/utils/xliff.js +++ b/src/utils/xliff.js @@ -9,59 +9,44 @@ // Exports title and body as JSON string in so MDX/React content is preserved. function escapeXml(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; + if (unsafe === null || unsafe === undefined) return ""; return String(unsafe) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - -function escapeXmlWithLineBreaks(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; - // Normalize newlines - let s = String(unsafe); - // Match all common newline sequences (CRLF, CR, LF) and normalize to a - // placeholder so we can safely escape XML and then restore XLIFF tags. - const LB = '___XLIFF_LB___'; - s = s.replace(/\r\n|\r|\n/g, LB); - s = s - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - // restore real XLIFF line-break tags - return s.replace(new RegExp(LB, 'g'), ''); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } // Escape XML but preserve real newline characters so XLIFF consumers // (and CAT tools like Swordfish) can round-trip actual line breaks. function escapeXmlPreserveNewlines(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; + if (unsafe === null || unsafe === undefined) return ""; return String(unsafe) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/\"/g, '"') - .replace(/'/g, '''); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } // Remove control characters that may be embedded in AST serializations // (keep tab, LF, CR). This prevents NULs and other controls from // corrupting XLIFF consumers or terminal output. function stripControlChars(s) { - if (s === null || s === undefined) return ''; + if (s === null || s === undefined) return ""; try { // Remove BOM and all Unicode C0/C1 control characters (U+0000..U+001F, U+007F..U+009F) // but keep tab (\x09), LF (\x0A), and CR (\x0D) so line breaks are preserved. // This avoids leaving high-bit control bytes that show up as M-^@ sequences // in some terminals or when processed by CAT tools. - return String(s) - .replace(/\uFEFF/g, '') - .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''); - } catch (e) { + return ( + String(s) + .replace(/\uFEFF/g, "") + // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control characters is the entire point of this function + .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "") + ); + } catch { return String(s); } } @@ -70,12 +55,14 @@ function stripControlChars(s) { // blocks (``` or ~~~). This prevents link conversion, JSX marker conversion, // and other transformations from modifying code examples. function outsideCodeFences(fn) { - return function (s) { - if (!s || typeof s !== 'string') return fn(s); + return (s) => { + if (!s || typeof s !== "string") return fn(s); // Split on fenced code blocks (``` or ~~~). The regex captures the // complete fenced block (including opening/closing fences) so that // odd-numbered parts are code blocks and even-numbered parts are prose. - const parts = s.split(/(^`{3,}[^\n]*\n[\s\S]*?^`{3,}\s*$|^~{3,}[^\n]*\n[\s\S]*?^~{3,}\s*$)/m); + const parts = s.split( + /(^`{3,}[^\n]*\n[\s\S]*?^`{3,}\s*$|^~{3,}[^\n]*\n[\s\S]*?^~{3,}\s*$)/m + ); for (let i = 0; i < parts.length; i++) { if (i % 2 === 0) { // Outside code fence – apply the transformation @@ -83,128 +70,74 @@ function outsideCodeFences(fn) { } // Odd indices are fenced code blocks – leave them untouched } - return parts.join(''); + return parts.join(""); }; } -// Annotate JSX component occurrences inside raw MDX/markdown strings so that -// stringy prop values and simple children are included in the exported -// source text (translators need to see prop text even when it's inside an -// attribute). This works on plain strings and is intentionally conservative — -// it only tries to extract simple quoted/templated prop values. -function annotateJsxPropsAndChildren(text) { - if (!text || typeof text !== 'string') return text; - - // regex to capture simple prop string forms: "..." or '...' or `{`...`}` or {"..."} - const propStringRe = /([a-zA-Z0-9_:-]+)=?(?:"([^"]*)"|'([^']*)'|\{`([^`]*)`\}|\{\s*"([^"]*)"\s*\}|\{\s*'([^']*)'\s*\})/g; - - // 1) handle self-closing tags: -> append annotation after tag - text = text.replace(/<([A-Z][\w]*)\b([^>]*)\/>/g, (m, name, propsPart) => { - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m} (${vals.join(', ')})`; - return m; - }); - - // 2) handle open tags with attributes: -> inject annotation immediately after the opening tag - text = text.replace(/<([A-Z][\w]*)\b([^>]*)>/g, (m, name, propsPart) => { - // skip closing tags which also match pattern (they start with { - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m} (${vals.join(', ')})`; - return m; - }); - // open marker: (jsx:Name prop="x") -> append annotation after marker - text = text.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)/g, (m, name, propsPart) => { - // skip closing markers which look like (/jsx:Name) - if (/^\(\/jsx:/.test(m)) return m; - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m}${vals.length ? ' (' + vals.join(', ') + ')' : ''}`; - return m; - }); - return text; -} - // Convert angle-bracket JSX/MDX to a robust marker form that begins with // `(jsx:` so CAT tools like Swordfish won't treat tags as HTML and drop the // component name. Examples: //
    -> (jsx:Figure img="x" caption="y"/) // child -> (jsx:Comp prop="v")child(/jsx:Comp) function angleToMarker(source) { - if (!source || typeof source !== 'string') return source; + if (!source || typeof source !== "string") return source; // Robust pass: convert tags that include a children={...} prop where the // prop value may contain nested braces or newlines. Regex alone can fail // on nested braces, so scan for balanced braces and replace each occurrence. source = (function scanChildrenProps(s) { - let out = ''; + let out = ""; let idx = 0; while (true) { const m = s.slice(idx).match(/<([A-Z][\w-]*)\b[^>]*?\bchildren=\{/); - if (!m) { out += s.slice(idx); break; } + if (!m) { + out += s.slice(idx); + break; + } const matchIndex = idx + m.index; out += s.slice(idx, matchIndex); const tagStart = matchIndex; // find position of '{' that starts the children value - const bracePos = s.indexOf('{', tagStart + m[0].length - 1); - if (bracePos === -1) { out += s.slice(matchIndex); break; } + const bracePos = s.indexOf("{", tagStart + m[0].length - 1); + if (bracePos === -1) { + out += s.slice(matchIndex); + break; + } // scan for matching closing '}' with nesting let depth = 0; let j = bracePos; for (; j < s.length; j++) { const ch = s[j]; - if (ch === '{') depth++; - else if (ch === '}') { + if (ch === "{") depth++; + else if (ch === "}") { depth--; - if (depth === 0) { j++; break; } + if (depth === 0) { + j++; + break; + } } } - if (depth !== 0) { out += s.slice(matchIndex); break; } + if (depth !== 0) { + out += s.slice(matchIndex); + break; + } const children = s.slice(bracePos + 1, j - 1 + 1); // content inside braces // now find end of tag '>' after the children prop - const tagEnd = s.indexOf('>', j); - if (tagEnd === -1) { out += s.slice(matchIndex); break; } + const tagEnd = s.indexOf(">", j); + if (tagEnd === -1) { + out += s.slice(matchIndex); + break; + } const fullTag = s.slice(tagStart, tagEnd + 1); // remove the children={...} piece from fullTag - const withoutChildren = fullTag.replace(/\bchildren=\{[\s\S]*?\}/, '').replace(/\s+/g, ' ').trim(); - // determine if it was self-closing - const selfClosing = /\/>\s*$/.test(fullTag); - const propsStr = withoutChildren.replace(/^<[^\s]+/, '').replace(/^[\s>]+|[\s>]+$/g, '').trim(); - const p = propsStr ? ' ' + propsStr : ''; + const withoutChildren = fullTag + .replace(/\bchildren=\{[\s\S]*?\}/, "") + .replace(/\s+/g, " ") + .trim(); + const propsStr = withoutChildren + .replace(/^<[^\s]+/, "") + .replace(/^[\s>]+|[\s>]+$/g, "") + .trim(); + const p = propsStr ? ` ${propsStr}` : ""; out += `(jsx:${m[1]}${p})${children}(/jsx:${m[1]})`; idx = tagEnd + 1; } @@ -212,21 +145,27 @@ function angleToMarker(source) { })(source); // self-closing source = source.replace(/<([A-Z][\w-]*)\b([^>]*)\/>/g, (_m, name, props) => { - const p = props.trim().replace(/\s+/g, ' '); - return `(jsx:${name}${p ? ' ' + p : ''}/)`; + const p = props.trim().replace(/\s+/g, " "); + return `(jsx:${name}${p ? ` ${p}` : ""}/)`; }); // tags that pass content via a children={...} prop (no inner text) - source = source.replace(/<([A-Z][\w-]*)\b([^>]*)\bchildren=\{([\s\S]*?)\}([^>]*)\/?>/g, (_m, name, before, child, after) => { - // merge remaining props (before + after) and trim - const props = (before + ' ' + after).trim().replace(/\s+/g, ' '); - const p = props ? ' ' + props : ''; - return `(jsx:${name}${p})${child}(/jsx:${name})`; - }); + source = source.replace( + /<([A-Z][\w-]*)\b([^>]*)\bchildren=\{([\s\S]*?)\}([^>]*)\/?>/g, + (_m, name, before, child, after) => { + // merge remaining props (before + after) and trim + const props = `${before} ${after}`.trim().replace(/\s+/g, " "); + const p = props ? ` ${props}` : ""; + return `(jsx:${name}${p})${child}(/jsx:${name})`; + } + ); // paired tags (non-greedy children) - source = source.replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, (_m, name, props, children) => { - const p = props.trim().replace(/\s+/g, ' '); - return `(jsx:${name}${p ? ' ' + p : ''})${children}(/jsx:${name})`; - }); + source = source.replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + (_m, name, props, children) => { + const p = props.trim().replace(/\s+/g, " "); + return `(jsx:${name}${p ? ` ${p}` : ""})${children}(/jsx:${name})`; + } + ); return source; } @@ -239,13 +178,16 @@ function angleToMarker(source) { // backslash-escape, destroying all formatting). // --------------------------------------------------------------------------- function parseMarkdownToTinaAst(md) { - if (!md || typeof md !== 'string') { - return { type: 'root', children: [{ type: 'p', children: [{ type: 'text', text: '' }] }] }; + if (!md || typeof md !== "string") { + return { + type: "root", + children: [{ type: "p", children: [{ type: "text", text: "" }] }], + }; } // ---- inline parser ---- function parseInline(text) { - if (!text) return [{ type: 'text', text: '' }]; + if (!text) return [{ type: "text", text: "" }]; const nodes = []; let remaining = text; @@ -255,18 +197,20 @@ function parseMarkdownToTinaAst(md) { let earliestIdx = remaining.length; // Inline JSX marker (paired): (jsx:Name props)content(/jsx:Name) - const jsxInlinePairedRe = /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/; + const jsxInlinePairedRe = + /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/; const jsxInlinePairedM = jsxInlinePairedRe.exec(remaining); if (jsxInlinePairedM && jsxInlinePairedM.index < earliestIdx) { - earliest = { type: 'jsxPaired', match: jsxInlinePairedM }; + earliest = { type: "jsxPaired", match: jsxInlinePairedM }; earliestIdx = jsxInlinePairedM.index; } // Inline JSX marker (self-closing): (jsx:Name props/) - const jsxInlineSelfRe = /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/; + const jsxInlineSelfRe = + /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/; const jsxInlineSelfM = jsxInlineSelfRe.exec(remaining); if (jsxInlineSelfM && jsxInlineSelfM.index < earliestIdx) { - earliest = { type: 'jsxSelf', match: jsxInlineSelfM }; + earliest = { type: "jsxSelf", match: jsxInlineSelfM }; earliestIdx = jsxInlineSelfM.index; } @@ -274,7 +218,7 @@ function parseMarkdownToTinaAst(md) { const linkRe = /\[([^\]]*)\]\(([^)]*)\)/; const linkM = linkRe.exec(remaining); if (linkM && linkM.index < earliestIdx) { - earliest = { type: 'link', match: linkM }; + earliest = { type: "link", match: linkM }; earliestIdx = linkM.index; } @@ -282,7 +226,7 @@ function parseMarkdownToTinaAst(md) { const codeRe = /`([^`]+)`/; const codeM = codeRe.exec(remaining); if (codeM && codeM.index < earliestIdx) { - earliest = { type: 'code', match: codeM }; + earliest = { type: "code", match: codeM }; earliestIdx = codeM.index; } @@ -290,15 +234,16 @@ function parseMarkdownToTinaAst(md) { const boldRe = /\*\*([^*]+)\*\*|__([^_]+)__/; const boldM = boldRe.exec(remaining); if (boldM && boldM.index < earliestIdx) { - earliest = { type: 'bold', match: boldM }; + earliest = { type: "bold", match: boldM }; earliestIdx = boldM.index; } // Italic: *text* or _text_ (but not ** or __) - const italicRe = /(? 0) { - nodes.push({ type: 'text', text: remaining.slice(0, earliestIdx) }); + nodes.push({ type: "text", text: remaining.slice(0, earliestIdx) }); } const m = earliest.match; switch (earliest.type) { - case 'jsxPaired': - case 'jsxSelf': { + case "jsxPaired": + case "jsxSelf": { const compName = m[1]; - let rawProps = (m[2] || '').trim(); - const innerText = earliest.type === 'jsxPaired' ? (m[3] || '') : ''; + let rawProps = (m[2] || "").trim(); + const innerText = earliest.type === "jsxPaired" ? m[3] || "" : ""; // Unescape HTML entities in prop values that CAT tools may have introduced - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); // Parse simple props: key="value" or key='value' or key={value} // Also handle bare boolean props (e.g. `initcap` without =value) const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop - if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { + if ( + pm[2] === undefined && + pm[3] === undefined && + pm[4] === undefined + ) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) // that were introduced by JSON.stringify during export. - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -371,46 +336,59 @@ function parseMarkdownToTinaAst(md) { } nodes.push({ - type: 'mdxJsxTextElement', + type: "mdxJsxTextElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); break; } - case 'link': { - const linkText = m[1] || ''; - const href = m[2] || ''; - const linkChildren = linkText ? [{ type: 'text', text: linkText }] : []; - nodes.push({ type: 'a', url: href, title: null, children: linkChildren }); + case "link": { + const linkText = m[1] || ""; + const href = m[2] || ""; + const linkChildren = linkText + ? [{ type: "text", text: linkText }] + : []; + nodes.push({ + type: "a", + url: href, + title: null, + children: linkChildren, + }); break; } - case 'code': - nodes.push({ type: 'text', text: m[1], code: true }); + case "code": + nodes.push({ type: "text", text: m[1], code: true }); break; - case 'bold': - nodes.push({ type: 'text', text: m[1] || m[2], bold: true }); + case "bold": + nodes.push({ type: "text", text: m[1] || m[2], bold: true }); break; - case 'italic': - nodes.push({ type: 'text', text: m[1] || m[2], italic: true }); + case "italic": + nodes.push({ type: "text", text: m[1] || m[2], italic: true }); break; - case 'strikethrough': - nodes.push({ type: 'text', text: m[1], strikethrough: true }); + case "strikethrough": + nodes.push({ type: "text", text: m[1], strikethrough: true }); break; - case 'image': { - const imgAlt = m[1] || ''; - const imgSrc = m[2] || ''; - nodes.push({ type: 'img', url: imgSrc, caption: imgAlt || null, alt: imgAlt || '', children: [{ type: 'text', text: '' }] }); + case "image": { + const imgAlt = m[1] || ""; + const imgSrc = m[2] || ""; + nodes.push({ + type: "img", + url: imgSrc, + caption: imgAlt || null, + alt: imgAlt || "", + children: [{ type: "text", text: "" }], + }); break; } } remaining = remaining.slice(earliestIdx + m[0].length); } - return nodes.length ? nodes : [{ type: 'text', text: '' }]; + return nodes.length ? nodes : [{ type: "text", text: "" }]; } // ---- block parser ---- - const lines = md.replace(/\r\n?/g, '\n').split('\n'); + const lines = md.replace(/\r\n?/g, "\n").split("\n"); const rootChildren = []; let i = 0; @@ -420,7 +398,7 @@ function parseMarkdownToTinaAst(md) { function consumeList(startIdx, ordered, sourceLines) { const src = sourceLines || lines; const items = []; - const marker = ordered ? /^(\d+)\.\s+(.*)$/ : /^[\*\-\+]\s+(.*)$/; + const marker = ordered ? /^(\d+)\.\s+(.*)$/ : /^[*\-+]\s+(.*)$/; let idx = startIdx; while (idx < src.length) { const line = src[idx]; @@ -428,20 +406,22 @@ function parseMarkdownToTinaAst(md) { if (!m) break; const content = ordered ? m[2] : m[1]; const currentItem = { - type: 'li', - children: [{ type: 'lic', children: parseInline(content) }] + type: "li", + children: [{ type: "lic", children: parseInline(content) }], }; items.push(currentItem); idx++; // Absorb continuation lines (indented or non-blank, non-block-start) while (idx < src.length) { const next = src[idx]; - if (next === '') break; + if (next === "") break; if (marker.test(next)) break; // next list item at same level // Detect indented nested list (2+ spaces followed by a list marker) const nestedOlMatch = next.match(/^\s{2,}(\d+)\.\s+(.*)$/); - const nestedUlMatch = !nestedOlMatch ? next.match(/^\s{2,}[\*\-\+]\s+(.*)$/) : null; + const nestedUlMatch = !nestedOlMatch + ? next.match(/^\s{2,}[*\-+]\s+(.*)$/) + : null; if (nestedOlMatch || nestedUlMatch) { // Gather all indented lines for the nested list, then strip // their leading whitespace and parse recursively. @@ -449,7 +429,7 @@ function parseMarkdownToTinaAst(md) { const baseIndent = next.match(/^(\s+)/)[1].length; while (idx < src.length) { const nl = src[idx]; - if (nl === '') break; + if (nl === "") break; const indentMatch = nl.match(/^(\s+)/); if (!indentMatch || indentMatch[1].length < baseIndent) break; nestedLines.push(nl.slice(baseIndent)); @@ -468,26 +448,29 @@ function parseMarkdownToTinaAst(md) { // Continuation of previous item – append to last lic's text const lastLic = currentItem.children[0]; const lastChild = lastLic.children[lastLic.children.length - 1]; - if (lastChild && lastChild.type === 'text') { - lastChild.text += '\n' + next.replace(/^\s+/, ''); + if (lastChild && lastChild.type === "text") { + lastChild.text += `\n${next.replace(/^\s+/, "")}`; } idx++; } } - return [{ type: ordered ? 'ol' : 'ul', children: items }, idx]; + return [{ type: ordered ? "ol" : "ul", children: items }, idx]; } while (i < lines.length) { const line = lines[i]; // Blank line – skip - if (line.trim() === '') { i++; continue; } + if (line.trim() === "") { + i++; + continue; + } // Fenced code block: ``` or ~~~ const fenceMatch = line.match(/^(`{3,}|~{3,})\s*(\S*)\s*$/); if (fenceMatch) { const fence = fenceMatch[1]; - const lang = fenceMatch[2] || ''; + const lang = fenceMatch[2] || ""; const codeLines = []; i++; while (i < lines.length && !lines[i].startsWith(fence)) { @@ -495,15 +478,15 @@ function parseMarkdownToTinaAst(md) { i++; } if (i < lines.length) i++; // skip closing fence - const value = codeLines.join('\n'); + const value = codeLines.join("\n"); rootChildren.push({ - type: 'code_block', + type: "code_block", lang: lang || undefined, value, - children: codeLines.map(cl => ({ - type: 'code_line', - children: [{ text: cl }] - })) + children: codeLines.map((cl) => ({ + type: "code_line", + children: [{ text: cl }], + })), }); continue; } @@ -513,8 +496,8 @@ function parseMarkdownToTinaAst(md) { if (headingMatch) { const depth = headingMatch[1].length; rootChildren.push({ - type: 'h' + depth, - children: parseInline(headingMatch[2]) + type: `h${depth}`, + children: parseInline(headingMatch[2]), }); i++; continue; @@ -522,13 +505,13 @@ function parseMarkdownToTinaAst(md) { // Horizontal rule: ---, ***, ___ if (/^(---|\*\*\*|___)\s*$/.test(line)) { - rootChildren.push({ type: 'hr', children: [{ type: 'text', text: '' }] }); + rootChildren.push({ type: "hr", children: [{ type: "text", text: "" }] }); i++; continue; } // Unordered list item: * , - , + - if (/^[\*\-\+]\s+/.test(line)) { + if (/^[*\-+]\s+/.test(line)) { const [listNode, nextIdx] = consumeList(i, false); rootChildren.push(listNode); i = nextIdx; @@ -547,24 +530,24 @@ function parseMarkdownToTinaAst(md) { if (/^>\s?/.test(line)) { const bqLines = []; while (i < lines.length && /^>\s?/.test(lines[i])) { - bqLines.push(lines[i].replace(/^>\s?/, '')); + bqLines.push(lines[i].replace(/^>\s?/, "")); i++; } // Recursively parse blockquote content - const inner = parseMarkdownToTinaAst(bqLines.join('\n')); + const inner = parseMarkdownToTinaAst(bqLines.join("\n")); // Tina expects blockquote children to be inline (text, a, etc.), // not block-level (p). Unwrap any p nodes produced by the recursive parse. const bqChildren = []; - for (const child of (inner.children || [])) { - if (child.type === 'p' && child.children) { + for (const child of inner.children || []) { + if (child.type === "p" && child.children) { bqChildren.push(...child.children); } else { bqChildren.push(child); } } rootChildren.push({ - type: 'blockquote', - children: bqChildren.length ? bqChildren : [{ type: 'text', text: '' }] + type: "blockquote", + children: bqChildren.length ? bqChildren : [{ type: "text", text: "" }], }); continue; } @@ -573,45 +556,64 @@ function parseMarkdownToTinaAst(md) { // or self-closing: (jsx:Name props/) // Detect on the current line and produce a proper mdxJsxFlowElement node. // Supports both single-line and multi-line paired elements. - const jsxPairedRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)$/; - const jsxSelfRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)$/; + const jsxPairedRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)$/; + const jsxSelfRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)$/; const jsxPairedM = jsxPairedRe.exec(line); const jsxSelfM = !jsxPairedM ? jsxSelfRe.exec(line) : null; // Also detect multi-line paired JSX: opening tag on this line, closing // on a subsequent line. (jsx:Name props) ... lines ... (/jsx:Name) - const jsxOpenRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)(.*)$/; - const jsxOpenM = (!jsxPairedM && !jsxSelfM) ? jsxOpenRe.exec(line) : null; + const jsxOpenRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)(.*)$/; + const jsxOpenM = !jsxPairedM && !jsxSelfM ? jsxOpenRe.exec(line) : null; if (jsxPairedM || jsxSelfM) { // Single-line paired or self-closing const m = jsxPairedM || jsxSelfM; const compName = m[1]; - let rawProps = (m[2] || '').trim(); - const innerText = jsxPairedM ? (m[3] || '') : ''; + let rawProps = (m[2] || "").trim(); + const innerText = jsxPairedM ? m[3] || "" : ""; - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); // Parse simple props: key="value" or key={value} or bare boolean const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; // Try to parse JSON-like values (arrays, bools, numbers) - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -622,10 +624,10 @@ function parseMarkdownToTinaAst(md) { } rootChildren.push({ - type: 'mdxJsxFlowElement', + type: "mdxJsxFlowElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); i++; continue; @@ -635,8 +637,8 @@ function parseMarkdownToTinaAst(md) { // Multi-line paired JSX: opening tag on this line, gather content // until we find the matching closing tag (/jsx:Name). const compName = jsxOpenM[1]; - let rawProps = (jsxOpenM[2] || '').trim(); - const firstLineContent = jsxOpenM[3] || ''; + let rawProps = (jsxOpenM[2] || "").trim(); + const firstLineContent = jsxOpenM[3] || ""; const closingTag = `(/jsx:${compName})`; const contentLines = []; if (firstLineContent) contentLines.push(firstLineContent); @@ -654,28 +656,44 @@ function parseMarkdownToTinaAst(md) { contentLines.push(cur); i++; } - const innerText = contentLines.join('\n'); + const innerText = contentLines.join("\n"); - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -685,10 +703,10 @@ function parseMarkdownToTinaAst(md) { } rootChildren.push({ - type: 'mdxJsxFlowElement', + type: "mdxJsxFlowElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); continue; } @@ -697,11 +715,11 @@ function parseMarkdownToTinaAst(md) { const paraLines = []; while (i < lines.length) { const cur = lines[i]; - if (cur.trim() === '') break; + if (cur.trim() === "") break; if (/^#{1,6}\s/.test(cur)) break; if (/^(`{3,}|~{3,})/.test(cur)) break; if (/^(---|\*\*\*|___)\s*$/.test(cur)) break; - if (/^[\*\-\+]\s+/.test(cur)) break; + if (/^[*\-+]\s+/.test(cur)) break; if (/^\d+\.\s+/.test(cur)) break; if (/^>\s/.test(cur)) break; if (/^\(jsx:[A-Z]/.test(cur)) break; @@ -712,321 +730,389 @@ function parseMarkdownToTinaAst(md) { // pattern) advance past the current line to prevent an infinite loop. if (paraLines.length === 0) { rootChildren.push({ - type: 'p', - children: parseInline(lines[i] || '') + type: "p", + children: parseInline(lines[i] || ""), }); i++; } else { rootChildren.push({ - type: 'p', - children: parseInline(paraLines.join('\n')) + type: "p", + children: parseInline(paraLines.join("\n")), }); } } return { - type: 'root', + type: "root", children: rootChildren.length ? rootChildren - : [{ type: 'p', children: [{ type: 'text', text: '' }] }] + : [{ type: "p", children: [{ type: "text", text: "" }] }], }; } -// Convert marker form back to angle-bracket JSX/MDX -function markerToAngle(source) { - if (!source || typeof source !== 'string') return source; - // paired tags first - source = source.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, (_m, name, props, children) => { - const p = props.trim(); - return `<${name}${p ? ' ' + p : ''}>${children}`; - }); - // self-closing marker - source = source.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, (_m, name, props) => { - const p = props.trim(); - return `<${name}${p ? ' ' + p : ''} />`; - }); - return source; -} - // Read an XML element while treating XLIFF elements as newline characters. function readElementTextPreservingLineBreaks(el) { - if (!el) return ''; - let s = ''; + if (!el) return ""; + let s = ""; const nodes = Array.from(el.childNodes || []); for (const node of nodes) { if (node.nodeType === 3) { - s += node.nodeValue || ''; + s += node.nodeValue || ""; } else if (node.nodeType === 1) { - const tag = (node.tagName || '').toLowerCase(); - if (tag === 'lb') s += '\n'; - else s += node.textContent || ''; + const tag = (node.tagName || "").toLowerCase(); + if (tag === "lb") s += "\n"; + else s += node.textContent || ""; } } return s; } function extractFrontmatter(text) { - if (!text) return { metadata: {}, body: text || '' }; + if (!text) return { metadata: {}, body: text || "" }; const m = String(text).match(/^---\s*\n([\s\S]*?)\n---\s*\n?/); if (!m) return { metadata: {}, body: text }; const fmRaw = m[1]; const body = text.slice(m[0].length); const metadata = {}; - fmRaw.split(/\n/).forEach((line) => { - const kv = line.match(/^([A-Za-z0-9_\-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/); + for (const line of fmRaw.split(/\n/)) { + const kv = line.match( + /^([A-Za-z0-9_-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/ + ); if (kv) { - metadata[kv[1]] = (kv[2] || kv[3] || (kv[4] || '')).trim(); + metadata[kv[1]] = (kv[2] || kv[3] || kv[4] || "").trim(); } - }); + } return { metadata, body }; } function serializeRichTextToMarkdown(node) { - if (!node) return ''; - if (typeof node === 'string') return node; - if (Array.isArray(node)) return node.map(serializeRichTextToMarkdown).join(''); + if (!node) return ""; + if (typeof node === "string") return node; + if (Array.isArray(node)) + return node.map(serializeRichTextToMarkdown).join(""); // Tina AST sometimes uses typeless leaf objects like { text: "..." } // (e.g. inside code_line children). Handle them before the switch. if (!node.type && (node.text != null || node.value != null)) { - return String(node.text ?? node.value ?? ''); + return String(node.text ?? node.value ?? ""); } const type = node.type; switch (type) { - case 'root': - return (node.children || []).map(serializeRichTextToMarkdown).join('\n\n'); - case 'p': - return (node.children || []).map(serializeRichTextToMarkdown).join(''); - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': { + case "root": + return (node.children || []) + .map(serializeRichTextToMarkdown) + .join("\n\n"); + case "p": + return (node.children || []).map(serializeRichTextToMarkdown).join(""); + case "h1": + case "h2": + case "h3": + case "h4": + case "h5": + case "h6": { const depth = parseInt(type.slice(1), 10) || 1; - const prefix = '#'.repeat(Math.max(1, Math.min(6, depth))); - const content = (node.children || []).map(serializeRichTextToMarkdown).join(''); + const prefix = "#".repeat(Math.max(1, Math.min(6, depth))); + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join(""); return `${prefix} ${content}`; } - case 'heading': { + case "heading": { const depth = node.depth || 1; - const prefix = '#'.repeat(Math.max(1, Math.min(6, depth))); - const content = (node.children || []).map(serializeRichTextToMarkdown).join(''); + const prefix = "#".repeat(Math.max(1, Math.min(6, depth))); + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join(""); return `${prefix} ${content}`; } - case 'code': - case 'code_block': { - const lang = node.lang || ''; + case "code": + case "code_block": { + const lang = node.lang || ""; // Prefer the flat `value` string when available; otherwise join // code_line children with newlines to reconstruct the block content. - const content = node.value - || (node.children || []).map(c => serializeRichTextToMarkdown(c)).join('\n'); - return '\n\n```' + (lang ? ' ' + lang : '') + '\n' + content + '\n```\n\n'; + const content = + node.value || + (node.children || []) + .map((c) => serializeRichTextToMarkdown(c)) + .join("\n"); + return `\n\n\`\`\`${lang ? ` ${lang}` : ""}\n${content}\n\`\`\`\n\n`; } - case 'code_line': { + case "code_line": { // Individual line inside a code_block – return its raw text content. - return (node.children || []).map(serializeRichTextToMarkdown).join(''); + return (node.children || []).map(serializeRichTextToMarkdown).join(""); } - case 'hr': - return '\n\n---\n\n'; - case 'break': + case "hr": + return "\n\n---\n\n"; + case "break": // represent an explicit hard line-break within a paragraph - return '\n'; - case 'blockquote': { - const content = (node.children || []).map(serializeRichTextToMarkdown).join('\n'); - return content.split('\n').map(line => `> ${line}`).join('\n'); + return "\n"; + case "blockquote": { + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join("\n"); + return content + .split("\n") + .map((line) => `> ${line}`) + .join("\n"); } - case 'text': { - let txt = node.text || node.value || ''; + case "text": { + let txt = node.text || node.value || ""; if (node.code) txt = `\`${txt}\``; if (node.bold) txt = `**${txt}**`; if (node.italic) txt = `_${txt}_`; if (node.strikethrough) txt = `~~${txt}~~`; return txt; } - case 'inlineCode': - return `\`${(node.value || node.text || node.literal || '')}\``; - case 'ol': { - const indent = node._indent || ''; - return (node.children || []).map((li, idx) => { - // Separate lic (inline content) from nested list children - const licParts = []; - const nestedLists = []; - for (const child of (li.children || [])) { - if (child.type === 'ol' || child.type === 'ul') { - nestedLists.push(child); - } else { - licParts.push(child); + case "inlineCode": + return `\`${node.value || node.text || node.literal || ""}\``; + case "ol": { + const indent = node._indent || ""; + return (node.children || []) + .map((li, idx) => { + // Separate lic (inline content) from nested list children + const licParts = []; + const nestedLists = []; + for (const child of li.children || []) { + if (child.type === "ol" || child.type === "ul") { + nestedLists.push(child); + } else { + licParts.push(child); + } } - } - const content = licParts.map(serializeRichTextToMarkdown).join(''); - let result = `${indent}${idx + 1}. ${content}`; - // Render nested lists indented under the parent item - for (const nested of nestedLists) { - // 3-char indent to align under ordered list content ("1. ") - const nestedCopy = Object.assign({}, nested, { _indent: indent + ' ' }); - result += '\n' + serializeRichTextToMarkdown(nestedCopy); - } - return result; - }).join('\n'); + const content = licParts.map(serializeRichTextToMarkdown).join(""); + let result = `${indent}${idx + 1}. ${content}`; + // Render nested lists indented under the parent item + for (const nested of nestedLists) { + // 3-char indent to align under ordered list content ("1. ") + const nestedCopy = Object.assign({}, nested, { + _indent: `${indent} `, + }); + result += `\n${serializeRichTextToMarkdown(nestedCopy)}`; + } + return result; + }) + .join("\n"); } - case 'ul': { - const indent = node._indent || ''; - return (node.children || []).map((li) => { - const licParts = []; - const nestedLists = []; - for (const child of (li.children || [])) { - if (child.type === 'ol' || child.type === 'ul') { - nestedLists.push(child); - } else { - licParts.push(child); + case "ul": { + const indent = node._indent || ""; + return (node.children || []) + .map((li) => { + const licParts = []; + const nestedLists = []; + for (const child of li.children || []) { + if (child.type === "ol" || child.type === "ul") { + nestedLists.push(child); + } else { + licParts.push(child); + } } - } - const content = licParts.map(serializeRichTextToMarkdown).join(''); - let result = `${indent}- ${content}`; - for (const nested of nestedLists) { - const nestedCopy = Object.assign({}, nested, { _indent: indent + ' ' }); - result += '\n' + serializeRichTextToMarkdown(nestedCopy); - } - return result; - }).join('\n'); + const content = licParts.map(serializeRichTextToMarkdown).join(""); + let result = `${indent}- ${content}`; + for (const nested of nestedLists) { + const nestedCopy = Object.assign({}, nested, { + _indent: `${indent} `, + }); + result += `\n${serializeRichTextToMarkdown(nestedCopy)}`; + } + return result; + }) + .join("\n"); } - case 'li': - case 'lic': - return (node.children || []).map(serializeRichTextToMarkdown).join(''); - case 'link': - case 'a': { - const text = (node.children || []).map(serializeRichTextToMarkdown).join('') || node.title || ''; - const href = node.url || node.href || ''; + case "li": + case "lic": + return (node.children || []).map(serializeRichTextToMarkdown).join(""); + case "link": + case "a": { + const text = + (node.children || []).map(serializeRichTextToMarkdown).join("") || + node.title || + ""; + const href = node.url || node.href || ""; return href ? `[${text}](${href})` : text; } - case 'img': - case 'image': { - const alt = node.alt || node.title || ''; - const src = node.url || node.src || ''; + case "img": + case "image": { + const alt = node.alt || node.title || ""; + const src = node.url || node.src || ""; return `![${alt}](${src})`; } - case 'jsx': - case 'mdxJsxFlowElement': - case 'mdxJsxTextElement': { - // Emit marker-form components (jsx:Name ...) so CAT tools see them - const propsToString = (pairs) => { - if (!pairs || !pairs.length) return ''; - return pairs.map(attr => { - const name = attr.name || attr.key || ''; - const value = attr.hasOwnProperty('value') ? attr.value : attr.val || attr.v; - if (!name) return ''; + case "jsx": + case "mdxJsxFlowElement": + case "mdxJsxTextElement": { + // Emit marker-form components (jsx:Name ...) so CAT tools see them + const propsToString = (pairs) => { + if (!pairs?.length) return ""; + return pairs + .map((attr) => { + const name = attr.name || attr.key || ""; + const value = Object.hasOwn(attr, "value") + ? attr.value + : attr.val || attr.v; + if (!name) return ""; if (value === true || value === undefined) return name; - if (typeof value === 'string') return `${name}=${JSON.stringify(value)}`; + if (typeof value === "string") + return `${name}=${JSON.stringify(value)}`; try { return `${name}={${JSON.stringify(value)}}`; - } catch (e) { + } catch { return `${name}=${JSON.stringify(String(value))}`; } - }).filter(Boolean).join(' '); - }; - - // Determine children content (prefer explicit children array). - // If not present, attempt a deep extraction from nested shapes - // (GraphQL/Tina may return varying AST shapes). - const deepSerialize = (obj) => { - if (obj === null || obj === undefined) return ''; - if (typeof obj === 'string') return obj; - if (Array.isArray(obj)) return obj.map(deepSerialize).join(''); - if (typeof obj === 'object') { - // If this looks like a node, let serializer handle it - if (obj.type) return serializeRichTextToMarkdown(obj); - // common text fields - if (obj.value || obj.text || obj.literal) return String(obj.value || obj.text || obj.literal); - // children-like containers - if (obj.children) return deepSerialize(obj.children); - if (obj._values) return deepSerialize(obj._values); - // otherwise inspect own properties - const parts = []; - for (const k of Object.keys(obj)) { - try { - parts.push(deepSerialize(obj[k])); - } catch (e) {} - } - return parts.join(''); - } - return String(obj); - }; - - let children = ''; - if (node.children && node.children.length) { - children = node.children.map(serializeRichTextToMarkdown).join(''); - } else if (node.attributes && node.attributes.length) { - const childAttr = node.attributes.find(a => a.name === 'children' && (a.value !== undefined && a.value !== null)); - if (childAttr) { - children = typeof childAttr.value === 'string' ? childAttr.value : deepSerialize(childAttr.value); - } - } else if (node.props && node.props.children) { - children = typeof node.props.children === 'string' ? node.props.children : deepSerialize(node.props.children); - } else if (node._values && node._values.children) { - children = typeof node._values.children === 'string' ? node._values.children : deepSerialize(node._values.children); - } else { - // final attempt: scan the whole node for nested text - children = deepSerialize(node); - } + }) + .filter(Boolean) + .join(" "); + }; - // If children derived from node.children was empty, prefer any - // explicit `props.children` or `_values.children` which may contain - // meaningful content (some AST shapes put the real child inside props). - if ((!children || String(children).trim() === '')) { - if (node.props && node.props.children) { - children = typeof node.props.children === 'string' ? node.props.children : deepSerialize(node.props.children); - } else if (node._values && node._values.children) { - children = typeof node._values.children === 'string' ? node._values.children : deepSerialize(node._values.children); + // Determine children content (prefer explicit children array). + // If not present, attempt a deep extraction from nested shapes + // (GraphQL/Tina may return varying AST shapes). + const deepSerialize = (obj) => { + if (obj === null || obj === undefined) return ""; + if (typeof obj === "string") return obj; + if (Array.isArray(obj)) return obj.map(deepSerialize).join(""); + if (typeof obj === "object") { + // If this looks like a node, let serializer handle it + if (obj.type) return serializeRichTextToMarkdown(obj); + // common text fields + if (obj.value || obj.text || obj.literal) + return String(obj.value || obj.text || obj.literal); + // children-like containers + if (obj.children) return deepSerialize(obj.children); + if (obj._values) return deepSerialize(obj._values); + // otherwise inspect own properties + const parts = []; + for (const k of Object.keys(obj)) { + try { + parts.push(deepSerialize(obj[k])); + } catch {} } + return parts.join(""); } + return String(obj); + }; - // collect attribute pairs from various node shapes - let attrPairs = []; - if (node.attributes && Array.isArray(node.attributes) && node.attributes.length) { - attrPairs = node.attributes - .filter(a => a && a.name && String(a.name).toLowerCase() !== 'children') - .map(a => ({ name: a.name, value: a.value })); - } else if (node.props && typeof node.props === 'object') { - attrPairs = Object.keys(node.props).filter(k => k !== 'children').map(k => ({ name: k, value: node.props[k] })); - } else if (node._values && typeof node._values === 'object') { - attrPairs = Object.keys(node._values).filter(k => k !== 'children').map(k => ({ name: k, value: node._values[k] })); + let children = ""; + if (node.children?.length) { + children = node.children.map(serializeRichTextToMarkdown).join(""); + } else if (node.attributes?.length) { + const childAttr = node.attributes.find( + (a) => + a.name === "children" && a.value !== undefined && a.value !== null + ); + if (childAttr) { + children = + typeof childAttr.value === "string" + ? childAttr.value + : deepSerialize(childAttr.value); } - const props = propsToString(attrPairs); - const p = props ? ' ' + props : ''; - if (children && children.length) { - return `(jsx:${node.name}${p})${children}(/jsx:${node.name})`; - } - // Prefer exposing a primary prop value (common keys like title, - // summary or caption) as the visible child text when no children - // are present. This gives translators the actual text they need - // rather than a machine-readable parenthetical list. - const preferred = ['title', 'summary', 'caption', 'alt', 'label', 'termKey', 'text']; - let primary = null; - for (const k of preferred) { - const found = (attrPairs || []).find(a => a && String(a.name) === k && typeof a.value === 'string' && String(a.value).trim()); - if (found) { primary = String(found.value); break; } - } - if (primary) { - return `(jsx:${node.name}${p})${primary}(/jsx:${node.name})`; + } else if (node.props?.children) { + children = + typeof node.props.children === "string" + ? node.props.children + : deepSerialize(node.props.children); + } else if (node._values?.children) { + children = + typeof node._values.children === "string" + ? node._values.children + : deepSerialize(node._values.children); + } else { + // final attempt: scan the whole node for nested text + children = deepSerialize(node); + } + + // If children derived from node.children was empty, prefer any + // explicit `props.children` or `_values.children` which may contain + // meaningful content (some AST shapes put the real child inside props). + if (!children || String(children).trim() === "") { + if (node.props?.children) { + children = + typeof node.props.children === "string" + ? node.props.children + : deepSerialize(node.props.children); + } else if (node._values?.children) { + children = + typeof node._values.children === "string" + ? node._values.children + : deepSerialize(node._values.children); } - // Fallback: expose a compact parenthetical annotation containing - // simple prop values so translators can still see translatable - // strings when no obvious primary prop exists. - const annParts = (attrPairs || []).map(a => { - const v = a && a.value; - if (v === undefined || v === null) return ''; - if (typeof v === 'string') return `${a.name}:${v}`; - try { return `${a.name}:${JSON.stringify(v)}`; } catch (e) { return `${a.name}:${String(v)}`; } - }).filter(Boolean); - if (annParts.length) { - const ann = `(${annParts.join(', ')})`; - return `(jsx:${node.name}${p})${ann}(/jsx:${node.name})`; + } + + // collect attribute pairs from various node shapes + let attrPairs = []; + if ( + node.attributes && + Array.isArray(node.attributes) && + node.attributes.length + ) { + attrPairs = node.attributes + .filter((a) => a?.name && String(a.name).toLowerCase() !== "children") + .map((a) => ({ name: a.name, value: a.value })); + } else if (node.props && typeof node.props === "object") { + attrPairs = Object.keys(node.props) + .filter((k) => k !== "children") + .map((k) => ({ name: k, value: node.props[k] })); + } else if (node._values && typeof node._values === "object") { + attrPairs = Object.keys(node._values) + .filter((k) => k !== "children") + .map((k) => ({ name: k, value: node._values[k] })); + } + const props = propsToString(attrPairs); + const p = props ? ` ${props}` : ""; + if (children?.length) { + return `(jsx:${node.name}${p})${children}(/jsx:${node.name})`; + } + // Prefer exposing a primary prop value (common keys like title, + // summary or caption) as the visible child text when no children + // are present. This gives translators the actual text they need + // rather than a machine-readable parenthetical list. + const preferred = [ + "title", + "summary", + "caption", + "alt", + "label", + "termKey", + "text", + ]; + let primary = null; + for (const k of preferred) { + const found = (attrPairs || []).find( + (a) => + a && + String(a.name) === k && + typeof a.value === "string" && + String(a.value).trim() + ); + if (found) { + primary = String(found.value); + break; } - return `(jsx:${node.name}${p}/)`; + } + if (primary) { + return `(jsx:${node.name}${p})${primary}(/jsx:${node.name})`; + } + // Fallback: expose a compact parenthetical annotation containing + // simple prop values so translators can still see translatable + // strings when no obvious primary prop exists. + const annParts = (attrPairs || []) + .map((a) => { + const v = a?.value; + if (v === undefined || v === null) return ""; + if (typeof v === "string") return `${a.name}:${v}`; + try { + return `${a.name}:${JSON.stringify(v)}`; + } catch { + return `${a.name}:${String(v)}`; + } + }) + .filter(Boolean); + if (annParts.length) { + const ann = `(${annParts.join(", ")})`; + return `(jsx:${node.name}${p})${ann}(/jsx:${node.name})`; + } + return `(jsx:${node.name}${p}/)`; } default: // Fallback: serialize children - return (node.children || []).map(serializeRichTextToMarkdown).join(''); + return (node.children || []).map(serializeRichTextToMarkdown).join(""); } } @@ -1034,25 +1120,28 @@ function serializeRichTextToMarkdown(node) { // links so hrefs are preserved in XLIFF text exports. This is a best-effort // conversion for stringy bodies that may contain raw HTML. function htmlAnchorsToMarkdown(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; try { // Unescape common < > entities so regex can match tags - let work = String(s).replace(/</g, '<').replace(/>/g, '>'); + let work = String(s).replace(/</g, "<").replace(/>/g, ">"); // Replace anchor tags with Markdown links; capture href in single/double/no-quotes - work = work.replace(/]*href=(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi, (m, g1, g2, g3, inner) => { - const href = g1 || g2 || g3 || ''; - // strip any nested tags inside link text - const innerStr = inner.replace(/<[^>]+>/g, '').trim(); - // If inner already contains a markdown-style link like [text](url), - // avoid producing nested markdown. Prefer an inline form: "text ". - const mdMatch = innerStr.match(/\[([^\]]+)\]\(([^)]+)\)/); - if (mdMatch) { - const display = mdMatch[1] || innerStr; - const u = href || (mdMatch[2] || '').trim(); - return u ? `${display} <${u}>` : display; - } - return href ? `[${innerStr}](${href})` : innerStr; - }); + work = work.replace( + /]*href=(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi, + (_m, g1, g2, g3, inner) => { + const href = g1 || g2 || g3 || ""; + // strip any nested tags inside link text + const innerStr = inner.replace(/<[^>]+>/g, "").trim(); + // If inner already contains a markdown-style link like [text](url), + // avoid producing nested markdown. Prefer an inline form: "text ". + const mdMatch = innerStr.match(/\[([^\]]+)\]\(([^)]+)\)/); + if (mdMatch) { + const display = mdMatch[1] || innerStr; + const u = href || (mdMatch[2] || "").trim(); + return u ? `${display} <${u}>` : display; + } + return href ? `[${innerStr}](${href})` : innerStr; + } + ); // Convert bare URLs into Markdown links: https://example.com -> [example.com](https://example.com) // Avoid autolinking URLs that are already part of a markdown link or // are inside angle brackets/parentheses/brackets to prevent nested links. @@ -1078,14 +1167,18 @@ function htmlAnchorsToMarkdown(s) { return s; }; work = _protect(work); - work = work.replace(/(?]+/gi, (m) => { + work = work.replace(/(?]+/gi, (m) => { try { const url = m; // use hostname or full url for link text let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } + try { + text = new URL(url).hostname; + } catch { + text = url; + } return `[${text}](${url})`; - } catch (e) { + } catch { return m; } }); @@ -1093,31 +1186,45 @@ function htmlAnchorsToMarkdown(s) { work = _protect(work); // Autolink www. and common TLDs without scheme (e.g. www.example.com or example.com) // Avoid cases already wrapped in markdown or angle brackets. - work = work.replace(/(?]+/gi, (m) => { - const url = m.startsWith('http') ? m : `https://${m}`; + work = work.replace(/(?]+/gi, (m) => { + const url = m.startsWith("http") ? m : `https://${m}`; let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } + try { + text = new URL(url).hostname; + } catch { + text = url; + } return `[${text}](${url})`; }); work = _protect(work); - work = work.replace(/(? { - // Avoid converting markdown-wrapped links or already-handled anchors - if (/^\[.*\]\(.*\)$/.test(m)) return m; - const url = m.startsWith('http') ? m : `https://${m}`; - let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } - return `[${text}](${url})`; - }); + work = work.replace( + /(? { + // Avoid converting markdown-wrapped links or already-handled anchors + if (/^\[.*\]\(.*\)$/.test(m)) return m; + const url = m.startsWith("http") ? m : `https://${m}`; + let text; + try { + text = new URL(url).hostname; + } catch { + text = url; + } + return `[${text}](${url})`; + } + ); // Restore all protected markdown links - work = work.replace(/___MDLINK_(\d+)___/g, (m, idx) => _mdLinkSlots[parseInt(idx, 10)] || m); + work = work.replace( + /___MDLINK_(\d+)___/g, + (m, idx) => _mdLinkSlots[parseInt(idx, 10)] || m + ); return work; - } catch (e) { + } catch { return s; } } function escapeRegExpFor(text) { - return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return String(text).replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Walk an AST-like object (various shapes from Tina) and gather link @@ -1126,25 +1233,37 @@ function escapeRegExpFor(text) { function gatherLinkPairsFromAst(node, out) { out = out || []; if (!node) return out; - if (typeof node === 'string') return out; + if (typeof node === "string") return out; if (Array.isArray(node)) { for (const c of node) gatherLinkPairsFromAst(c, out); return out; } - if (typeof node === 'object') { + if (typeof node === "object") { const type = node.type || node._type || node.name || node.tagName; - if (type && String(type).toLowerCase() === 'link') { - const text = (node.children || []).map(n => (typeof n === 'string' ? n : (n.text || n.value || ''))).join('') || node.title || node.text || ''; - const href = node.url || node.href || node.destination || ''; - if (text && href) out.push({ text: String(text).trim(), href: String(href).trim() }); + if (type && String(type).toLowerCase() === "link") { + const text = + (node.children || []) + .map((n) => (typeof n === "string" ? n : n.text || n.value || "")) + .join("") || + node.title || + node.text || + ""; + const href = node.url || node.href || node.destination || ""; + if (text && href) + out.push({ text: String(text).trim(), href: String(href).trim() }); } // also inspect known prop shapes that may contain links if (node.url && (node.title || node.text)) { - out.push({ text: String(node.title || node.text).trim(), href: String(node.url).trim() }); + out.push({ + text: String(node.title || node.text).trim(), + href: String(node.url).trim(), + }); } // recursively inspect properties for (const k of Object.keys(node)) { - try { gatherLinkPairsFromAst(node[k], out); } catch (e) {} + try { + gatherLinkPairsFromAst(node[k], out); + } catch {} } } return out; @@ -1155,23 +1274,23 @@ function gatherLinkPairsFromAst(node, out) { // href is already present in the conv text. function repairLinksFromAst(conv, srcNode) { try { - if (!conv || typeof conv !== 'string') return conv; + if (!conv || typeof conv !== "string") return conv; if (!srcNode) return conv; // if conv already contains an explicit url, skip repair if (/https?:\/\//.test(conv) || /`); } } return out; - } catch (e) { + } catch { return conv; } } @@ -1182,30 +1301,29 @@ function findUrlsInObject(obj) { try { const txt = JSON.stringify(obj || {}, null, 0); const re = /https?:\/\/[^"'\\\s,<>]*/gi; - const out = []; - let m; - while ((m = re.exec(txt)) !== null) { - out.push(m[0]); - } - return out; - } catch (e) { + return txt.match(re) || []; + } catch { return []; } } // Append extracted URLs to plain list items when link pairs aren't available. function appendUrlsToListItems(conv, urls) { - if (!conv || !urls || !urls.length) return conv; + if (!conv || !urls?.length) return conv; const lines = String(conv).split(/\r?\n/); let i = 0; for (let li = 0; li < lines.length && i < urls.length; li++) { const line = lines[li]; - if (/^\s*-\s+/.test(line) && !/https?:\/\//.test(line) && !/'; + if ( + /^\s*-\s+/.test(line) && + !/https?:\/\//.test(line) && + !/`; i++; } } - return lines.join('\n'); + return lines.join("\n"); } // Preserve Markdown inline links [text](url) as-is. Previously this function @@ -1223,13 +1341,16 @@ function markdownLinksToInlineUrl(s) { // markdown link using the inner URL (url1). This avoids producing // malformed or duplicated links during subsequent conversions. function normalizeNestedMarkdownLinks(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; try { - return String(s).replace(/\[\[([^\]]+)\]\(([^)]+)\)\]\(([^)]+)\)/g, (m, innerText, innerUrl, outerUrl) => { - // prefer the inner URL as it is usually the intended target - return `[${innerText}](${innerUrl})`; - }); - } catch (e) { + return String(s).replace( + /\[\[([^\]]+)\]\(([^)]+)\)\]\(([^)]+)\)/g, + (_m, innerText, innerUrl, _outerUrl) => { + // prefer the inner URL as it is usually the intended target + return `[${innerText}](${innerUrl})`; + } + ); + } catch { return s; } } @@ -1238,54 +1359,90 @@ function normalizeNestedMarkdownLinks(s) { // into explicit Markdown links so hrefs survive export. Handles both // angle-bracket JSX and marker-form `(jsx:...)` forms. function convertJsxPropLinksToMarkdown(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; let out = String(s); try { // 1) Handle marker-form paired elements: (jsx:Name props...)children(/jsx:Name) - out = out.replace(/\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, (m, name, props, children) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const text = (children && String(children).trim()) ? String(children).trim() : (String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i) || [])[1] || href; - if (href) return `[${text}](${href})`; + out = out.replace( + /\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, + (m, _name, props, children) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const text = + children && String(children).trim() + ? String(children).trim() + : (String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ) || [])[1] || href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); + ); // 2) Handle angle-bracket paired JSX: children - out = out.replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, (m, name, props, children) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const text = (children && String(children).trim()) ? String(children).trim() : (String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i) || [])[1] || href; - if (href) return `[${text}](${href})`; + out = out.replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + (m, _name, props, children) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const text = + children && String(children).trim() + ? String(children).trim() + : (String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ) || [])[1] || href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); + ); // 3) Handle self-closing marker or angle forms with href prop: (jsx:Name href="...") or - out = out.replace(/\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, (m, name, props) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const textMatch = String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - const text = (textMatch && (textMatch[1]||textMatch[2]||textMatch[3])) ? (textMatch[1]||textMatch[2]||textMatch[3]) : href; - if (href) return `[${text}](${href})`; + out = out.replace( + /\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, + (m, _name, props) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const textMatch = String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + const text = + textMatch && (textMatch[1] || textMatch[2] || textMatch[3]) + ? textMatch[1] || textMatch[2] || textMatch[3] + : href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); - out = out.replace(/<([A-Z][\w-]*)\b([^>]*)\/\>/g, (m, name, props) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); + ); + out = out.replace(/<([A-Z][\w-]*)\b([^>]*)\/>/g, (m, _name, props) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const textMatch = String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); - const text = (textMatch && (textMatch[1]||textMatch[2]||textMatch[3])) ? (textMatch[1]||textMatch[2]||textMatch[3]) : href; + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const textMatch = String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); + const text = + textMatch && (textMatch[1] || textMatch[2] || textMatch[3]) + ? textMatch[1] || textMatch[2] || textMatch[3] + : href; if (href) return `[${text}](${href})`; } return m; }); - - } catch (e) { + } catch { return s; } return out; @@ -1295,39 +1452,45 @@ export async function exportOutOfDateAsXliff(client, language) { // Fetch docs and i18n similar to scanTranslations and build units for outdated const canonicalize = (p) => { if (!p) return p; - let s = p.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); + let s = p.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); return s; }; // load all docs and translations - const docsResult = await client.queries.docConnection({ sort: 'title', first: 1000 }); + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 1000, + }); const docsEdges = docsResult.data?.docConnection?.edges || []; const sourceMap = {}; for (const edge of docsEdges) { const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; + const rel = node._sys?.relativePath || node._sys?.filename || ""; let clean = rel; - if (rel.startsWith('docs/')) clean = rel.replace(/^docs\//, ''); - if (clean.startsWith('api/')) continue; + if (rel.startsWith("docs/")) clean = rel.replace(/^docs\//, ""); + if (clean.startsWith("api/")) continue; sourceMap[canonicalize(clean)] = node; } - const i18nResult = await client.queries.i18nConnection({ sort: 'title', first: 1000 }); + const i18nResult = await client.queries.i18nConnection({ + sort: "title", + first: 1000, + }); const i18nEdges = i18nResult.data?.i18nConnection?.edges || []; const translationsMap = {}; for (const edge of i18nEdges) { const node = edge.node; - const relPath = node._sys?.relativePath || node._sys?.filename || ''; + const relPath = node._sys?.relativePath || node._sys?.filename || ""; const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); if (!m) continue; const lang = m[1]; if (lang !== language) continue; const after = m[2]; - const prefix = 'docusaurus-plugin-content-docs/current/'; + const prefix = "docusaurus-plugin-content-docs/current/"; if (!after.startsWith(prefix)) continue; - const cleanAfter = after.replace(new RegExp(`^${prefix}`), ''); + const cleanAfter = after.replace(new RegExp(`^${prefix}`), ""); const canonical = canonicalize(cleanAfter); translationsMap[canonical] = node; } @@ -1339,110 +1502,111 @@ export async function exportOutOfDateAsXliff(client, language) { if (!translationsMap[key]) continue; const tr = translationsMap[key]; // Determine lastmod dates consistent with scanTranslations rules - const srcDate = src && src.lastmod ? new Date(src.lastmod) : null; - const trDate = tr && tr.lastmod ? new Date(tr.lastmod) : null; + const srcDate = src?.lastmod ? new Date(src.lastmod) : null; + const trDate = tr?.lastmod ? new Date(tr.lastmod) : null; // Include only when source has a date and translation is missing or older const isOutOfDate = srcDate && (!trDate || trDate < srcDate); if (!isOutOfDate) continue; // Prefer raw MDX if available so exported contains original headings // and full MDX/React component contents. Strip YAML frontmatter and capture // metadata separately so it can be emitted as elements. - let sourceBody = ''; + let sourceBody = ""; let sourceMeta = {}; // Try several common places where Tina may store raw or rich content if (src.raw) { const parsed = extractFrontmatter(src.raw); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; + sourceBody = parsed.body || ""; } else if (src._raw) { const parsed = extractFrontmatter(src._raw); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; - } else if (src._values && typeof src._values === 'string') { + sourceBody = parsed.body || ""; + } else if (src._values && typeof src._values === "string") { const parsed = extractFrontmatter(src._values); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; - } else if (src._values && typeof src._values === 'object') { - // Support several shapes: _values.body may be a string or an AST-like - // object. Prefer serializing AST shapes to Markdown when possible. - if (src._values.body && typeof src._values.body === 'object') { - try { sourceBody = serializeRichTextToMarkdown(src._values.body); } catch (e) { sourceBody = JSON.stringify(src._values.body); } - } else if (src._values.body && typeof src._values.body === 'string') { - sourceBody = src._values.body; - } else if (src._values.children) { - try { sourceBody = serializeRichTextToMarkdown(src._values); } catch (e) { sourceBody = JSON.stringify(src._values); } - } else { - try { sourceBody = JSON.stringify(src._values); } catch (e) { sourceBody = String(src._values); } + sourceBody = parsed.body || ""; + } else if (src._values && typeof src._values === "object") { + // Support several shapes: _values.body may be a string or an AST-like + // object. Prefer serializing AST shapes to Markdown when possible. + if (src._values.body && typeof src._values.body === "object") { + try { + sourceBody = serializeRichTextToMarkdown(src._values.body); + } catch { + sourceBody = JSON.stringify(src._values.body); } - } else if (src.body && typeof src.body === 'object') { + } else if (src._values.body && typeof src._values.body === "string") { + sourceBody = src._values.body; + } else if (src._values.children) { + try { + sourceBody = serializeRichTextToMarkdown(src._values); + } catch { + sourceBody = JSON.stringify(src._values); + } + } else { + try { + sourceBody = JSON.stringify(src._values); + } catch { + sourceBody = String(src._values); + } + } + } else if (src.body && typeof src.body === "object") { try { sourceBody = serializeRichTextToMarkdown(src.body); - } catch (e) { + } catch { sourceBody = JSON.stringify(src.body); } - } else if (typeof src.body === 'string') { + } else if (typeof src.body === "string") { const parsed = extractFrontmatter(src.body); sourceMeta = parsed.metadata || {}; sourceBody = parsed.body || src.body; } else { - sourceBody = src.body || ''; + sourceBody = src.body || ""; } - // optional debug helper - const DEBUG = (typeof process !== 'undefined' && process && process.env && process.env.XLIFF_DEBUG === '1') || (typeof globalThis !== 'undefined' && globalThis && globalThis.__XLIFF_DEBUG); - const debug = (...args) => { if (DEBUG) try { console.error('[xliff-debug]', ...args); } catch (e) {} }; - - // emit debug info about which path we used to populate sourceBody - try { - if (DEBUG) { - const srcTypes = []; - if (src.raw) srcTypes.push('raw'); - if (src._raw) srcTypes.push('_raw'); - if (src._values) srcTypes.push('_values'); - if (src.body && typeof src.body === 'object') srcTypes.push('body(AST)'); - if (typeof src.body === 'string') srcTypes.push('body(string)'); - if (src._sys && (src._sys.relativePath || src._sys.filename)) srcTypes.push('has _sys'); - debug('unit', key, 'srcTypes=' + srcTypes.join(',') + ' sourceBodyLen=' + String(sourceBody || '').length); - } - } catch (e) {} - // Cloud-only export: do NOT attempt filesystem fallbacks here. // The exporter should rely exclusively on data returned by GraphQL/Tina. // Any previous server-side filesystem fallbacks have been removed to // ensure exports generated in cloud environments do not access local disk. - // For target prefer raw translated MDX if present (tr.raw), otherwise // handle common shapes returned by GraphQL/Tina. When translation content // is provided as an AST-like object (for example in `tr._values.body` or // `tr.body`), serialize it to Markdown so the XLIFF target is human- // readable rather than a JSON blob. - let targetBody = ''; + let targetBody = ""; let targetMeta = {}; if (tr.raw) { const parsedT = extractFrontmatter(tr.raw); targetMeta = parsedT.metadata || {}; - targetBody = parsedT.body || ''; - } else if (tr._values && typeof tr._values === 'object') { + targetBody = parsedT.body || ""; + } else if (tr._values && typeof tr._values === "object") { // Prefer AST in tr._values.body when available - if (tr._values.body && typeof tr._values.body === 'object') { - try { targetBody = serializeRichTextToMarkdown(tr._values.body); } catch (e) { targetBody = JSON.stringify(tr._values.body); } - } else if (tr._values.body && typeof tr._values.body === 'string') { + if (tr._values.body && typeof tr._values.body === "object") { + try { + targetBody = serializeRichTextToMarkdown(tr._values.body); + } catch { + targetBody = JSON.stringify(tr._values.body); + } + } else if (tr._values.body && typeof tr._values.body === "string") { targetBody = tr._values.body; } else { - try { targetBody = JSON.stringify(tr._values); } catch (e) { targetBody = String(tr._values); } + try { + targetBody = JSON.stringify(tr._values); + } catch { + targetBody = String(tr._values); + } } - } else if (tr.body && typeof tr.body === 'object') { + } else if (tr.body && typeof tr.body === "object") { try { targetBody = serializeRichTextToMarkdown(tr.body); - } catch (e) { + } catch { targetBody = JSON.stringify(tr.body); } } else { - targetBody = tr.body || ''; + targetBody = tr.body || ""; } - const sourceTitle = src.title || ''; - const targetTitle = tr.title || ''; + const sourceTitle = src.title || ""; + const targetTitle = tr.title || ""; // Cloud-only export: do not attempt any additional filesystem fallback // here. If GraphQL/Tina returns an empty or incomplete shape for the @@ -1451,13 +1615,24 @@ export async function exportOutOfDateAsXliff(client, language) { // capture an explicit source path (if available) so we can store it as // a note for downstream tools (Swordfish may replace unit ids with // numeric placeholders; keeping the original path in notes preserves it). - const sourcePath = (src && src._sys && (src._sys.relativePath || src._sys.filename)) || (typeof key === 'string' ? `docs/${key}.mdx` : ''); - units.push({ id: key, sourceTitle, targetTitle, sourceBody, targetBody, sourceMeta, targetMeta, sourcePath }); + const sourcePath = + (src?._sys && (src._sys.relativePath || src._sys.filename)) || + (typeof key === "string" ? `docs/${key}.mdx` : ""); + units.push({ + id: key, + sourceTitle, + targetTitle, + sourceBody, + targetBody, + sourceMeta, + targetMeta, + sourcePath, + }); } // build XLIFF 2.1 document (Swordfish and most CAT tools prefer 2.0/2.1 over 2.2) const header = `\n\n`; - let body = ''; + let body = ""; // group by file attribute (we'll use language as file id) body += ` \n`; for (const u of units) { @@ -1465,19 +1640,19 @@ export async function exportOutOfDateAsXliff(client, language) { // Build notes for metadata. Include title and any frontmatter keys we captured. const notes = []; // store original source file path to aid tools that replace unit ids - notes.push(`path:${u.sourcePath || ''}`); - notes.push(`title:${u.sourceTitle || u.targetTitle || ''}`); + notes.push(`path:${u.sourcePath || ""}`); + notes.push(`title:${u.sourceTitle || u.targetTitle || ""}`); // source metadata if (u.sourceMeta) { for (const k of Object.keys(u.sourceMeta)) { - if (k === 'title') continue; + if (k === "title") continue; notes.push(`${k}:${u.sourceMeta[k]}`); } } // target metadata (prefix keys with 't.' to avoid collisions) if (u.targetMeta) { for (const k of Object.keys(u.targetMeta)) { - if (k === 'title') continue; + if (k === "title") continue; notes.push(`t.${k}:${u.targetMeta[k]}`); } } @@ -1488,7 +1663,9 @@ export async function exportOutOfDateAsXliff(client, language) { body += ` \n`; body += ` \n`; // Ensure source is never empty: insert a visible placeholder if needed - let safeSource = (u.sourceBody || '').toString().trim() ? u.sourceBody : '(no source content)'; + let safeSource = (u.sourceBody || "").toString().trim() + ? u.sourceBody + : "(no source content)"; // Cloud-only export: do not attempt to read local docs files by unit id. // If GraphQL did not provide content, leave the placeholder rather than // trying to access disk in cloud environments. @@ -1504,36 +1681,35 @@ export async function exportOutOfDateAsXliff(client, language) { // Normalize nested markdown links, convert to inline form so hrefs // survive CAT-tool round-trips, then convert HTML anchors and JSX prop // links. - let conv = outsideCodeFences(normalizeNestedMarkdownLinks)(String(safeSource)); + let conv = outsideCodeFences(normalizeNestedMarkdownLinks)( + String(safeSource) + ); conv = outsideCodeFences(markdownLinksToInlineUrl)(conv); conv = outsideCodeFences(htmlAnchorsToMarkdown)(conv); - // Extra debug output for specific problematic document - try { - if (DEBUG && u && String(u.id) === 'Getting-started---working-in-the-cloud') { - console.error('[xliff-debug-unit] id=' + u.id + ' serializedSourceLen=' + String((safeSource||'').length)); - console.error('[xliff-debug-unit] after normalizeNestedMarkdownLinks:\n' + normalizeNestedMarkdownLinks(String(safeSource)).slice(0,2000)); - console.error('[xliff-debug-unit] after markdownLinksToInlineUrl:\n' + markdownLinksToInlineUrl(normalizeNestedMarkdownLinks(String(safeSource))).slice(0,2000)); - console.error('[xliff-debug-unit] after htmlAnchorsToMarkdown:\n' + htmlAnchorsToMarkdown(markdownLinksToInlineUrl(normalizeNestedMarkdownLinks(String(safeSource)))).slice(0,2000)); - } - } catch (e) {} // If conversion appears to have lost hrefs, attempt AST-based repair try { - if ((!/https?:\/\//.test(conv) || /\[.*\]\(/.test(safeSource)) && src && src._values) { + if ( + (!/https?:\/\//.test(conv) || /\[.*\]\(/.test(safeSource)) && + src && + src._values + ) { conv = repairLinksFromAst(conv, src._values.body || src._values); // If repair didn't find pairs, try extracting raw URLs from the // source object and append them to list items in order. - if ((!/https?:\/\//.test(conv) || !/marker conversion so hrefs are visible to translators. conv = outsideCodeFences(convertJsxPropLinksToMarkdown)(conv); - conv = outsideCodeFences(s => s.replace(/</g, '<').replace(/>/g, '>'))(conv); + conv = outsideCodeFences((s) => + s.replace(/</g, "<").replace(/>/g, ">") + )(conv); // Convert angle-bracket JSX to marker form for CAT tools; do not // append parenthetical annotations here to avoid duplicate prop // annotations in the exported XLIFF. Translators will see props @@ -1547,10 +1723,10 @@ export async function exportOutOfDateAsXliff(client, language) { // the previous [^)]* approach which failed when JSX props contained ')'. conv = conv.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); safeSource = conv; - } catch (e) { + } catch { // ignore and fall back to raw source } // sanitize control chars before emitting @@ -1559,74 +1735,96 @@ export async function exportOutOfDateAsXliff(client, language) { // Ensure target text also preserves anchor hrefs and markdown links. // Convert markdown links to inline form and convert any HTML anchors // or JSX-prop links so hrefs are visible in the exported XLIFF target. - let safeTarget = outsideCodeFences(normalizeNestedMarkdownLinks)(String(u.targetBody || '')); + let safeTarget = outsideCodeFences(normalizeNestedMarkdownLinks)( + String(u.targetBody || "") + ); safeTarget = outsideCodeFences(markdownLinksToInlineUrl)(safeTarget); safeTarget = outsideCodeFences(htmlAnchorsToMarkdown)(safeTarget); safeTarget = outsideCodeFences(convertJsxPropLinksToMarkdown)(safeTarget); // Convert JSX to marker form and strip annotations (same pipeline as source) try { - safeTarget = outsideCodeFences(s => s.replace(/</g, '<').replace(/>/g, '>'))(safeTarget); + safeTarget = outsideCodeFences((s) => + s.replace(/</g, "<").replace(/>/g, ">") + )(safeTarget); safeTarget = outsideCodeFences(angleToMarker)(safeTarget); safeTarget = safeTarget.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); - } catch (e) { /* keep as-is on error */ } + } catch { + /* keep as-is on error */ + } const sanitizedTarget = stripControlChars(safeTarget); body += ` ${escapeXmlPreserveNewlines(sanitizedTarget)}\n`; body += ` \n`; body += ` \n`; } - body += ' \n'; - const footer = '\n'; + body += " \n"; + const footer = "\n"; return header + body + footer; } -export async function importXliffBundle(client, xliffText, language, onProgress) { +export async function importXliffBundle( + client, + xliffText, + language, + onProgress +) { // Surface an immediate progress signal so UI knows the import started - try { if (onProgress) onProgress({ id: null, status: 'started' }); } catch (e) {} + try { + if (onProgress) onProgress({ id: null, status: "started" }); + } catch {} // Parse XLIFF using DOMParser let doc; try { const parser = new DOMParser(); - doc = parser.parseFromString(xliffText, 'application/xml'); + doc = parser.parseFromString(xliffText, "application/xml"); } catch (parseErr) { - try { console.error && console.error('[xliff] parse error', parseErr); } catch (e) {} - if (onProgress) onProgress({ id: null, status: 'error', error: 'XLIFF parse error: ' + (parseErr && parseErr.message ? parseErr.message : String(parseErr)) }); - return [{ id: null, status: 'error', error: 'XLIFF parse error' }]; + if (onProgress) + onProgress({ + id: null, + status: "error", + error: + "XLIFF parse error: " + + (parseErr?.message ? parseErr.message : String(parseErr)), + }); + return [{ id: null, status: "error", error: "XLIFF parse error" }]; } // Be tolerant: XLIFF variants (or CAT tools like Swordfish) may wrap // units differently or add extra container tags. Try several fallbacks // to locate translation units: (XLIFF2), (XLIFF1.2) // or fall back to scanning for elements and their parent // or identifiers. Use a namespace-robust discovery. - const allEls = Array.from(doc.getElementsByTagName('*')); - let units = allEls.filter(el => { - const ln = (el.localName || el.tagName || '').toLowerCase(); - return ln === 'unit' || ln === 'trans-unit'; + const allEls = Array.from(doc.getElementsByTagName("*")); + let units = allEls.filter((el) => { + const ln = (el.localName || el.tagName || "").toLowerCase(); + return ln === "unit" || ln === "trans-unit"; }); if (!units || units.length === 0) { // find and use its ancestor as a unit-like container - const segs = allEls.filter(el => (el.localName || el.tagName || '').toLowerCase() === 'segment'); - units = segs.map(s => { + const segs = allEls.filter( + (el) => (el.localName || el.tagName || "").toLowerCase() === "segment" + ); + units = segs.map((s) => { // prefer parent unit/trans-unit, otherwise parent node if (!s) return s; const p = s.parentNode; if (!p) return s; - const pln = (p.localName || p.tagName || '').toLowerCase(); - if (pln === 'unit' || pln === 'trans-unit') return p; + const pln = (p.localName || p.tagName || "").toLowerCase(); + if (pln === "unit" || pln === "trans-unit") return p; return s; }); } // make unique (segments map could include duplicates) units = units.filter((v, i, a) => a.indexOf(v) === i); // diagnostic: report how many units were discovered - try { console.log && console.log('[xliff] discovered units:', units.length); } catch (e) {} // inform UI of discovered unit count - try { if (onProgress) onProgress({ id: null, status: 'discovered', count: units.length }); } catch (e) {} + try { + if (onProgress) + onProgress({ id: null, status: "discovered", count: units.length }); + } catch {} const results = []; for (const unit of units) { - try { console.debug && console.debug('[xliff] processing unit element', unit && (unit.getAttribute ? unit.getAttribute('id') : null)); } catch (e) {} // Try to determine an id for this unit. If unit lacks an explicit id, // attempt to find one on ancestor elements or derive one from a // `path:` note emitted by our exporter. @@ -1634,26 +1832,29 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (!p) return p; let s = String(p); // Strip a leading docs/ prefix if present - s = s.replace(/^docs\//, ''); + s = s.replace(/^docs\//, ""); // if path starts with a language code (2-3 letter code, optionally with // region e.g. "fr/", "nl/", "en-IE/") followed by the plugin prefix, // strip the language segment and plugin prefix together. const m = s.match(/^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(.*)$/i); if (m) s = m[1]; - s = s.replace(/^docusaurus-plugin-content-docs\/current\//, ''); - s = s.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(?:index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); + s = s.replace(/^docusaurus-plugin-content-docs\/current\//, ""); + s = s.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(?:index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); return s; }; let id = null; - if (unit.getAttribute && unit.getAttribute('id')) id = unit.getAttribute('id'); + if (unit.getAttribute?.("id")) id = unit.getAttribute("id"); // try ancestor nodes for id if (!id) { let p = unit.parentNode; while (p) { - if (p.getAttribute && p.getAttribute('id')) { id = p.getAttribute('id'); break; } + if (p.getAttribute?.("id")) { + id = p.getAttribute("id"); + break; + } p = p.parentNode; } } @@ -1667,11 +1868,11 @@ export async function importXliffBundle(client, xliffText, language, onProgress) let targetEl = null; if (unit.getElementsByTagName) { // Look for a element first - const segments = Array.from(unit.getElementsByTagName('segment')); + const segments = Array.from(unit.getElementsByTagName("segment")); const seg = segments.length ? segments[0] : null; if (seg) { - sourceEl = seg.getElementsByTagName('source')[0] || null; - targetEl = seg.getElementsByTagName('target')[0] || null; + sourceEl = seg.getElementsByTagName("source")[0] || null; + targetEl = seg.getElementsByTagName("target")[0] || null; } // If the segment target's text is identical to the segment source, // the translator may not have actually translated this segment (XLIFF @@ -1681,34 +1882,41 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // DeepL or TM). if (sourceEl && targetEl) { try { - const srcText = (sourceEl.textContent || '').trim(); - const tgtText = (targetEl.textContent || '').trim(); + const srcText = (sourceEl.textContent || "").trim(); + const tgtText = (targetEl.textContent || "").trim(); if (srcText && tgtText && srcText === tgtText) { // Target equals source — look for a different target in mtc:matches - const allTargets = Array.from(unit.getElementsByTagName('target')); + const allTargets = Array.from(unit.getElementsByTagName("target")); for (const t of allTargets) { if (t === targetEl) continue; - const altText = (t.textContent || '').trim(); + const altText = (t.textContent || "").trim(); if (altText && altText !== srcText) { targetEl = t; break; } } } - } catch (e) { /* keep segment target on error */ } + } catch { + /* keep segment target on error */ + } } // Fallback: pick the first source/target anywhere in the unit - if (!sourceEl) sourceEl = unit.getElementsByTagName('source')[0] || null; - if (!targetEl) targetEl = unit.getElementsByTagName('target')[0] || null; + if (!sourceEl) sourceEl = unit.getElementsByTagName("source")[0] || null; + if (!targetEl) targetEl = unit.getElementsByTagName("target")[0] || null; } - const notes = unit.getElementsByTagName ? Array.from(unit.getElementsByTagName('note')) : []; + const notes = unit.getElementsByTagName + ? Array.from(unit.getElementsByTagName("note")) + : []; // Find a note that starts with 'title:' (robust to ordering and whitespace) let titleNote = null; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^\s*title:\s*(.*)$/i); - if (m && m[1]) { titleNote = m[1].trim(); break; } + if (m?.[1]) { + titleNote = m[1].trim(); + break; + } } } // if no id yet, look for a note that begins with 'path:' which our exporter @@ -1716,11 +1924,11 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // original filename (including extension) for GraphQL relativePath so we // don't lose the .mdx extension required by the API. let rawPathFromNote = null; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^path:\s*(.*)$/i); - if (m && m[1]) { + if (m?.[1]) { rawPathFromNote = m[1].trim(); // use canonicalized id (without extensions) for unit id. // Always prefer the path-derived id over the existing id when the @@ -1736,21 +1944,26 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Extract visible text from the target while ignoring decorative XML tags const extractVisible = (el) => { - if (!el) return ''; - if (el.nodeType === 3) return el.nodeValue || ''; - let out = ''; + if (!el) return ""; + if (el.nodeType === 3) return el.nodeValue || ""; + let out = ""; const nodes = Array.from(el.childNodes || []); for (const n of nodes) { if (n.nodeType === 3) { - out += n.nodeValue || ''; + out += n.nodeValue || ""; } else if (n.nodeType === 1) { - const tag = (n.tagName || '').toLowerCase(); - if (tag === 'lb' || tag === 'br') { - out += '\n'; - } else if (tag === 'a') { + const tag = (n.tagName || "").toLowerCase(); + if (tag === "lb" || tag === "br") { + out += "\n"; + } else if (tag === "a") { // preserve links as Markdown [text](href) - const href = n.getAttribute && (n.getAttribute('href') || n.getAttribute('xlink:href') || n.getAttribute('data-href')) || ''; - const inner = extractVisible(n) || ''; + const href = + (n.getAttribute && + (n.getAttribute("href") || + n.getAttribute("xlink:href") || + n.getAttribute("data-href"))) || + ""; + const inner = extractVisible(n) || ""; if (href) out += `[${inner}](${href})`; else out += inner; } else { @@ -1761,7 +1974,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) return out; }; - let rawTarget = targetEl ? extractVisible(targetEl) : ''; + let rawTarget = targetEl ? extractVisible(targetEl) : ""; // If XML target contains JSON (export previously stored JSON), parse it; // otherwise treat as markdown/plain text and send through as-is. // Quick normalization: undo some remaining escape sequences that CAT @@ -1780,7 +1993,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // so props containing ')' in the preceding marker don't break matching. rawTarget = rawTarget.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); // Remove backslashes that CAT tools (e.g. Swordfish) insert before @@ -1790,22 +2003,35 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Note: \\n is left as-is (actual escaped newline) so we only strip // backslash when followed by a non-alphanumeric, non-space character // commonly used as a markdown control character. - rawTarget = rawTarget.replace(/\\([#\*\-\+\[\]\(\)>`_~!|:\.\\])/g, '$1'); + rawTarget = rawTarget.replace(/\\([#*\-+[\]()>`_~!|:.\\])/g, "$1"); // Undo escaped ordered-list dot: "1\. " -> "1. " (already covered by // the general pattern above, but keep for clarity) // Convert dash bullets to asterisk bullets for consistency with Tina // Preserve leading whitespace (indentation) for nested lists. // Only convert outside fenced code blocks so YAML/shell dashes are kept. - rawTarget = outsideCodeFences(s => s.replace(/(^|\n)(\s*)-\s+/g, '$1$2* '))(rawTarget); + rawTarget = outsideCodeFences((s) => + s.replace(/(^|\n)(\s*)-\s+/g, "$1$2* ") + )(rawTarget); // Trim accidental trailing whitespace per-line - rawTarget = rawTarget.split('\n').map(l => l.replace(/\s+$/,'')).join('\n'); - } catch (e) {} + rawTarget = rawTarget + .split("\n") + .map((l) => l.replace(/\s+$/, "")) + .join("\n"); + } catch {} // Targets exported by older flows may be JSON blobs; try to parse // JSON when it looks like a JSON object, otherwise keep string. let parsedBody = rawTarget; - if (rawTarget && typeof rawTarget === 'string' && rawTarget.trim().startsWith('{')) { - try { parsedBody = JSON.parse(rawTarget); } catch (e) { parsedBody = rawTarget; } + if ( + rawTarget && + typeof rawTarget === "string" && + rawTarget.trim().startsWith("{") + ) { + try { + parsedBody = JSON.parse(rawTarget); + } catch { + parsedBody = rawTarget; + } } // Convert angle-bracket JSX (e.g. ... // or ) to marker form so the parser handles them @@ -1819,13 +2045,19 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (fp % 2 === 0) { // Outside fenced code – convert angle-bracket JSX to marker form // Paired: content - fenceParts[fp] = fenceParts[fp].replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, '(jsx:$1$2)$3(/jsx:$1)'); + fenceParts[fp] = fenceParts[fp].replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + "(jsx:$1$2)$3(/jsx:$1)" + ); // Self-closing: - fenceParts[fp] = fenceParts[fp].replace(/<([A-Z][\w-]*)\b([^>]*)\s*\/>/g, '(jsx:$1$2/)'); + fenceParts[fp] = fenceParts[fp].replace( + /<([A-Z][\w-]*)\b([^>]*)\s*\/>/g, + "(jsx:$1$2/)" + ); } } - rawTarget = fenceParts.join(''); - } catch (e) {} + rawTarget = fenceParts.join(""); + } catch {} // The parseMarkdownToTinaAst parser handles marker-form JSX directly // and creates proper mdxJsxFlowElement/mdxJsxTextElement nodes, // avoiding the problem where angle-bracket JSX in text nodes gets @@ -1837,7 +2069,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // available, fall back to `id` and append `.mdx` to satisfy the API. let rel = null; if (rawPathFromNote) { - let cleaned = rawPathFromNote.replace(/^docs\//, ''); + const cleaned = rawPathFromNote.replace(/^docs\//, ""); rel = `${language}/docusaurus-plugin-content-docs/current/${cleaned}`; } else if (id) { // ensure extension present @@ -1848,9 +2080,9 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } if (!rel) { const errMsg = `missing unit id`; - try { console.warn && console.warn('[xliff] skipping unit without id'); } catch (e) {} - results.push({ id: id || null, status: 'error', error: errMsg }); - if (onProgress) onProgress({ id: id || null, status: 'error', error: errMsg }); + results.push({ id: id || null, status: "error", error: errMsg }); + if (onProgress) + onProgress({ id: id || null, status: "error", error: errMsg }); continue; } @@ -1861,71 +2093,99 @@ export async function importXliffBundle(client, xliffText, language, onProgress) updateI18n(relativePath: $relativePath, params: $params) { id } } `; - // Build variables matching the UpdateI18n mutation: `params` must be - // an `I18nMutation` object (not wrapped under `i18n`). - // Ensure body is a JSON object as expected by the I18nMutation schema. - // If parsedBody is a plain string (markdown/plain text), preserve - // its newlines and common Markdown constructs rather than collapsing - // them to single-line paragraphs. Also attempt to undo some CAT-tool - // escapes and normalize empty paired JSX tags into self-closing form. - let bodyPayload = parsedBody; - if (typeof parsedBody === 'string') { - try { - // Collapse empty paired JSX tags like `` -> `` - parsedBody = parsedBody.replace(/<([A-Z][\\w-]*)([^>]*)>\s*<\/\1>/g, '<$1$2 />'); - } catch (e) { - /* ignore */ - } - try { - // Comprehensive backslash-unescape for markdown control characters - // that CAT tools may have inserted. The first rawTarget cleanup - // handles the bulk, but if parsedBody went through JSON-parse or - // markerToAngle it may have re-introduced some escapes. - parsedBody = parsedBody.replace(/\\([#\*\-\+\[\]\(\)>`_~!|:\.\\])/g, '$1'); - // Some CAT tools encode '#' as HTML entity; unescape common ones - parsedBody = parsedBody.replace(/#|#/g, '#'); - } catch (e) {} - - // Preserve full markdown text by parsing it into the structured - // Tina AST that TinaCMS expects for the `body` field. Previously - // the code split on double-newlines and wrapped each chunk in a - // bare { type: 'p', children: [{ type: 'text', text: ... }] } node - // which caused Tina's serializer to backslash-escape every Markdown - // control character (headings, list markers, backticks, etc.). - bodyPayload = parseMarkdownToTinaAst(String(parsedBody || '')); + // Build variables matching the UpdateI18n mutation: `params` must be + // an `I18nMutation` object (not wrapped under `i18n`). + // Ensure body is a JSON object as expected by the I18nMutation schema. + // If parsedBody is a plain string (markdown/plain text), preserve + // its newlines and common Markdown constructs rather than collapsing + // them to single-line paragraphs. Also attempt to undo some CAT-tool + // escapes and normalize empty paired JSX tags into self-closing form. + let bodyPayload = parsedBody; + if (typeof parsedBody === "string") { + try { + // Collapse empty paired JSX tags like `` -> `` + parsedBody = parsedBody.replace( + /<([A-Z][\\w-]*)([^>]*)>\s*<\/\1>/g, + "<$1$2 />" + ); + } catch { + /* ignore */ } + try { + // Comprehensive backslash-unescape for markdown control characters + // that CAT tools may have inserted. The first rawTarget cleanup + // handles the bulk, but if parsedBody went through JSON-parse or + // markerToAngle it may have re-introduced some escapes. + parsedBody = parsedBody.replace(/\\([#*\-+[\]()>`_~!|:.\\])/g, "$1"); + // Some CAT tools encode '#' as HTML entity; unescape common ones + parsedBody = parsedBody.replace(/#|#/g, "#"); + } catch {} + + // Preserve full markdown text by parsing it into the structured + // Tina AST that TinaCMS expects for the `body` field. Previously + // the code split on double-newlines and wrapped each chunk in a + // bare { type: 'p', children: [{ type: 'text', text: ... }] } node + // which caused Tina's serializer to backslash-escape every Markdown + // control character (headings, list markers, backticks, etc.). + bodyPayload = parseMarkdownToTinaAst(String(parsedBody || "")); + } // Seed metadata from entries as a fallback when the source // doc cannot be fetched (TinaCloud may reject doc queries). let sourceMetaParams = {}; try { const noteMeta = {}; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^\s*([^:]+):\s*([\s\S]*)$/); if (!m) continue; - const k = String(m[1] || '').trim(); - const vRaw = (m[2] || '').trim(); + const k = String(m[1] || "").trim(); + const vRaw = (m[2] || "").trim(); if (!k) continue; const lk = k.toLowerCase(); - if (lk === 'path') { continue; } // path is used for ID resolution, not a mutation field - if (lk === 'title') { noteMeta.title = vRaw; continue; } - if (lk === 'description') { noteMeta.description = vRaw; continue; } - if (lk === 'tags') { + if (lk === "path") { + continue; + } // path is used for ID resolution, not a mutation field + if (lk === "title") { + noteMeta.title = vRaw; + continue; + } + if (lk === "description") { + noteMeta.description = vRaw; + continue; + } + if (lk === "tags") { let vals = null; - try { if (/^[\[\{]/.test(vRaw)) vals = JSON.parse(vRaw); } catch (e) { vals = null; } + try { + if (/^[[{]/.test(vRaw)) vals = JSON.parse(vRaw); + } catch { + vals = null; + } if (!vals) vals = vRaw.split(/\s*,\s*/).filter(Boolean); noteMeta.tags = Array.isArray(vals) ? vals : [String(vals)]; continue; } - if (['draft','review','translate','approved','published','unlisted'].includes(lk)) { - noteMeta[lk] = (/^(true|1|yes)$/i).test(vRaw); + if ( + [ + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", + ].includes(lk) + ) { + noteMeta[lk] = /^(true|1|yes)$/i.test(vRaw); continue; } - if (lk === 'conditions') { + if (lk === "conditions") { let vals = null; - try { if (/^[\[]/.test(vRaw)) vals = JSON.parse(vRaw); } catch (e) { vals = null; } + try { + if (/^[[]/.test(vRaw)) vals = JSON.parse(vRaw); + } catch { + vals = null; + } if (!vals) vals = vRaw.split(/\s*,\s*/).filter(Boolean); noteMeta.conditions = Array.isArray(vals) ? vals : [String(vals)]; continue; @@ -1934,7 +2194,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } } sourceMetaParams = Object.assign({}, noteMeta); - } catch (e) { + } catch { /* ignore note parsing errors */ } @@ -1942,59 +2202,70 @@ export async function importXliffBundle(client, xliffText, language, onProgress) try { let sourceDocRel = null; if (rawPathFromNote) { - let rp = String(rawPathFromNote || '').replace(/^\/?/, ''); + let rp = String(rawPathFromNote || "").replace(/^\/?/, ""); // The `doc` collection resolves relative to its configured content // directory (typically `docs/`). Strip any prefix that doesn't // belong: `docs/`, `docusaurus-plugin-content-docs/current/`, or // language prefixes like `fr/...`. - rp = rp.replace(/^docs\//, ''); - rp = rp.replace(/^docusaurus-plugin-content-docs\/current\//, ''); - rp = rp.replace(/^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(?:docusaurus-plugin-content-docs\/current\/)?/, ''); + rp = rp.replace(/^docs\//, ""); + rp = rp.replace(/^docusaurus-plugin-content-docs\/current\//, ""); + rp = rp.replace( + /^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(?:docusaurus-plugin-content-docs\/current\/)?/, + "" + ); sourceDocRel = rp; } else if (id) { - const cleaned = String(id).replace(/^\//, '').replace(/\.mdx?$|\.md$/i, ''); + const cleaned = String(id) + .replace(/^\//, "") + .replace(/\.mdx?$|\.md$/i, ""); sourceDocRel = `${cleaned}.mdx`; } if (sourceDocRel) { // Strip leading slashes. try { - sourceDocRel = String(sourceDocRel || '').replace(/^\//, ''); - } catch (e) {} - try { console.debug && console.debug('[xliff] sourceDocRel normalized to', sourceDocRel); } catch (e) {} + sourceDocRel = String(sourceDocRel || "").replace(/^\//, ""); + } catch {} try { - const docQuery = await client.queries.doc({ relativePath: sourceDocRel }); - const sdoc = docQuery && docQuery.data && docQuery.data.doc ? docQuery.data.doc : null; + const docQuery = await client.queries.doc({ + relativePath: sourceDocRel, + }); + const sdoc = docQuery?.data?.doc ? docQuery.data.doc : null; if (sdoc) { // Dynamically copy all non-null fields from the source doc, // skipping internal/GraphQL fields and body/lastmod. - const skipKeys = new Set(['__typename', '_sys', '_values', 'id', 'body', 'lastmod']); + const skipKeys = new Set([ + "__typename", + "_sys", + "_values", + "id", + "body", + "lastmod", + ]); for (const k of Object.keys(sdoc)) { if (skipKeys.has(k)) continue; if (sdoc[k] != null) { - sourceMetaParams[k] = Array.isArray(sdoc[k]) ? sdoc[k].slice() : sdoc[k]; + sourceMetaParams[k] = Array.isArray(sdoc[k]) + ? sdoc[k].slice() + : sdoc[k]; } } } - } catch (dqErr) { - try { console.warn && console.warn('[xliff] source doc query failed for', sourceDocRel, dqErr && dqErr.message); } catch (e) {} - } + } catch (_dqErr) {} } - } catch (metaErr) { - try { console.warn && console.warn('[xliff] metadata clone failed', metaErr && metaErr.message); } catch (e) {} - } + } catch (_metaErr) {} // Build final params. // Prefer preserving an existing translation's frontmatter (except lastmod). // If a translation doc exists at `rel`, clone its metadata and replace // the `body` with the imported content. If no translation exists, // fall back to source-cloned metadata (or notes) and the title note. - let paramsObj = {}; + const paramsObj = {}; try { let existingTranslation = null; try { const trQuery = await client.queries.i18n({ relativePath: rel }); - existingTranslation = trQuery && trQuery.data && trQuery.data.i18n ? trQuery.data.i18n : null; - } catch (e) { + existingTranslation = trQuery?.data?.i18n ? trQuery.data.i18n : null; + } catch { // If fetching the existing translation fails (cloud permissions), // we'll fall back to source metadata parsed from notes or cloned source. existingTranslation = null; @@ -2003,11 +2274,20 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (existingTranslation) { // Retain whatever metadata is present in the existing translation. // Skip internal/GraphQL fields and lastmod/body (we set those below). - const skipKeys = new Set(['__typename', '_sys', '_values', 'id', 'body', 'lastmod']); + const skipKeys = new Set([ + "__typename", + "_sys", + "_values", + "id", + "body", + "lastmod", + ]); for (const k of Object.keys(existingTranslation)) { if (skipKeys.has(k)) continue; if (existingTranslation[k] != null) { - paramsObj[k] = Array.isArray(existingTranslation[k]) ? existingTranslation[k].slice() : existingTranslation[k]; + paramsObj[k] = Array.isArray(existingTranslation[k]) + ? existingTranslation[k].slice() + : existingTranslation[k]; } } } else { @@ -2018,7 +2298,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } if (titleNote) paramsObj.title = titleNote; } - } catch (buildErr) { + } catch { // Fallback to source-cloned metadata if anything unexpected fails. // Only include keys with meaningful values. for (const k of Object.keys(sourceMetaParams || {})) { @@ -2029,14 +2309,26 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Always replace the body with the imported payload and set new lastmod paramsObj.body = bodyPayload; - paramsObj.lastmod = (new Date()).toISOString(); + paramsObj.lastmod = new Date().toISOString(); // Sanitize params: only include fields defined by I18nMutation and strip // null/undefined values. This prevents unexpected fields (e.g. 'path' from // XLIFF notes, or 'priority' from source docs) from causing GraphQL errors. const validI18nFields = new Set([ - 'help', 'lastmod', 'modifiedBy', 'title', 'body', 'conditions', - 'description', 'slug', 'tags', 'draft', 'review', 'translate', - 'approved', 'published', 'unlisted' + "help", + "lastmod", + "modifiedBy", + "title", + "body", + "conditions", + "description", + "slug", + "tags", + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", ]); const sanitized = {}; for (const k of Object.keys(paramsObj)) { @@ -2045,7 +2337,6 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } const variables = { relativePath: rel, params: sanitized }; // client.request in the dashboard expects an object with query/variables - try { console.debug && console.debug('[xliff] sending update for', rel); } catch (e) {} // Send request and inspect response for GraphQL errors. Some client // implementations return a response object rather than throwing on // GraphQL errors, so we must explicitly check `errors` to avoid @@ -2054,43 +2345,51 @@ export async function importXliffBundle(client, xliffText, language, onProgress) try { resp = await client.request({ query: mutation, variables }); } catch (requestErr) { - const emsg = requestErr && requestErr.message ? requestErr.message : String(requestErr); - try { console.warn && console.warn('[xliff] request threw for', rel, emsg); } catch (e) {} - results.push({ id, status: 'error', error: emsg }); - if (onProgress) onProgress({ id, status: 'error', error: emsg }); + const emsg = requestErr?.message + ? requestErr.message + : String(requestErr); + results.push({ id, status: "error", error: emsg }); + if (onProgress) onProgress({ id, status: "error", error: emsg }); continue; } // The generated Tina requester may return { data, errors } or the raw // GraphQL data. Inspect both shapes and ensure updateI18n succeeded. - const respErrors = resp && (resp.errors || (resp.data && resp.data.errors)) || null; - if (respErrors && respErrors.length) { - const msg = (respErrors.map && respErrors.map(e => (e && e.message) ? e.message : String(e)).join('; ')) || 'GraphQL errors'; - try { console.warn && console.warn('[xliff] update failed for', rel, msg, resp); } catch (e) {} - results.push({ id, status: 'error', error: msg, response: resp }); - if (onProgress) onProgress({ id, status: 'error', error: msg, response: resp }); + const respErrors = (resp && (resp.errors || resp.data?.errors)) || null; + if (respErrors?.length) { + const msg = Array.isArray(respErrors) + ? respErrors + .map((e) => (e?.message ? e.message : String(e))) + .join("; ") + : "GraphQL errors"; + results.push({ id, status: "error", error: msg, response: resp }); + if (onProgress) + onProgress({ id, status: "error", error: msg, response: resp }); continue; } // If no explicit errors, ensure the mutation returned a valid payload. const data = resp && (resp.data || resp); - const updated = data && (data.updateI18n || (data.updateI18n === null ? null : (Object.values(data).find(v => v && v.id)))); + const updated = + data && + (data.updateI18n || + (data.updateI18n === null + ? null + : Object.values(data).find((v) => v?.id))); if (!updated) { // If updateI18n is absent or null, surface the whole response for diagnosis - const msg = 'No update returned from server'; - try { console.warn && console.warn('[xliff] no update for', rel, resp); } catch (e) {} - results.push({ id, status: 'error', error: msg, response: resp }); - if (onProgress) onProgress({ id, status: 'error', error: msg, response: resp }); + const msg = "No update returned from server"; + results.push({ id, status: "error", error: msg, response: resp }); + if (onProgress) + onProgress({ id, status: "error", error: msg, response: resp }); } else { - try { console.debug && console.debug('[xliff] update successful for', rel, updated); } catch (e) {} - results.push({ id, status: 'updated' }); - if (onProgress) onProgress({ id, status: 'updated' }); + results.push({ id, status: "updated" }); + if (onProgress) onProgress({ id, status: "updated" }); } } catch (err) { - const errMsg = err && err.message ? err.message : String(err); - try { console.warn && console.warn('[xliff] import error for', id, errMsg); } catch (e) {} - results.push({ id, status: 'error', error: errMsg }); - if (onProgress) onProgress({ id, status: 'error', error: errMsg }); + const errMsg = err?.message ? err.message : String(err); + results.push({ id, status: "error", error: errMsg }); + if (onProgress) onProgress({ id, status: "error", error: errMsg }); } } return results; diff --git a/template/biome.json b/template/biome.template.json similarity index 72% rename from template/biome.json rename to template/biome.template.json index e3cf79f2..f0210ab0 100644 --- a/template/biome.json +++ b/template/biome.template.json @@ -4,25 +4,30 @@ "maxSize": 10485760, "includes": [ "**", - "!**/.next/**", - "!**/node_modules/**", - "!**/dist/**", - "!**/public/**", - "!**/content/**", - "!**/coverage/**", - "!**/tina/__generated__/**", + "!**/.next", + "!**/node_modules", + "!**/dist", + "!**/public", + "!**/content", + "!**/coverage", + "!**/tina/__generated__", "!**/tina/tina-lock.json", - "!**/src/styles/**", + "!**/src/styles", "!**/reuse/code-files.json", "!**/reuse/snippets-files.json", "!**/reuse/media/index.json", "!**/src/data/docs-metadata.json", - "!**/config/**/*.json" + "!**/config/**/*.json", + "!**/static/admin", + "!**/build", + "!**/.docusaurus", + "!**/src/css/theme-variables.css", + "!**/update-manifest.json" ] }, "overrides": [ { - "includes": ["scripts/**", "bin/**", "create-docstatic/**"], + "includes": ["**/scripts/**", "**/bin/**", "**/create-docstatic/**"], "linter": { "rules": { "suspicious": { @@ -30,6 +35,16 @@ } } } + }, + { + "includes": ["**/src/css/custom.css"], + "linter": { + "rules": { + "style": { + "noDescendingSpecificity": "off" + } + } + } } ], "formatter": { @@ -53,7 +68,7 @@ "linter": { "enabled": true, "rules": { - "recommended": true, + "preset": "recommended", "suspicious": { "noConsole": "error", "noExplicitAny": "off", @@ -79,7 +94,8 @@ "complexity": { "noForEach": "error", "useOptionalChain": "error", - "noBannedTypes": "off" + "noBannedTypes": "off", + "noImportantStyles": "off" } } }, @@ -94,6 +110,7 @@ "quoteStyle": "double", "attributePosition": "auto", "bracketSpacing": true - } + }, + "jsxRuntime": "reactClassic" } } diff --git a/template/docusaurus.config.ts b/template/docusaurus.config.ts index 0e47fbcf..37b9b342 100644 --- a/template/docusaurus.config.ts +++ b/template/docusaurus.config.ts @@ -1,13 +1,12 @@ -import remarkMath from 'remark-math'; -import rehypeKatex from 'rehype-katex'; -import { themes } from 'prism-react-renderer'; - -import PrismLight from './src/utils/prismLight'; -import PrismDark from './src/utils/prismDark'; +import { themes } from "prism-react-renderer"; +import rehypeKatex from "rehype-katex"; +import remarkMath from "remark-math"; +import PrismDark from "./src/utils/prismDark"; +import PrismLight from "./src/utils/prismLight"; // Import the blog date filter utility // eslint-disable-next-line @typescript-eslint/no-var-requires -const { getFutureDatedBlogFiles } = require('./src/plugins/blog-date-filter'); +const { getFutureDatedBlogFiles } = require("./src/plugins/blog-date-filter"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = createConfig; @@ -16,29 +15,52 @@ const docusaurusData = require("./config/docusaurus/index.json"); // Function to map theme names to actual theme objects const getTheme = (themeName: string) => { switch (themeName) { - case 'github': return themes.github; - case 'vsLight': return themes.vsLight; - case 'vsDark': return themes.vsDark; - case 'dracula': return themes.dracula; - case 'nightOwl': return themes.nightOwl; - case 'nightOwlLight': return themes.nightOwlLight; - case 'oceanicNext': return themes.oceanicNext; - case 'oneLight': return themes.oneLight; - case 'oneDark': return themes.oneDark; - case 'duotoneLight': return themes.duotoneLight; - case 'duotoneDark': return themes.duotoneDark; - case 'gruvboxMaterialLight': return themes.gruvboxMaterialLight; - case 'gruvboxMaterialDark': return themes.gruvboxMaterialDark; - case 'jettwaveLight': return themes.jettwaveLight; - case 'jettwaveDark': return themes.jettwaveDark; - case 'okaidia': return themes.okaidia; - case 'palenight': return themes.palenight; - case 'shadesOfPurple': return themes.shadesOfPurple; - case 'synthwave84': return themes.synthwave84; - case 'ultramin': return themes.ultramin; - case 'prismLight': return PrismLight; - case 'prismDark': return PrismDark; - default: return themes.github; + case "github": + return themes.github; + case "vsLight": + return themes.vsLight; + case "vsDark": + return themes.vsDark; + case "dracula": + return themes.dracula; + case "nightOwl": + return themes.nightOwl; + case "nightOwlLight": + return themes.nightOwlLight; + case "oceanicNext": + return themes.oceanicNext; + case "oneLight": + return themes.oneLight; + case "oneDark": + return themes.oneDark; + case "duotoneLight": + return themes.duotoneLight; + case "duotoneDark": + return themes.duotoneDark; + case "gruvboxMaterialLight": + return themes.gruvboxMaterialLight; + case "gruvboxMaterialDark": + return themes.gruvboxMaterialDark; + case "jettwaveLight": + return themes.jettwaveLight; + case "jettwaveDark": + return themes.jettwaveDark; + case "okaidia": + return themes.okaidia; + case "palenight": + return themes.palenight; + case "shadesOfPurple": + return themes.shadesOfPurple; + case "synthwave84": + return themes.synthwave84; + case "ultramin": + return themes.ultramin; + case "prismLight": + return PrismLight; + case "prismDark": + return PrismDark; + default: + return themes.github; } }; const getPageRoute = (page: string) => { @@ -55,7 +77,13 @@ type FooterItem = | { title: any; items: FooterItem[] } | { label: any; to?: any; href?: any }; -const formatFooterItem = (item: { title: any; items: any[]; label: any; to: any; href: any; }): FooterItem => { +const formatFooterItem = (item: { + title: any; + items: any[]; + label: any; + to: any; + href: any; +}): FooterItem => { if (item.title) { return { title: item.title, @@ -145,12 +173,12 @@ const config = { hooks: { onBrokenMarkdownLinks: "warn", }, - preprocessor: ({fileContent, filePath}: {fileContent: string; filePath: string}) => { + preprocessor: ({ fileContent }: { fileContent: string }) => { // Convert markers to MDX comments before compilation. // Tina CMS writes but Docusaurus expects {/* truncate */}. // The truncateMarker regex in the blog plugin handles the actual split // for list-view truncation *before* this runs, so removing it here is safe. - return fileContent.replace(//g, '{/* truncate */}'); + return fileContent.replace(//g, "{/* truncate */}"); }, }, title: docusaurusData.title, @@ -169,14 +197,14 @@ const config = { stylesheets: [ { - href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css', - type: 'text/css', + href: "https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css", + type: "text/css", integrity: - 'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM', - crossorigin: 'anonymous', + "sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM", + crossorigin: "anonymous", }, ], - + // Even if you don't use internalization, you can use this field to set useful // metadata like html lang. For example, if your site is Chinese, you may want // to replace "en" with "zh-Hans". @@ -194,7 +222,13 @@ const config = { remarkPlugins: [remarkMath], rehypePlugins: [rehypeKatex], // Remove this to remove the "edit this page" links. - editUrl: ({ versionDocsDirPath, docPath }: { versionDocsDirPath: string; docPath: string }) => { + editUrl: ({ + versionDocsDirPath, + docPath, + }: { + versionDocsDirPath: string; + docPath: string; + }) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const _unused = versionDocsDirPath; // docPath gives us the file path relative to docs directory @@ -212,7 +246,7 @@ const config = { blog: { exclude: (() => { // Get the absolute path to the blog directory - const blogDir = require('path').resolve(__dirname, 'blog'); + const blogDir = require("node:path").resolve(__dirname, "blog"); return getFutureDatedBlogFiles(blogDir); })(), showReadingTime: docusaurusData.showReadingTime, @@ -253,7 +287,8 @@ const config = { colorMode: { defaultMode: docusaurusData.colorMode?.defaultMode, disableSwitch: docusaurusData.colorMode?.disableSwitch, - respectPrefersColorScheme: docusaurusData.colorMode?.respectPrefersColorScheme, + respectPrefersColorScheme: + docusaurusData.colorMode?.respectPrefersColorScheme, }, docs: { sidebar: { @@ -275,12 +310,12 @@ const config = { }), copyright: `Copyright Ā© ${new Date().getFullYear()} ${docusaurusData.footer?.copyright}`, }, - prism: { - additionalLanguages: docusaurusData.prism?.additionalLanguages, - magicComments: docusaurusData.prism?.magicComments, - theme: getTheme(docusaurusData.prism.theme), - darkTheme: getTheme(docusaurusData.prism.darkTheme), - }, + prism: { + additionalLanguages: docusaurusData.prism?.additionalLanguages, + magicComments: docusaurusData.prism?.magicComments, + theme: getTheme(docusaurusData.prism.theme), + darkTheme: getTheme(docusaurusData.prism.darkTheme), + }, languageTabs: (() => { // Define all available language configurations const availableLanguages = { @@ -383,11 +418,13 @@ const config = { }; // Get selected languages from global languageTabs setting - const selectedLanguages = docusaurusData.openapi?.languageTabs as Array; - + const selectedLanguages = docusaurusData.openapi?.languageTabs as Array< + keyof typeof availableLanguages + >; + // Map selected languages to their full configurations return selectedLanguages - .map(lang => availableLanguages[lang]) + .map((lang) => availableLanguages[lang]) .filter(Boolean); // Remove any undefined entries })(), }, @@ -399,8 +436,26 @@ const config = { id: "openapi", docsPluginId: "classic", config: (() => { - const config: { [key: string]: { specPath: string; outputDir: string; downloadUrl?: string; tagTemplate?: string; sidebarOptions: { groupPathsBy: string; categoryLinkSource: string } } } = {}; - const apis: Array<{ name: string; specPath: string; outputDir: string; downloadUrl?: string; groupPathsBy?: string; categoryLinkSource?: string }> = docusaurusData.openapi?.apis || []; + const config: { + [key: string]: { + specPath: string; + outputDir: string; + downloadUrl?: string; + tagTemplate?: string; + sidebarOptions: { + groupPathsBy: string; + categoryLinkSource: string; + }; + }; + } = {}; + const apis: Array<{ + name: string; + specPath: string; + outputDir: string; + downloadUrl?: string; + groupPathsBy?: string; + categoryLinkSource?: string; + }> = docusaurusData.openapi?.apis || []; for (const api of apis) { config[api.name] = { @@ -414,7 +469,7 @@ const config = { }, }; } - + return config; })(), }, diff --git a/template/frontmatter.json b/template/frontmatter.json index f51058ba..458071d0 100644 --- a/template/frontmatter.json +++ b/template/frontmatter.json @@ -73,4 +73,4 @@ "tags", "authors" ] -} \ No newline at end of file +} diff --git a/template/package.json b/template/package.json index 104eebfb..3cb139bb 100644 --- a/template/package.json +++ b/template/package.json @@ -12,8 +12,10 @@ "generate-files": "node scripts/generate-file-list.js", "generate-docs-metadata": "node scripts/generate-docs-metadata.js", "update-theme-css": "node scripts/update-theme-css.js", - "prebuild": "yarn generate-media-index && yarn generate-files && yarn generate-docs-metadata && yarn update-theme-css && yarn generate-git-identity", - "predev": "yarn generate-media-index && yarn generate-files && yarn generate-docs-metadata && yarn update-theme-css && yarn generate-git-identity", + "generate": "node scripts/generate-media-index.js && node scripts/generate-file-list.js && node scripts/generate-docs-metadata.js && node scripts/update-theme-css.js && node scripts/generate-git-identity.js", + "prebuild": "yarn generate", + "predev": "yarn generate", + "prebuild-local": "yarn generate", "build": "tinacms build && docusaurus build", "build-local": "NODE_OPTIONS=--max-old-space-size=8192 tinacms build --local --skip-indexing --skip-cloud-checks && docusaurus build", "swizzle": "docusaurus swizzle", @@ -27,23 +29,23 @@ "gen-graphql": "docusaurus docs:generate:graphql", "gen-api-docs:version": "docusaurus gen-api-docs:version", "clean-api-docs:version": "docusaurus clean-api-docs:version", - "lint": "biome check config/ reuse/ scripts/ src/ tina/", - "lint:fix": "biome check config/ reuse/ scripts/ src/ tina/ --fix" + "lint": "biome check .", + "lint:fix": "biome check . --fix" }, "dependencies": { - "@algolia/client-search": "^5.53.0", + "@algolia/client-search": "^5.56.0", "@codemirror/language": "6.0.0", - "@docusaurus/core": "^3.10.1", - "@docusaurus/faster": "^3.10.1", - "@docusaurus/plugin-content-docs": "^3.10.1", - "@docusaurus/preset-classic": "^3.10.1", - "@docusaurus/theme-common": "^3.10.1", - "@docusaurus/theme-mermaid": "^3.10.1", - "@docusaurus/types": "^3.10.1", - "@docusaurus/utils": "^3.10.1", - "@docusaurus/utils-validation": "^3.10.1", + "@docusaurus/core": "^3.10.2", + "@docusaurus/faster": "^3.10.2", + "@docusaurus/plugin-content-docs": "^3.10.2", + "@docusaurus/preset-classic": "^3.10.2", + "@docusaurus/theme-common": "^3.10.2", + "@docusaurus/theme-mermaid": "^3.10.2", + "@docusaurus/types": "^3.10.2", + "@docusaurus/utils": "^3.10.2", + "@docusaurus/utils-validation": "^3.10.2", "@mdx-js/react": "^3.0.0", - "@types/react": "^19.2.15", + "@types/react": "^19.2.18", "color": "^5.0.2", "docusaurus-graphql-plugin": "0.7.0", "docusaurus-lunr-search": "^3.6.0", @@ -54,25 +56,25 @@ "fs-extra": "9.0.1", "image-size": "^2.0.2", "raw-loader": "^4.0.2", - "react": "^19.2.6", + "react": "^19.2.8", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^19.2.6", + "react-dom": "^19.2.8", "react-loadable": "^5.5.0", "react-markdown": "^10.1.0", "rehype-katex": "^7.0.1", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "remark-math": "^6.0.0", - "sass": "^1.100.0", + "sass": "^1.102.0", "search-insights": "^2.17.3", "slate": "^0.118.1", "slate-dom": "^0.118.1", "sucrase": "^3.35.0", - "tinacms": "^3.8.4", + "tinacms": "^3.11.0", "title": "^4.0.1", "typescript": "5.6.3", - "webpack": "^5.107.2", + "webpack": "^5.109.2", "yup": "0.32.11" }, "resolutions": { @@ -98,8 +100,8 @@ ] }, "devDependencies": { - "@biomejs/biome": "^2.4.16", - "@tinacms/cli": "^2.4.2", + "@biomejs/biome": "^2.5.7", + "@tinacms/cli": "^2.5.6", "gray-matter": "^4.0.3" }, "engines": { diff --git a/template/reuse/conditions/index.json b/template/reuse/conditions/index.json index aa4e131d..79de4cb6 100644 --- a/template/reuse/conditions/index.json +++ b/template/reuse/conditions/index.json @@ -17,4 +17,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/template/reuse/glossaryTerms/index.json b/template/reuse/glossaryTerms/index.json index 8f68dd38..0456fe21 100644 --- a/template/reuse/glossaryTerms/index.json +++ b/template/reuse/glossaryTerms/index.json @@ -13,4 +13,4 @@ "_template": "glossaryTerm" } ] -} \ No newline at end of file +} diff --git a/template/reuse/taxonomy/index.json b/template/reuse/taxonomy/index.json index 77259bfe..b8b54ff2 100644 --- a/template/reuse/taxonomy/index.json +++ b/template/reuse/taxonomy/index.json @@ -9,4 +9,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/template/reuse/variableSets/index.json b/template/reuse/variableSets/index.json index e556b291..a5a56288 100644 --- a/template/reuse/variableSets/index.json +++ b/template/reuse/variableSets/index.json @@ -15,4 +15,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/template/scripts/generate-docs-metadata.js b/template/scripts/generate-docs-metadata.js index ace3fc92..3bb0075b 100644 --- a/template/scripts/generate-docs-metadata.js +++ b/template/scripts/generate-docs-metadata.js @@ -34,7 +34,11 @@ function generateDocsMetadata() { const { data: frontmatter } = matter(fileContent); // Only include published documents with tags - if (frontmatter.published !== false && frontmatter.tags && Array.isArray(frontmatter.tags)) { + if ( + frontmatter.published !== false && + frontmatter.tags && + Array.isArray(frontmatter.tags) + ) { // Generate the URL path for Docusaurus let urlPath = relativeFilePath .replace(/\.(mdx?|md)$/, "") @@ -50,7 +54,9 @@ function generateDocsMetadata() { } docs.push({ - title: frontmatter.title || path.basename(entry.name, path.extname(entry.name)), + title: + frontmatter.title || + path.basename(entry.name, path.extname(entry.name)), description: frontmatter.description || "", tags: frontmatter.tags || [], path: urlPath, @@ -59,12 +65,16 @@ function generateDocsMetadata() { }); } } catch (error) { - console.warn(`Warning: Could not process ${fullPath}: ${error.message}`); + console.warn( + `Warning: Could not process ${fullPath}: ${error.message}` + ); } } } } catch (error) { - console.warn(`Warning: Could not read directory ${dir}: ${error.message}`); + console.warn( + `Warning: Could not read directory ${dir}: ${error.message}` + ); } } @@ -93,4 +103,4 @@ if (require.main === module) { generateDocsMetadata(); } -module.exports = generateDocsMetadata; \ No newline at end of file +module.exports = generateDocsMetadata; diff --git a/template/scripts/generate-git-identity.js b/template/scripts/generate-git-identity.js index ebc17385..9596ec54 100644 --- a/template/scripts/generate-git-identity.js +++ b/template/scripts/generate-git-identity.js @@ -3,9 +3,9 @@ * Writes the current Git user's identity to static/git-identity.json * so the Tina admin (browser) can read it during local development. */ -const { execSync } = require("child_process"); -const fs = require("fs"); -const path = require("path"); +const { execSync } = require("node:child_process"); +const fs = require("node:fs"); +const path = require("node:path"); function safe(cmd) { try { @@ -26,9 +26,11 @@ function main() { const outFile = path.join(outDir, "git-identity.json"); try { if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }); - fs.writeFileSync(outFile, JSON.stringify(data, null, 2) + "\n"); + fs.writeFileSync(outFile, `${JSON.stringify(data, null, 2)}\n`); // eslint-disable-next-line no-console - console.log(`[git-identity] Wrote ${outFile}: ${name}${email ? ` <${email}>` : ""}`); + console.log( + `[git-identity] Wrote ${outFile}: ${name}${email ? ` <${email}>` : ""}` + ); } catch (err) { // eslint-disable-next-line no-console console.warn("[git-identity] Failed to write git identity:", err.message); diff --git a/template/scripts/generate-media-index.js b/template/scripts/generate-media-index.js index d24e8dcd..85325163 100644 --- a/template/scripts/generate-media-index.js +++ b/template/scripts/generate-media-index.js @@ -5,24 +5,24 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require('fs'); -const path = require('path'); -const { imageSize } = require('image-size'); +const fs = require("node:fs"); +const path = require("node:path"); +const { imageSize } = require("image-size"); -const IMG_DIR = path.join(__dirname, '../static/img'); -const OUTPUT_FILE = path.join(__dirname, '../reuse/media/index.json'); +const IMG_DIR = path.join(__dirname, "../static/img"); +const OUTPUT_FILE = path.join(__dirname, "../reuse/media/index.json"); function getMediaFiles(dir, baseDir = IMG_DIR) { let results = []; const list = fs.readdirSync(dir); - list.forEach(file => { + for (const file of list) { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); - if (stat && stat.isDirectory()) { + if (stat?.isDirectory()) { results = results.concat(getMediaFiles(filePath, baseDir)); } else if (/\.(jpg|jpeg|png|gif|svg|webp)$/i.test(file)) { const ext = path.extname(file).toLowerCase(); - let dimensions = undefined; + let dimensions; // Only get dimensions for raster images if (/(jpg|jpeg|png|gif|webp)$/i.test(ext)) { try { @@ -31,7 +31,7 @@ function getMediaFiles(dir, baseDir = IMG_DIR) { if (size.width && size.height) { dimensions = `${size.width}x${size.height}`; } - } catch (e) { + } catch (_e) { // Skip dimensions for this file, continue processing others } } @@ -39,13 +39,13 @@ function getMediaFiles(dir, baseDir = IMG_DIR) { const lastModified = stat.mtime.toISOString(); results.push({ filename: file, - path: path.relative(baseDir, filePath).replace(/\\/g, '/'), + path: path.relative(baseDir, filePath).replace(/\\/g, "/"), size: stat.size, ...(dimensions ? { dimensions } : {}), - lastModified + lastModified, }); } - }); + } return results; } @@ -55,4 +55,4 @@ function main() { console.log(`Media index written to ${OUTPUT_FILE}`); } -main(); \ No newline at end of file +main(); diff --git a/template/sidebars.ts b/template/sidebars.ts index 1e5b6f18..81231d84 100644 --- a/template/sidebars.ts +++ b/template/sidebars.ts @@ -1,7 +1,7 @@ -const fs = require("fs"); -const path = require("path"); +const fs = require("node:fs"); +const path = require("node:path"); const sidebarData = require("./config/sidebar/index.json"); -const docusaurusData = require("./config/docusaurus/index.json"); +const _docusaurusData = require("./config/docusaurus/index.json"); const getDocId = (doc) => { return doc @@ -73,7 +73,7 @@ const getItem = (item) => { }, ]; } - + if (type === "link") { if (item.href && item.title) { itemProps.label = item.title; diff --git a/template/src/components/CollapsibleField/index.jsx b/template/src/components/CollapsibleField/index.jsx index 4cbe771a..35c545d9 100644 --- a/template/src/components/CollapsibleField/index.jsx +++ b/template/src/components/CollapsibleField/index.jsx @@ -28,17 +28,9 @@ const CollapsibleField = wrapFieldsWithMeta( } const toggleCollapsed = () => { - setIsCollapsed(!isCollapsed); + setIsCollapsed((collapsed) => !collapsed); }; - const hasValue = - input.value && - (Array.isArray(input.value) - ? input.value.length > 0 - : typeof input.value === "string" - ? input.value.trim() !== "" - : true); - return ( <> {/* Toggle button positioned independently */} @@ -82,10 +74,7 @@ const CollapsibleField = wrapFieldsWithMeta( > { +const Comment = () => { // This component intentionally returns null // The comment is only visible in the source code return null; diff --git a/template/src/components/ConditionalText/index.jsx b/template/src/components/ConditionalText/index.jsx index e2a3baf8..9975712c 100644 --- a/template/src/components/ConditionalText/index.jsx +++ b/template/src/components/ConditionalText/index.jsx @@ -24,21 +24,19 @@ const ConditionalText = ({ let pageConditions = []; let currentLanguage = "en"; + // useDoc() throws outside a doc page (blog posts, custom pages), so this + // guard is load-bearing. useDocusaurusContext() needs no guard: its provider + // is mounted at the app root. try { - // Get document metadata (conditions from frontmatter) + // biome-ignore lint/correctness/useHookAtTopLevel: useDoc throws off doc pages; the catch is the only way to render this component elsewhere const doc = useDoc(); pageConditions = doc?.frontMatter?.conditions || []; } catch { // Not in a doc context, pageConditions stays empty } - try { - // Get current language from Docusaurus context - const { i18n } = useDocusaurusContext(); - currentLanguage = i18n?.currentLocale || "en"; - } catch { - // Context not available, use default - } + const { i18n } = useDocusaurusContext(); + currentLanguage = i18n?.currentLocale || "en"; // Check if required conditions are met against page metadata conditions const checkConditionsMet = () => { @@ -46,21 +44,25 @@ const ConditionalText = ({ if (logic === "all") { // All required conditions must be present in page metadata - return conditions.every((condition) => pageConditions.includes(condition)); + return conditions.every((condition) => + pageConditions.includes(condition) + ); } // Any required condition must be present in page metadata return conditions.some((condition) => pageConditions.includes(condition)); }; - // Check if language conditions are satisfied + // Check if language conditions are satisfied. Only one language is ever + // active, so "all" is only satisfiable by a single-entry list — previously + // both branches were identical and languageLogic had no effect at all. const checkLanguageConditions = () => { if (languages.length === 0) return true; if (languageLogic === "all") { - // For 'all' logic, current language must be in the list - return languages.includes(currentLanguage); + // Every listed language must match the active one + return languages.every((language) => language === currentLanguage); } - // For 'any' logic, current language must match at least one + // Any listed language may match the active one return languages.includes(currentLanguage); }; @@ -90,7 +92,8 @@ const ConditionalText = ({ } // Apply action logic: show or hide based on whether conditions are met - const shouldShow = action === "hide" ? !conditionsSatisfied : conditionsSatisfied; + const shouldShow = + action === "hide" ? !conditionsSatisfied : conditionsSatisfied; // const debugInfo = debug // ? { @@ -131,11 +134,11 @@ const ConditionalText = ({ )} */} - {shouldShow ? ( - children - ) : ( - fallback && {fallback} - )} + {shouldShow + ? children + : fallback && ( + {fallback} + )} ); }; diff --git a/template/src/components/ConditionalText/template.jsx b/template/src/components/ConditionalText/template.jsx index 2f809df3..f7a479cd 100644 --- a/template/src/components/ConditionalText/template.jsx +++ b/template/src/components/ConditionalText/template.jsx @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import conditionsData from "../../../reuse/conditions/index.json"; import docusaurusData from "../../../config/docusaurus/index.json"; +import conditionsData from "../../../reuse/conditions/index.json"; import ConditionsTreeField from "../ConditionsField"; // Build condition options from conditions data @@ -67,7 +67,8 @@ export const ConditionalTextBlockTemplate = { ], ui: { component: "select", - description: "Choose whether to show or hide content when conditions match", + description: + "Choose whether to show or hide content when conditions match", }, }, { @@ -78,7 +79,8 @@ export const ConditionalTextBlockTemplate = { options: conditionOptions, ui: { component: ConditionsTreeField, - description: "Content action will be triggered when these conditions are met (defined in page metadata)", + description: + "Content action will be triggered when these conditions are met (defined in page metadata)", }, }, { diff --git a/template/src/components/ConditionsField/index.jsx b/template/src/components/ConditionsField/index.jsx index e17342be..7a2e78be 100644 --- a/template/src/components/ConditionsField/index.jsx +++ b/template/src/components/ConditionsField/index.jsx @@ -72,54 +72,11 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => { }; const handleConditionToggle = (conditionValue) => { - try { - const newConditions = selectedConditions.includes(conditionValue) - ? selectedConditions.filter((c) => c !== conditionValue) - : [...selectedConditions, conditionValue]; + const newConditions = selectedConditions.includes(conditionValue) + ? selectedConditions.filter((c) => c !== conditionValue) + : [...selectedConditions, conditionValue]; - input.onChange(newConditions); - } catch (error) { - // Silent error handling for production - } - }; - - const handleCategoryToggle = (category, conditions) => { - try { - const categoryValues = conditions.map((c) => c.value); - const allSelected = categoryValues.every((value) => - selectedConditions.includes(value) - ); - - let newConditions; - if (allSelected) { - // Deselect all conditions in this category - newConditions = selectedConditions.filter( - (c) => !categoryValues.includes(c) - ); - } else { - // Select all conditions in this category - const toAdd = categoryValues.filter( - (value) => !selectedConditions.includes(value) - ); - newConditions = [...selectedConditions, ...toAdd]; - } - - input.onChange(newConditions); - } catch (error) { - // Silent error handling for production - } - }; - - const getCategoryStatus = (conditions) => { - const categoryValues = conditions.map((c) => c.value); - const selectedCount = categoryValues.filter((value) => - selectedConditions.includes(value) - ).length; - const totalCount = categoryValues.length; - - if (selectedCount === 0) return "none"; - if (selectedCount === totalCount) return "all"; - return "some"; + input.onChange(newConditions); }; return ( @@ -177,11 +134,6 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => {
    {Object.entries(conditionsTree).map(([category, conditions]) => { const isExpanded = expandedCategories.has(category); - const categoryStatus = getCategoryStatus(conditions); - const selectedInCategory = conditions.filter((c) => - selectedConditions.includes(c.value) - ).length; - return (
    {/* Category Header */} @@ -204,12 +156,13 @@ const ConditionsTreeField = wrapFieldsWithMeta(({ input, field }) => { ā–¶ - toggleCategory(category)} - className="flex-1 text-left text-sm cursor-pointer select-none" + className="flex-1 text-left text-sm cursor-pointer select-none bg-transparent border-none p-0" > {category} - +
    {/* Category Conditions */} diff --git a/template/src/components/Dashboard/BrokenLinksDashboard.jsx b/template/src/components/Dashboard/BrokenLinksDashboard.jsx index 5b5e82ac..45821b51 100644 --- a/template/src/components/Dashboard/BrokenLinksDashboard.jsx +++ b/template/src/components/Dashboard/BrokenLinksDashboard.jsx @@ -1,879 +1,1226 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const BrokenLinksDashboard = () => { - const [linkData, setLinkData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [showDetails, setShowDetails] = useState(false); - const [selectedFile, setSelectedFile] = useState(null); - - // Function to extract links from MDX content - const extractLinksFromContent = (content, filePath) => { - const links = []; - - // Regex for markdown links [text](url) - const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g; - // Regex for HTML links - const htmlLinkRegex = /]+href=["']([^"']+)["'][^>]*>/gi; - // Regex for reference links [text][ref] and [ref]: url - const refLinkRegex = /\[([^\]]+)\]\[([^\]]*)\]/g; - const refDefRegex = /^\[([^\]]+)\]:\s*(.+)$/gm; - - let match; - - // Extract markdown links - while ((match = markdownLinkRegex.exec(content)) !== null) { - links.push({ - text: match[1], - url: match[2].trim(), - type: 'markdown', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - - // Extract HTML links - while ((match = htmlLinkRegex.exec(content)) !== null) { - links.push({ - text: match[0], - url: match[1].trim(), - type: 'html', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - - // Extract reference definitions - const refDefs = {}; - while ((match = refDefRegex.exec(content)) !== null) { - refDefs[match[1].toLowerCase()] = match[2].trim(); - } - - // Extract reference links - while ((match = refLinkRegex.exec(content)) !== null) { - const refKey = (match[2] || match[1]).toLowerCase(); - if (refDefs[refKey]) { - links.push({ - text: match[1], - url: refDefs[refKey], - type: 'reference', - filePath, - lineNumber: content.substring(0, match.index).split('\n').length - }); - } - } - - return links; - }; - - // Function to validate a single link - const validateLink = async (link) => { - try { - const url = link.url.trim(); - - // Skip anchors, mailto, and tel links - if (url.startsWith('#') || url.startsWith('mailto:') || url.startsWith('tel:')) { - return { ...link, status: 'skipped', reason: 'Not validated (anchor/mailto/tel)' }; - } - - // Handle relative/internal links - if (!url.startsWith('http://') && !url.startsWith('https://')) { - // Check if it's a relative link to another doc - if (url.endsWith('.mdx') || url.endsWith('.md')) { - return { ...link, status: 'valid', reason: 'Internal doc link (assumed valid)' }; - } - return { ...link, status: 'valid', reason: 'Internal link (assumed valid)' }; - } - - // Validate external links with timeout - use original no-cors approach first - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 8000); - - try { - // Primary approach: Use no-cors mode (original working method) - const response = await fetch(url, { - method: 'HEAD', - signal: controller.signal, - mode: 'no-cors', - headers: { - 'User-Agent': 'Mozilla/5.0 (compatible; docStatic Link Checker/1.0)' - } - }); - - clearTimeout(timeoutId); - - // With no-cors mode, if no error is thrown, assume link is reachable - return { ...link, status: 'valid', reason: 'Link is reachable' }; - - } catch (fetchError) { - clearTimeout(timeoutId); - - if (fetchError.name === 'AbortError') { - return { ...link, status: 'broken', reason: 'Timeout (>8s)' }; - } - - // Fallback: Check if this might be a CORS/CORP issue for known problematic domains - const urlObj = new URL(url); - const knownCorsDomains = [ - 'docs.github.com', - 'support.microsoft.com', - 'docs.microsoft.com', - 'developer.mozilla.org' - ]; - - const isKnownCorsDomain = knownCorsDomains.some(domain => - urlObj.hostname === domain || urlObj.hostname.endsWith('.' + domain) - ); - - if (isKnownCorsDomain) { - return { - ...link, - status: 'warning', - reason: 'CORS/CORP policy prevents validation - manual check required' - }; - } - - // For other errors, use original logic - if (fetchError.message.includes('network') || fetchError.message.includes('fetch')) { - return { ...link, status: 'broken', reason: 'Network error or unreachable' }; - } - - // For other errors, assume CORS restrictions but link might be valid - return { ...link, status: 'warning', reason: 'CORS restricted (unable to verify)' }; - } - } catch (error) { - return { ...link, status: 'broken', reason: error.message }; - } - }; - - // Function to open file in CMS editor - const openInCMS = (filePath) => { - // Extract relative path from full path - const relativePath = filePath.replace(/^\/docs\//, '').replace(/\.mdx?$/i, ''); - const cmsUrl = `/admin/index.html#/collections/edit/doc/${encodeURIComponent(relativePath)}`; - window.open(cmsUrl, '_blank'); - }; - - // Function to scan docs directory for MDX files using GraphQL - const scanDocsForLinks = async () => { - setLoading(true); - setError(null); - - try { - // Import the Tina client - const { client } = await import('../../../tina/__generated__/client'); - - // Fetch all docs from the main collection - const docsResult = await client.queries.docConnection({ - sort: 'title', - first: 500 // Request more documents - }); - - const docs = docsResult.data.docConnection.edges || []; - - const allLinks = []; - const fileStats = {}; - - // Process each document - for (const edge of docs) { - const node = edge.node; - const fileName = `${node._sys.filename}.mdx`; - const filePath = `/docs/${node._sys.relativePath}`; - - // Get the document body content - let content = ''; - if (node.body) { - // Extract text content from rich text blocks - content = extractTextFromBody(node.body); - } - - // Add title content if available - if (node.title) { - content = `# ${node.title}\n\n${content}`; - } - - const links = extractLinksFromContent(content, filePath); - - fileStats[filePath] = { - totalLinks: links.length, - fileName: fileName, - title: node.title || node._sys.filename, - relativePath: node._sys.relativePath - }; - - allLinks.push(...links); - } - - // Validate all links - const validatedLinks = []; - for (const link of allLinks) { - const validatedLink = await validateLink(link); - validatedLinks.push(validatedLink); - } - - // Calculate statistics - const stats = validatedLinks.reduce((acc, link) => { - acc.total++; - if (link.status === 'valid') acc.valid++; - else if (link.status === 'broken') acc.broken++; - else if (link.status === 'warning') acc.warning++; - else if (link.status === 'skipped') acc.skipped++; - return acc; - }, { total: 0, valid: 0, broken: 0, warning: 0, skipped: 0 }); - - // Group by file - const linksByFile = {}; - validatedLinks.forEach(link => { - const fileName = link.filePath.split('/').pop(); - if (!linksByFile[fileName]) { - linksByFile[fileName] = []; - } - linksByFile[fileName].push(link); - }); - - setLinkData({ - stats, - fileStats, - linksByFile, - allLinks: validatedLinks, - brokenLinks: validatedLinks.filter(link => link.status === 'broken'), - warningLinks: validatedLinks.filter(link => link.status === 'warning'), - timestamp: new Date().toISOString() - }); - } catch (error) { - setError(error.message); - console.error('Error scanning for broken links:', error); - } finally { - setLoading(false); - } - }; - - // Function to extract text content from Tina CMS rich text body - const extractTextFromBody = (body) => { - if (!body || !body.children) return ''; - - const extractFromChildren = (children) => { - return children.map(child => { - if (child.type === 'text') { - return child.text || ''; - } - if (child.type === 'a' && child.url) { - const text = child.children ? extractFromChildren(child.children) : ''; - return `[${text}](${child.url})`; - } - if (child.children) { - return extractFromChildren(child.children); - } - return ''; - }).join(''); - }; - - return extractFromChildren(body.children); - }; - - - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!linkData && !loading && !error) { - return ( -
    -
    -
    - - - - - - - -

    - Broken Links Dashboard -

    -
    - -
    -
    - ); - } - - if (loading) { - return ( -
    -
    -
    - Loading Dashboard -
    -
    - Scanning docs for links and validating... -
    - - {/* Progress Bar for Loading */} -
    -
    -
    -
    - -
    - ); - } - - if (error) { - return ( -
    -
    -
    - - - - - - Error -
    -
    {error}
    - -
    -
    - ); - } - - if (!linkData) { - return ( -
    - No data available -
    - ); - } - - const { stats, fileStats, linksByFile, brokenLinks, warningLinks } = linkData; - const problemLinks = [...(brokenLinks || []), ...(warningLinks || [])]; - - return ( -
    -
    -
    - - - - - - - -

    - Broken Links Dashboard -

    -
    - -
    - - {/* Statistics Cards */} -
    -
    -
    - - - - -
    -
    -

    Total Links

    -

    {stats.total}

    -
    -
    - -
    -
    - - - -
    -
    -

    Valid Links

    -

    {stats.valid}

    -
    -
    - -
    -
    - - - - -
    -
    -

    Broken Links

    -

    {stats.broken}

    -
    -
    - -
    -
    - - - - - -
    -
    -

    Warning Links

    -

    {stats.warning || 0}

    -
    -
    - -
    -
    - - - - -
    -
    -

    Files Scanned

    -

    {Object.keys(fileStats).length}

    -
    -
    -
    - - {/* Broken Links Section */} - {problemLinks.length > 0 && ( -
    -

    - 🚨 Problem Links ({problemLinks.length}) -

    -
    - {problemLinks.map((link, index) => ( -
    - - -
    - ))} -
    -
    - )} - - {/* Files with Broken Links */} - {(() => { - const filesWithProblemLinks = Object.entries(fileStats).filter(([filePath, stats]) => { - const fileName = stats.fileName; - const fileLinks = linksByFile[fileName] || []; - return fileLinks.some(link => link.status === 'broken' || link.status === 'warning'); - }); - - if (filesWithProblemLinks.length === 0) { - return null; - } - - return ( -
    -
    -

    - - - - - Files with Problem Links ({filesWithProblemLinks.length}) -

    - -
    - -
    - {filesWithProblemLinks.slice(0, showDetails ? undefined : 5).map(([filePath, stats], index) => { - const fileName = stats.fileName; - const fileLinks = linksByFile[fileName] || []; - const brokenCount = fileLinks.filter(link => link.status === 'broken').length; - const warningCount = fileLinks.filter(link => link.status === 'warning').length; - const totalProblems = brokenCount + warningCount; - - return ( -
    0 ? '#fff5f5' : '#fff8f0', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center' - }} - > -
    -
    - {stats.title || fileName} -
    -
    - {stats.totalLinks} total links • {totalProblems} problem{totalProblems !== 1 ? 's' : ''} - {brokenCount > 0 && ( - - ({brokenCount} broken{warningCount > 0 ? `, ${warningCount} warning` : ''}) - - )} - {brokenCount === 0 && warningCount > 0 && ( - - ({warningCount} warning) - - )} -
    -
    - -
    - ); - })} -
    - - {!showDetails && filesWithProblemLinks.length > 5 && ( -
    - And {filesWithProblemLinks.length - 5} more files... -
    - )} -
    - ); - })()} - - {/* Health Status */} -
    -
    - - {(stats.broken === 0 && (stats.warning || 0) === 0) ? ( - <> - - - - All Links Valid! - - ) : stats.broken === 0 ? ( - <> - - - - - - {stats.warning} Warning Links - - ) : ( - <> - - - - - {stats.broken} Broken Links{(stats.warning || 0) > 0 ? ` and ${stats.warning} Warnings` : ''} - - )} - -
    -
    - Link validation completed on {new Date().toLocaleString()} -
    -
    -
    - ); -}; - -export default BrokenLinksDashboard; \ No newline at end of file +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; + +const BrokenLinksDashboard = () => { + const [linkData, setLinkData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showDetails, setShowDetails] = useState(false); + const [_selectedFile, _setSelectedFile] = useState(null); + + // Function to extract links from MDX content + const extractLinksFromContent = (content, filePath) => { + const links = []; + + // Regex for markdown links [text](url) + const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g; + // Regex for HTML links + const htmlLinkRegex = /]+href=["']([^"']+)["'][^>]*>/gi; + // Regex for reference links [text][ref] and [ref]: url + const refLinkRegex = /\[([^\]]+)\]\[([^\]]*)\]/g; + const refDefRegex = /^\[([^\]]+)\]:\s*(.+)$/gm; + + // Extract markdown links + for (const match of content.matchAll(markdownLinkRegex)) { + links.push({ + text: match[1], + url: match[2].trim(), + type: "markdown", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + + // Extract HTML links + for (const match of content.matchAll(htmlLinkRegex)) { + links.push({ + text: match[0], + url: match[1].trim(), + type: "html", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + + // Extract reference definitions + const refDefs = {}; + for (const match of content.matchAll(refDefRegex)) { + refDefs[match[1].toLowerCase()] = match[2].trim(); + } + + // Extract reference links + for (const match of content.matchAll(refLinkRegex)) { + const refKey = (match[2] || match[1]).toLowerCase(); + if (refDefs[refKey]) { + links.push({ + text: match[1], + url: refDefs[refKey], + type: "reference", + filePath, + lineNumber: content.substring(0, match.index).split("\n").length, + }); + } + } + + return links; + }; + + // Function to validate a single link + const validateLink = async (link) => { + try { + const url = link.url.trim(); + + // Skip anchors, mailto, and tel links + if ( + url.startsWith("#") || + url.startsWith("mailto:") || + url.startsWith("tel:") + ) { + return { + ...link, + status: "skipped", + reason: "Not validated (anchor/mailto/tel)", + }; + } + + // Handle relative/internal links + if (!url.startsWith("http://") && !url.startsWith("https://")) { + // Check if it's a relative link to another doc + if (url.endsWith(".mdx") || url.endsWith(".md")) { + return { + ...link, + status: "valid", + reason: "Internal doc link (assumed valid)", + }; + } + return { + ...link, + status: "valid", + reason: "Internal link (assumed valid)", + }; + } + + // Validate external links with timeout - use original no-cors approach first + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 8000); + + try { + // Primary approach: Use no-cors mode (original working method) + const _response = await fetch(url, { + method: "HEAD", + signal: controller.signal, + mode: "no-cors", + headers: { + "User-Agent": + "Mozilla/5.0 (compatible; docStatic Link Checker/1.0)", + }, + }); + + clearTimeout(timeoutId); + + // With no-cors mode, if no error is thrown, assume link is reachable + return { ...link, status: "valid", reason: "Link is reachable" }; + } catch (fetchError) { + clearTimeout(timeoutId); + + if (fetchError.name === "AbortError") { + return { ...link, status: "broken", reason: "Timeout (>8s)" }; + } + + // Fallback: Check if this might be a CORS/CORP issue for known problematic domains + const urlObj = new URL(url); + const knownCorsDomains = [ + "docs.github.com", + "support.microsoft.com", + "docs.microsoft.com", + "developer.mozilla.org", + ]; + + const isKnownCorsDomain = knownCorsDomains.some( + (domain) => + urlObj.hostname === domain || urlObj.hostname.endsWith(`.${domain}`) + ); + + if (isKnownCorsDomain) { + return { + ...link, + status: "warning", + reason: + "CORS/CORP policy prevents validation - manual check required", + }; + } + + // For other errors, use original logic + if ( + fetchError.message.includes("network") || + fetchError.message.includes("fetch") + ) { + return { + ...link, + status: "broken", + reason: "Network error or unreachable", + }; + } + + // For other errors, assume CORS restrictions but link might be valid + return { + ...link, + status: "warning", + reason: "CORS restricted (unable to verify)", + }; + } + } catch (error) { + return { ...link, status: "broken", reason: error.message }; + } + }; + + // Function to open file in CMS editor + const openInCMS = (filePath) => { + // Extract relative path from full path + const relativePath = filePath + .replace(/^\/docs\//, "") + .replace(/\.mdx?$/i, ""); + const cmsUrl = `/admin/index.html#/collections/edit/doc/${encodeURIComponent(relativePath)}`; + window.open(cmsUrl, "_blank"); + }; + + // Function to scan docs directory for MDX files using GraphQL + const scanDocsForLinks = async () => { + setLoading(true); + setError(null); + + try { + // Import the Tina client + const { client } = await import("../../../tina/__generated__/client"); + + // Fetch all docs from the main collection + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + + const docs = docsResult.data.docConnection.edges || []; + + const allLinks = []; + const fileStats = {}; + + // Process each document + for (const edge of docs) { + const node = edge.node; + const fileName = `${node._sys.filename}.mdx`; + const filePath = `/docs/${node._sys.relativePath}`; + + // Get the document body content + let content = ""; + if (node.body) { + // Extract text content from rich text blocks + content = extractTextFromBody(node.body); + } + + // Add title content if available + if (node.title) { + content = `# ${node.title}\n\n${content}`; + } + + const links = extractLinksFromContent(content, filePath); + + fileStats[filePath] = { + totalLinks: links.length, + fileName: fileName, + title: node.title || node._sys.filename, + relativePath: node._sys.relativePath, + }; + + allLinks.push(...links); + } + + // Validate all links + const validatedLinks = []; + for (const link of allLinks) { + const validatedLink = await validateLink(link); + validatedLinks.push(validatedLink); + } + + // Calculate statistics + const stats = validatedLinks.reduce( + (acc, link) => { + acc.total++; + if (link.status === "valid") acc.valid++; + else if (link.status === "broken") acc.broken++; + else if (link.status === "warning") acc.warning++; + else if (link.status === "skipped") acc.skipped++; + return acc; + }, + { total: 0, valid: 0, broken: 0, warning: 0, skipped: 0 } + ); + + // Group by file + const linksByFile = {}; + for (const link of validatedLinks) { + const fileName = link.filePath.split("/").pop(); + if (!linksByFile[fileName]) { + linksByFile[fileName] = []; + } + linksByFile[fileName].push(link); + } + + setLinkData({ + stats, + fileStats, + linksByFile, + allLinks: validatedLinks, + brokenLinks: validatedLinks.filter((link) => link.status === "broken"), + warningLinks: validatedLinks.filter( + (link) => link.status === "warning" + ), + timestamp: new Date().toISOString(), + }); + } catch (error) { + setError(error.message); + } finally { + setLoading(false); + } + }; + + // Function to extract text content from Tina CMS rich text body + const extractTextFromBody = (body) => { + if (!body?.children) return ""; + + const extractFromChildren = (children) => { + return children + .map((child) => { + if (child.type === "text") { + return child.text || ""; + } + if (child.type === "a" && child.url) { + const text = child.children + ? extractFromChildren(child.children) + : ""; + return `[${text}](${child.url})`; + } + if (child.children) { + return extractFromChildren(child.children); + } + return ""; + }) + .join(""); + }; + + return extractFromChildren(body.children); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!linkData && !loading && !error) { + return ( +
    +
    +
    + + + + + + + +

    + Broken Links Dashboard +

    +
    + +
    +
    + ); + } + + if (loading) { + return ( +
    +
    +
    + Loading Dashboard +
    +
    + Scanning docs for links and validating... +
    + + {/* Progress Bar for Loading */} +
    +
    +
    +
    + +
    + ); + } + + if (error) { + return ( +
    +
    +
    + + + + + + Error +
    +
    {error}
    + +
    +
    + ); + } + + if (!linkData) { + return ( +
    + No data available +
    + ); + } + + const { stats, fileStats, linksByFile, brokenLinks, warningLinks } = linkData; + const problemLinks = [...(brokenLinks || []), ...(warningLinks || [])]; + + return ( +
    +
    +
    + + + + + + + +

    + Broken Links Dashboard +

    +
    + +
    + + {/* Statistics Cards */} +
    +
    +
    + + + + +
    +
    +

    Total Links

    +

    {stats.total}

    +
    +
    + +
    +
    + + + +
    +
    +

    Valid Links

    +

    {stats.valid}

    +
    +
    + +
    +
    + + + + +
    +
    +

    Broken Links

    +

    {stats.broken}

    +
    +
    + +
    +
    + + + + + +
    +
    +

    Warning Links

    +

    + {stats.warning || 0} +

    +
    +
    + +
    +
    + + + + +
    +
    +

    Files Scanned

    +

    + {Object.keys(fileStats).length} +

    +
    +
    +
    + + {/* Broken Links Section */} + {problemLinks.length > 0 && ( +
    +

    + 🚨 Problem Links ({problemLinks.length}) +

    +
    + {problemLinks.map((link, index) => ( +
    + + +
    + ))} +
    +
    + )} + + {/* Files with Broken Links */} + {(() => { + const filesWithProblemLinks = Object.entries(fileStats).filter( + ([_filePath, stats]) => { + const fileName = stats.fileName; + const fileLinks = linksByFile[fileName] || []; + return fileLinks.some( + (link) => link.status === "broken" || link.status === "warning" + ); + } + ); + + if (filesWithProblemLinks.length === 0) { + return null; + } + + return ( +
    +
    +

    + + + + + Files with Problem Links ({filesWithProblemLinks.length}) +

    + +
    + +
    + {filesWithProblemLinks + .slice(0, showDetails ? undefined : 5) + .map(([filePath, stats], index) => { + const fileName = stats.fileName; + const fileLinks = linksByFile[fileName] || []; + const brokenCount = fileLinks.filter( + (link) => link.status === "broken" + ).length; + const warningCount = fileLinks.filter( + (link) => link.status === "warning" + ).length; + const totalProblems = brokenCount + warningCount; + + return ( +
    0 ? "#fff5f5" : "#fff8f0", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + }} + > +
    +
    + {stats.title || fileName} +
    +
    + {stats.totalLinks} total links • {totalProblems}{" "} + problem{totalProblems !== 1 ? "s" : ""} + {brokenCount > 0 && ( + + ({brokenCount} broken + {warningCount > 0 + ? `, ${warningCount} warning` + : ""} + ) + + )} + {brokenCount === 0 && warningCount > 0 && ( + + ({warningCount} warning) + + )} +
    +
    + +
    + ); + })} +
    + + {!showDetails && filesWithProblemLinks.length > 5 && ( +
    + And {filesWithProblemLinks.length - 5} more files... +
    + )} +
    + ); + })()} + + {/* Health Status */} +
    +
    + + {stats.broken === 0 && (stats.warning || 0) === 0 ? ( + <> + + + + All Links Valid! + + ) : stats.broken === 0 ? ( + <> + + + + + + {stats.warning} Warning Links + + ) : ( + <> + + + + + {stats.broken} Broken Links + {(stats.warning || 0) > 0 + ? ` and ${stats.warning} Warnings` + : ""} + + )} + +
    +
    + Link validation completed on {new Date().toLocaleString()} +
    +
    +
    + ); +}; + +export default BrokenLinksDashboard; diff --git a/template/src/components/Dashboard/ContentReuseDashboard.jsx b/template/src/components/Dashboard/ContentReuseDashboard.jsx index cfe9d41e..b33af0cd 100644 --- a/template/src/components/Dashboard/ContentReuseDashboard.jsx +++ b/template/src/components/Dashboard/ContentReuseDashboard.jsx @@ -5,41 +5,58 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useEffect, useState } from 'react'; -import { client } from '../../../tina/__generated__/client'; +import React, { useState } from "react"; +import { client } from "../../../tina/__generated__/client"; // --- AST utilities --- function extractPlainText(node) { - if (!node || typeof node !== 'object') return ''; - if (typeof node.text === 'string') return node.text; - if (Array.isArray(node)) return node.map(extractPlainText).filter(Boolean).join(' '); - if (Array.isArray(node.children)) return node.children.map(extractPlainText).filter(Boolean).join(' '); - return ''; + if (!node || typeof node !== "object") return ""; + if (typeof node.text === "string") return node.text; + if (Array.isArray(node)) + return node.map(extractPlainText).filter(Boolean).join(" "); + if (Array.isArray(node.children)) + return node.children.map(extractPlainText).filter(Boolean).join(" "); + return ""; } function extractInlineCode(node, results = []) { - if (!node || typeof node !== 'object') return results; - if (Array.isArray(node)) { node.forEach(n => extractInlineCode(n, results)); return results; } - if (node.name === 'CodeSnippet') return results; // already a proper snippet - if (node.code === true && typeof node.text === 'string' && node.text.trim().length > 1) { + if (!node || typeof node !== "object") return results; + if (Array.isArray(node)) { + for (const n of node) extractInlineCode(n, results); + return results; + } + if (node.name === "CodeSnippet") return results; // already a proper snippet + if ( + node.code === true && + typeof node.text === "string" && + node.text.trim().length > 1 + ) { results.push(node.text.trim()); } - if ((node.type === 'code_block' || node.type === 'code') && typeof node.value === 'string' && node.value.trim()) { + if ( + (node.type === "code_block" || node.type === "code") && + typeof node.value === "string" && + node.value.trim() + ) { results.push(node.value.trim()); } - if (Array.isArray(node.children)) node.children.forEach(c => extractInlineCode(c, results)); + if (Array.isArray(node.children)) + for (const c of node.children) extractInlineCode(c, results); return results; } function extractParagraphTexts(node, results = []) { - if (!node || typeof node !== 'object') return results; - if (Array.isArray(node)) { node.forEach(n => extractParagraphTexts(n, results)); return results; } - if (node.type === 'p' || node.type === 'paragraph') { + if (!node || typeof node !== "object") return results; + if (Array.isArray(node)) { + for (const n of node) extractParagraphTexts(n, results); + return results; + } + if (node.type === "p" || node.type === "paragraph") { const text = extractPlainText(node).trim(); if (text.length >= 60) results.push(text); } else if (Array.isArray(node.children)) { - node.children.forEach(c => extractParagraphTexts(c, results)); + for (const c of node.children) extractParagraphTexts(c, results); } return results; } @@ -56,7 +73,7 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { } const codeSnippets = Object.entries(codeValueMap) .map(([value, paths]) => ({ value, paths })) - .filter(s => s.value.length > 2) + .filter((s) => s.value.length > 2) .sort((a, b) => b.paths.length - a.paths.length); // 2. Glossary terms appearing as plain text (not via GlossaryTerm component) @@ -66,9 +83,19 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { const plainPaths = []; for (const { path, body } of docBodies) { if (!body || term.usedIn.includes(path)) continue; - if (extractPlainText(body).toLowerCase().includes(term.termText.toLowerCase())) plainPaths.push(path); + if ( + extractPlainText(body) + .toLowerCase() + .includes(term.termText.toLowerCase()) + ) + plainPaths.push(path); } - if (plainPaths.length > 0) termText.push({ key: term.key, termText: term.termText, paths: plainPaths }); + if (plainPaths.length > 0) + termText.push({ + key: term.key, + termText: term.termText, + paths: plainPaths, + }); } // 3. Text blocks appearing in 2+ docs that could be snippets @@ -76,9 +103,11 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { for (const { path, body } of docBodies) { if (!body) continue; for (const para of extractParagraphTexts(body)) { - const normalized = para.trim().toLowerCase().replace(/\s+/g, ' '); - if (!paraMap[normalized]) paraMap[normalized] = { original: para, paths: [] }; - if (!paraMap[normalized].paths.includes(path)) paraMap[normalized].paths.push(path); + const normalized = para.trim().toLowerCase().replace(/\s+/g, " "); + if (!paraMap[normalized]) + paraMap[normalized] = { original: para, paths: [] }; + if (!paraMap[normalized].paths.includes(path)) + paraMap[normalized].paths.push(path); } } const duplicateText = Object.values(paraMap) @@ -88,16 +117,27 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { // 4. Variable values appearing as plain text (not via VariableSet component) const variables = []; for (const vs of variableSetsData) { - for (const variable of (vs.variableItems || [])) { - for (const translation of (variable.translations || [])) { - if (translation.lang !== 'en' || !translation.value || translation.value.length < 3) continue; + for (const variable of vs.variableItems || []) { + for (const translation of variable.translations || []) { + if ( + translation.lang !== "en" || + !translation.value || + translation.value.length < 3 + ) + continue; const value = translation.value; const plainPaths = []; for (const { path, body } of docBodies) { if (!body) continue; if (extractPlainText(body).includes(value)) plainPaths.push(path); } - if (plainPaths.length > 0) variables.push({ setName: vs.name, key: variable.key, value, paths: plainPaths }); + if (plainPaths.length > 0) + variables.push({ + setName: vs.name, + key: variable.key, + value, + paths: plainPaths, + }); } } } @@ -108,245 +148,455 @@ function computeSuggestions(docBodies, glossaryTermsData, variableSetsData) { // --- Data fetching --- async function fetchReuseData() { - const glossaryConn = await client.queries.glossaryTermsConnection({ first: 100 }); - const variableSetsConn = await client.queries.variableSetsConnection({ first: 100 }); + const glossaryConn = await client.queries.glossaryTermsConnection({ + first: 100, + }); + const variableSetsConn = await client.queries.variableSetsConnection({ + first: 100, + }); let snippets = []; if (client.queries.snippetsConnection) { - const snippetsConn = await client.queries.snippetsConnection({ first: 100 }); - snippets = (snippetsConn.data?.snippetsConnection?.edges || []).map(edge => ({ - name: edge.node._sys?.filename, - path: edge.node._sys?.relativePath, - description: edge.node.description || '' - })); + const snippetsConn = await client.queries.snippetsConnection({ + first: 100, + }); + snippets = (snippetsConn.data?.snippetsConnection?.edges || []).map( + (edge) => ({ + name: edge.node._sys?.filename, + path: edge.node._sys?.relativePath, + description: edge.node.description || "", + }) + ); } else { - snippets = [{ name: 'example.mdx', path: 'reuse/snippets/example.mdx', description: 'Snippets Example' }]; + snippets = [ + { + name: "example.mdx", + path: "reuse/snippets/example.mdx", + description: "Snippets Example", + }, + ]; } - const codeSnippets = [{ name: 'example.xml', path: 'reuse/code/example.xml' }]; + const codeSnippets = [ + { name: "example.xml", path: "reuse/code/example.xml" }, + ]; const docsResult = await client.queries.docConnection({ first: 1000 }); const docs = docsResult.data?.docConnection?.edges || []; const docBodies = docs.map((edge) => ({ path: edge.node._sys?.relativePath || edge.node._sys?.filename, - body: edge.node.body || null + body: edge.node.body || null, })); function bodyContainsComponent(node, componentName, propName, matchFn) { - if (!node || typeof node !== 'object') return false; - if (Array.isArray(node)) return node.some(n => bodyContainsComponent(n, componentName, propName, matchFn)); + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) + return node.some((n) => + bodyContainsComponent(n, componentName, propName, matchFn) + ); if (node.name === componentName && node.props) { const val = node.props[propName]; if (matchFn(val)) return true; } if (Array.isArray(node.children)) { - return node.children.some(child => bodyContainsComponent(child, componentName, propName, matchFn)); + return node.children.some((child) => + bodyContainsComponent(child, componentName, propName, matchFn) + ); } return false; } function findComponentUsage(componentName, propName, matchFn) { return docBodies - .filter(({ body }) => bodyContainsComponent(body, componentName, propName, matchFn)) + .filter(({ body }) => + bodyContainsComponent(body, componentName, propName, matchFn) + ) .map(({ path }) => path); } - const glossaryTermsData = (glossaryConn.data?.glossaryTermsConnection?.edges || []).map((edge) => { + const glossaryTermsData = ( + glossaryConn.data?.glossaryTermsConnection?.edges || [] + ).map((edge) => { const item = edge.node.glossaryTerms?.[0] || edge.node; return { key: item.key, - termText: item.translations?.find(t => t.lang === 'en')?.term || item.key, - definition: item.translations?.[0]?.definition || '', - usedIn: findComponentUsage('GlossaryTerm', 'termKey', (val) => val === item.key) + termText: + item.translations?.find((t) => t.lang === "en")?.term || item.key, + definition: item.translations?.[0]?.definition || "", + usedIn: findComponentUsage( + "GlossaryTerm", + "termKey", + (val) => val === item.key + ), }; }); - const variableSetsData = (variableSetsConn.data?.variableSetsConnection?.edges || []).map((edge) => { + const variableSetsData = ( + variableSetsConn.data?.variableSetsConnection?.edges || [] + ).map((edge) => { const item = edge.node.variableSets?.[0] || edge.node; return { name: item.name, variables: item.variables?.length || 0, variableItems: item.variables || [], - usedIn: findComponentUsage('VariableSet', 'variableSelection', (val) => typeof val === 'string' && (val === item.name || val.startsWith(item.name + '_'))) + usedIn: findComponentUsage( + "VariableSet", + "variableSelection", + (val) => + typeof val === "string" && + (val === item.name || val.startsWith(`${item.name}_`)) + ), }; }); - const suggestions = computeSuggestions(docBodies, glossaryTermsData, variableSetsData); + const suggestions = computeSuggestions( + docBodies, + glossaryTermsData, + variableSetsData + ); return { codeSnippets: codeSnippets.map((item) => ({ ...item, - usedIn: findComponentUsage('CodeSnippet', 'filepath', (val) => typeof val === 'string' && val.includes(item.name)) + usedIn: findComponentUsage( + "CodeSnippet", + "filepath", + (val) => typeof val === "string" && val.includes(item.name) + ), })), glossaryTerms: glossaryTermsData, snippets: snippets.map((item) => ({ ...item, - usedIn: findComponentUsage('Snippet', 'filepath', (val) => typeof val === 'string' && val.includes(item.name)) + usedIn: findComponentUsage( + "Snippet", + "filepath", + (val) => typeof val === "string" && val.includes(item.name) + ), })), variableSets: variableSetsData, - suggestions + suggestions, }; } // --- UI helpers --- const getEditUrl = (relativePath) => { - const clean = relativePath.replace(/\.(mdx?|md)$/, ''); + const clean = relativePath.replace(/\.(mdx?|md)$/, ""); return `/admin/index.html#/collections/edit/doc/${clean}`; }; const CATEGORIES = [ { - type: 'codeSnippets', - label: 'Code Snippets', - color: '#3b82f6', - bgClass: 'bg-blue-100', + type: "codeSnippets", + label: "Code Snippets", + color: "#3b82f6", + bgClass: "bg-blue-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'glossaryTerms', - label: 'Glossary Terms', - color: '#10b981', - bgClass: 'bg-green-100', + type: "glossaryTerms", + label: "Glossary Terms", + color: "#10b981", + bgClass: "bg-green-100", icon: ( - - + + ), sectionIcon: ( - - + + - ) + ), }, { - type: 'snippets', - label: 'Snippets', - color: '#f59e0b', - bgClass: 'bg-orange-100', + type: "snippets", + label: "Snippets", + color: "#f59e0b", + bgClass: "bg-orange-100", icon: ( - - - - - - - + + + + + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'variableSets', - label: 'Variable Sets', - color: '#8b5cf6', - bgClass: 'bg-purple-100', + type: "variableSets", + label: "Variable Sets", + color: "#8b5cf6", + bgClass: "bg-purple-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) - } + ), + }, ]; const SUGGESTION_CATEGORIES = [ { - type: 'codeSnippets', - label: 'Possible Snippets', - description: 'Inline code blocks that could become snippets', - color: '#3b82f6', - bgClass: 'bg-blue-100', + type: "codeSnippets", + label: "Possible Snippets", + description: "Inline code blocks that could become snippets", + color: "#3b82f6", + bgClass: "bg-blue-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'termText', - label: 'Possible Terms', - description: 'Plain text glossary terms', - color: '#10b981', - bgClass: 'bg-green-100', + type: "termText", + label: "Possible Terms", + description: "Plain text glossary terms", + color: "#10b981", + bgClass: "bg-green-100", icon: ( - - + + ), sectionIcon: ( - - + + - ) + ), }, { - type: 'duplicateText', - label: 'Possible Snippets', - description: 'Text blocks appearing in two or more topics', - color: '#f59e0b', - bgClass: 'bg-orange-100', + type: "duplicateText", + label: "Possible Snippets", + description: "Text blocks appearing in two or more topics", + color: "#f59e0b", + bgClass: "bg-orange-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) + ), }, { - type: 'variables', - label: 'Possible Variables', - description: 'Plain text variable values', - color: '#8b5cf6', - bgClass: 'bg-purple-100', + type: "variables", + label: "Possible Variables", + description: "Plain text variable values", + color: "#8b5cf6", + bgClass: "bg-purple-100", icon: ( - - - + + + ), sectionIcon: ( - - - + + + - ) - } + ), + }, ]; // --- Component --- @@ -367,56 +617,105 @@ const ContentReuseDashboard = () => { setLoading(false); }) .catch((err) => { - setError(err.message || 'Failed to load content reuse data'); + setError(err.message || "Failed to load content reuse data"); setLoading(false); }); }; const headerButtons = (label) => ( ); const dashboardHeader = ( -
    -
    +
    +
    - - - - - + + + + + -

    Content Reuse Dashboard

    +

    + Content Reuse Dashboard +

    - {headerButtons(loading ? 'Loading...' : reuseData ? 'Refresh' : 'Load')} + {headerButtons(loading ? "Loading..." : reuseData ? "Refresh" : "Load")}
    ); if (!reuseData && !loading && !error) { return ( -
    +
    {dashboardHeader}
    ); @@ -424,27 +723,51 @@ const ContentReuseDashboard = () => { if (loading) { return ( -
    -
    -
    Loading Dashboard
    -
    Loading content reuse data...
    -
    -
    +
    +
    +
    + Loading Dashboard +
    +
    + Loading content reuse data... +
    +
    +
    -
    - ); - } - - if (!contentData && !loading) { - return ( -
    -
    -
    - - - - - - - - - -

    Content Overview Dashboard

    -
    - -
    - {error && ( -
    - Error: {error} -
    - )} -
    - ); - } - - const StatCard = ({ title, count, total, color, percentage, onClick }) => { - const getStatusIcon = (status) => { - const icons = { - 'Draft': ( - - - - - - - ), - 'Review': ( - - - - - ), - 'Translate': ( - - - - - - ), - 'Approved': ( - - - - - - - - ), - 'Published': ( - - - - - - - ), - 'Unlisted': ( - - - - - ) - }; - return icons[status] || icons['Draft']; - }; - - const getBackgroundColor = (status) => { - const backgrounds = { - 'Draft': 'bg-orange-100', - 'Review': 'bg-blue-100', - 'Translate': 'bg-purple-100', - 'Approved': 'bg-green-100', - 'Published': 'bg-emerald-100', - 'Unlisted': 'bg-gray-100' - }; - return backgrounds[status] || 'bg-gray-100'; - }; - - return ( -
    count > 0 && onClick && onClick(title)} - className={`bg-white rounded-xl border border-gray-200 shadow-sm flex items-center gap-4 p-6 transition-all duration-200 ${ - count > 0 ? 'cursor-pointer hover:shadow-md' : 'cursor-default opacity-60' - }`} - > -
    -
    {getStatusIcon(title)}
    -
    -
    -

    {title}

    -

    {count || 0}

    -

    - {isNaN(percentage) ? '0' : percentage.toFixed(0)}% of {total} -

    -
    -
    - ); - }; - - return ( -
    -
    -
    - - - - - - - - - -

    - Content Overview Dashboard -

    -
    -
    -
    - Overall Progress: {contentData.totalProgress}% -
    - -
    -
    - - {/* Documentation Workflow */} -
    -

    - - - - - - - Documentation ({contentData.docs.total} topics) -

    -
    - - - - - - -
    -
    - - {/* Document List Modal */} - {showDocuments && ( -
    -
    -
    -

    - - - - - {showDocuments} Documents ({filteredDocs.length}) -

    - -
    - -
    - {filteredDocs.length === 0 ? ( -
    - No documents found with {showDocuments.toLowerCase()} status -
    - ) : ( - filteredDocs.map((edge, index) => { - const doc = edge.node; - return ( -
    -
    -
    - {doc.title || doc._sys.filename} -
    -
    - {doc._sys.relativePath} -
    - {doc.description && ( -
    - {doc.description.length > 100 ? doc.description.substring(0, 100) + '...' : doc.description} -
    - )} -
    - -
    - - {getStatus(doc)} - - - - Edit - -
    -
    - ); - }) - )} -
    -
    -
    - )} - - {/* Recent Activity */} -
    -
    -

    - - - - Recent Activity -

    -
    - - -
    -
    -
    - {contentData.recentActivity.length === 0 ? ( -
    - No recent activity found for the selected time period -
    - ) : ( - contentData.recentActivity.map((item, index) => ( -
    -
    -
    - {item.title} -
    -
    - - {item.type} - - {item.path} -
    -
    -
    -
    - {item.status} -
    -
    - {new Date(item.lastModified).toLocaleDateString()} -
    - - Edit - -
    -
    - )) - )} -
    -
    - - {error && ( -
    - - - - - - - Some data may be simulated due to connection issues: {error} - -
    - )} -
    - ); -}; - -export default Dashboard1; \ No newline at end of file +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useCallback, useEffect, useRef, useState } from "react"; + +const getStatus = (node) => { + if (node.published) return "Published"; + if (node.approved) return "Approved"; + if (node.translate) return "Translate"; + if (node.review) return "Review"; + if (node.draft) return "Draft"; + if (node.unlisted) return "Unlisted"; + return "No Status"; +}; + +const Dashboard1 = () => { + const [contentData, setContentData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showDocuments, setShowDocuments] = useState(null); + const [filteredDocs, setFilteredDocs] = useState([]); + const [allDocs, setAllDocs] = useState([]); + const [activityLimit, setActivityLimit] = useState(10); + const [activityPeriod, setActivityPeriod] = useState("week"); // 'week', 'month', 'all' + + // Tracks whether the overview has been loaded at least once, so changing a + // filter refetches but mounting does not auto-load. Kept in a ref so the + // effect below doesn't have to depend on contentData (which the fetch sets, + // which would loop). + const hasLoadedRef = useRef(false); + + const fetchContentOverview = useCallback(async () => { + setLoading(true); + setError(null); + + try { + const { client } = await import("../../../tina/__generated__/client"); + + // Fetch all docs from main collection + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + + const docs = docsResult.data.docConnection.edges || []; + + // Store all docs for filtering + setAllDocs(docs); + + // Analyze workflow status for docs + const docStats = docs.reduce( + (acc, edge) => { + const node = edge.node; + acc.total++; + + if (node.draft) acc.draft++; + if (node.review) acc.review++; + if (node.translate) acc.translate++; + if (node.approved) acc.approved++; + if (node.published) acc.published++; + if (node.unlisted) acc.unlisted++; + + return acc; + }, + { + total: 0, + draft: 0, + review: 0, + translate: 0, + approved: 0, + published: 0, + unlisted: 0, + } + ); + + // Get recent activity with configurable filters + // Only include docs that have a lastmod field set + const now = new Date(); + const getTimePeriodFilter = () => { + if (activityPeriod === "week") { + return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); // 7 days ago + } else if (activityPeriod === "month") { + return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); // 30 days ago + } + return null; // No time filter for 'all' + }; + + const timeCutoff = getTimePeriodFilter(); + + const recentActivity = docs + .filter((edge) => { + const node = edge.node; + const _relativePath = node._sys.relativePath; + + // Skip documents without lastmod field + if (!node.lastmod) return false; + + // Apply time filter if specified + if (timeCutoff) { + const docDate = new Date(node.lastmod); + if (docDate < timeCutoff) return false; + } + + return true; + }) + .map((edge) => { + const node = edge.node; + // Use lastmod as primary source, with system lastModified as fallback + const timestamp = node.lastmod || node._sys?.lastModified; + + return { + title: node.title || node._sys.filename, + type: "Documentation", + status: getStatus(node), + lastModified: timestamp, + path: node._sys.relativePath, + // Debug info + debugInfo: { + sysLastModified: node._sys?.lastModified, + lastmod: node.lastmod, + filename: node._sys.filename, + }, + }; + }) + .sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified)) + .slice(0, activityLimit); + + setContentData({ + docs: docStats, + recentActivity, + totalProgress: + Math.round((docStats.published / docStats.total) * 100) || 0, + }); + } catch (err) { + setError(err.message); + } finally { + hasLoadedRef.current = true; + setLoading(false); + } + }, [activityLimit, activityPeriod]); + + const getStatusColor = (status) => { + const colors = { + "No Status": "#6b7280", + Draft: "#f59e0b", + Review: "#3b82f6", + Translate: "#8b5cf6", + Approved: "#10b981", + Published: "#059669", + Unlisted: "#6b7280", + }; + return colors[status] || "#6b7280"; + }; + + const filterDocumentsByStatus = (status) => { + const filtered = allDocs.filter((edge) => { + const node = edge.node; + switch (status.toLowerCase()) { + case "draft": + return node.draft; + case "review": + return node.review; + case "translate": + return node.translate; + case "approved": + return node.approved; + case "published": + return node.published; + case "unlisted": + return node.unlisted; + default: + return false; + } + }); + setFilteredDocs(filtered); + setShowDocuments(status); + }; + + const getEditUrl = (doc) => { + const isLocal = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; + const relativePath = doc._sys.relativePath; + + if (isLocal) { + // Local Tina admin URL + return `/admin/index.html#/collections/edit/doc/${relativePath.replace(".mdx", "").replace(".md", "")}`; + } else { + // Production Tina admin URL (TinaCloud) + return `/admin/index.html#/collections/edit/doc/${relativePath.replace(".mdx", "").replace(".md", "")}`; + } + }; + + // Refetch when the activity filters change (fetchContentOverview's identity + // changes with them), but not before the first load. + useEffect(() => { + if (!hasLoadedRef.current) return; + fetchContentOverview(); + }, [fetchContentOverview]); + + if (loading) { + return ( +
    +
    +
    + Loading Dashboard +
    +
    + Loading content overview... +
    + + {/* Progress Bar for Loading */} +
    +
    +
    +
    + +
    + ); + } + + if (!contentData && !loading) { + return ( +
    +
    +
    + + + + + + + + + +

    + Content Overview Dashboard +

    +
    + +
    + {error && ( +
    + Error: {error} +
    + )} +
    + ); + } + + const StatCard = ({ title, count, total, color, percentage, onClick }) => { + const getStatusIcon = (status) => { + const icons = { + Draft: ( + + + + + + + ), + Review: ( + + + + + ), + Translate: ( + + + + + + ), + Approved: ( + + + + + + + + ), + Published: ( + + + + + + + ), + Unlisted: ( + + + + + ), + }; + return icons[status] || icons.Draft; + }; + + const getBackgroundColor = (status) => { + const backgrounds = { + Draft: "bg-orange-100", + Review: "bg-blue-100", + Translate: "bg-purple-100", + Approved: "bg-green-100", + Published: "bg-emerald-100", + Unlisted: "bg-gray-100", + }; + return backgrounds[status] || "bg-gray-100"; + }; + + return ( + // biome-ignore lint/a11y/useSemanticElements: the card body is block content, which cannot legally nest inside a +
    +
    + + {/* Documentation Workflow */} +
    +

    + + + + + + + Documentation ({contentData.docs.total} topics) +

    +
    + + + + + + +
    +
    + + {/* Document List Modal */} + {showDocuments && ( +
    +
    +
    +

    + + + + + {showDocuments} Documents ({filteredDocs.length}) +

    + +
    + +
    + {filteredDocs.length === 0 ? ( +
    + No documents found with {showDocuments.toLowerCase()} status +
    + ) : ( + filteredDocs.map((edge, index) => { + const doc = edge.node; + return ( +
    +
    +
    + {doc.title || doc._sys.filename} +
    +
    + {doc._sys.relativePath} +
    + {doc.description && ( +
    + {doc.description.length > 100 + ? `${doc.description.substring(0, 100)}...` + : doc.description} +
    + )} +
    + +
    + + {getStatus(doc)} + + + + Edit + +
    +
    + ); + }) + )} +
    +
    +
    + )} + + {/* Recent Activity */} +
    +
    +

    + + + + Recent Activity +

    +
    + + +
    +
    +
    + {contentData.recentActivity.length === 0 ? ( +
    + No recent activity found for the selected time period +
    + ) : ( + contentData.recentActivity.map((item, index) => ( +
    +
    +
    + {item.title} +
    +
    + + {item.type} + + {item.path} +
    +
    +
    +
    + {item.status} +
    +
    + {new Date(item.lastModified).toLocaleDateString()} +
    + + Edit + +
    +
    + )) + )} +
    +
    + + {error && ( +
    + + + + + + + Some data may be simulated due to connection issues: {error} + +
    + )} +
    + ); +}; + +export default Dashboard1; diff --git a/template/src/components/Dashboard/DocumentMutationDashboard.jsx b/template/src/components/Dashboard/DocumentMutationDashboard.jsx index 2209aa3c..6423b693 100644 --- a/template/src/components/Dashboard/DocumentMutationDashboard.jsx +++ b/template/src/components/Dashboard/DocumentMutationDashboard.jsx @@ -5,27 +5,35 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useState } from 'react'; +import React, { useState } from "react"; const DocumentMutationDashboard = () => { - const [createTitle, setCreateTitle] = useState(''); - const [deleteId, setDeleteId] = useState(''); - const [updateId, setUpdateId] = useState(''); - const [updateTitle, setUpdateTitle] = useState(''); - const [status, setStatus] = useState(''); + const [createTitle, setCreateTitle] = useState(""); + const [deleteId, setDeleteId] = useState(""); + const [updateId, setUpdateId] = useState(""); + const [updateTitle, setUpdateTitle] = useState(""); + const [status, setStatus] = useState(""); const [documents, setDocuments] = useState([]); // Real mutation handlers // Use Tina client for GraphQL operations const handleListDocuments = async () => { - setStatus(''); + setStatus(""); setDocuments([]); try { - const { client } = await import('../../../tina/__generated__/client'); - const docsResult = await client.queries.docConnection({ sort: 'title', first: 500 }); + const { client } = await import("../../../tina/__generated__/client"); + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, + }); const docs = docsResult.data.docConnection.edges || []; - setDocuments(docs.map(edge => ({ id: edge.node._sys.filename, title: edge.node.title || edge.node._sys.filename }))); - setStatus('Listed documents'); + setDocuments( + docs.map((edge) => ({ + id: edge.node._sys.filename, + title: edge.node.title || edge.node._sys.filename, + })) + ); + setStatus("Listed documents"); } catch (err) { setStatus(`Error: ${err.message}`); setDocuments([]); @@ -33,9 +41,9 @@ const DocumentMutationDashboard = () => { }; const handleCreate = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation CreateDocument($collection: String!, $relativePath: String!, $params: DocumentMutation!) { createDocument(collection: $collection, relativePath: $relativePath, params: $params) { @@ -46,23 +54,23 @@ const DocumentMutationDashboard = () => { } } `; - const variables = { - collection: 'doc', - relativePath: `${createTitle.replace(/\s+/g, '-')}.mdx`, - params: { doc: { title: createTitle } } + const variables = { + collection: "doc", + relativePath: `${createTitle.replace(/\s+/g, "-")}.mdx`, + params: { doc: { title: createTitle } }, }; const result = await client.request({ query: mutation, variables }); setStatus(`Created document: ${result.data.createDocument.title}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setCreateTitle(''); + setCreateTitle(""); }; const handleDelete = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation DeleteDocument($collection: String!, $relativePath: String!) { deleteDocument(collection: $collection, relativePath: $relativePath) { @@ -73,21 +81,21 @@ const DocumentMutationDashboard = () => { } `; const variables = { - collection: 'doc', - relativePath: `${deleteId}.mdx` + collection: "doc", + relativePath: `${deleteId}.mdx`, }; await client.request({ query: mutation, variables }); setStatus(`Deleted document ID: ${deleteId}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setDeleteId(''); + setDeleteId(""); }; const handleUpdate = async () => { - setStatus(''); + setStatus(""); try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); const mutation = ` mutation UpdateDocument($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) { updateDocument(collection: $collection, relativePath: $relativePath, params: $params) { @@ -98,71 +106,94 @@ const DocumentMutationDashboard = () => { } } `; - const variables = { - collection: 'doc', - relativePath: `${updateId}.mdx`, - params: { doc: { title: updateTitle } } - }; + const variables = { + collection: "doc", + relativePath: `${updateId}.mdx`, + params: { doc: { title: updateTitle } }, + }; await client.request({ query: mutation, variables }); setStatus(`Updated document ID: ${updateId} with title: ${updateTitle}`); } catch (err) { setStatus(`Error: ${err.message}`); } - setUpdateId(''); - setUpdateTitle(''); + setUpdateId(""); + setUpdateTitle(""); }; return ( -
    +

    Document Mutation Dashboard

    -
    +

    Create Document

    setCreateTitle(e.target.value)} + onChange={(e) => setCreateTitle(e.target.value)} /> - +
    -
    +

    Delete Document

    setDeleteId(e.target.value)} + onChange={(e) => setDeleteId(e.target.value)} /> - +
    -
    +

    Update Document

    setUpdateId(e.target.value)} + onChange={(e) => setUpdateId(e.target.value)} /> setUpdateTitle(e.target.value)} + onChange={(e) => setUpdateTitle(e.target.value)} /> - +
    -
    +

    List Documents

    - + {documents.length > 0 && ( -
      - {documents.map(doc => ( -
    • {doc.title} ({doc.id})
    • +
        + {documents.map((doc) => ( +
      • + {doc.title} ({doc.id}) +
      • ))}
      )}
    - {status &&
    {status}
    } + {status && ( +
    {status}
    + )}
    ); }; diff --git a/template/src/components/Dashboard/GraphQLtest.jsx b/template/src/components/Dashboard/GraphQLtest.jsx index f67dd7fe..443e7708 100644 --- a/template/src/components/Dashboard/GraphQLtest.jsx +++ b/template/src/components/Dashboard/GraphQLtest.jsx @@ -7,69 +7,76 @@ // add this dashboard to template.jsx if you have GraphQL connection issues -import React, { useState, useEffect } from 'react'; -import docusaurusSettings from '../../../config/docusaurus/index.json'; +import React, { useCallback, useEffect, useRef, useState } from "react"; +import docusaurusSettings from "../../../config/docusaurus/index.json"; -const Dashboard3 = () => { +const GraphQLtest = () => { const [connectionTests, setConnectionTests] = useState([]); const [loading, setLoading] = useState(false); + // Concurrency guard: a ref rather than `loading` state, so testConnections + // keeps a stable identity and the effect below doesn't re-run on every toggle. + const runningRef = useRef(false); + + const testConnections = useCallback(async () => { + if (runningRef.current) return; // Prevent concurrent executions + runningRef.current = true; - const testConnections = async () => { - if (loading) return; // Prevent concurrent executions - setLoading(true); const tests = []; try { // Test 1: Try the original GraphQL endpoint try { - const response1 = await fetch('http://localhost:4001/graphql', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + const response1 = await fetch("http://localhost:4001/graphql", { + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - query: '{ __typename }' + query: "{ __typename }", }), }); tests.push({ - name: 'http://localhost:4001/graphql', - status: response1.ok ? 'SUCCESS' : `FAILED (${response1.status})`, - details: response1.ok ? 'Connected successfully' : `HTTP ${response1.status}`, - color: response1.ok ? '#059669' : '#dc2626' + name: "http://localhost:4001/graphql", + status: response1.ok ? "SUCCESS" : `FAILED (${response1.status})`, + details: response1.ok + ? "Connected successfully" + : `HTTP ${response1.status}`, + color: response1.ok ? "#059669" : "#dc2626", }); } catch (err) { tests.push({ - name: 'http://localhost:4001/graphql', - status: 'ERROR', + name: "http://localhost:4001/graphql", + status: "ERROR", details: err.message, - color: '#dc2626' + color: "#dc2626", }); } // Test 2: Check TinaCloud configuration try { const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - + if (!clientId) { tests.push({ - name: 'TinaCloud Configuration', - status: 'CONFIG ERROR', - details: 'NEXT_PUBLIC_TINA_CLIENT_ID is not set in environment variables', - color: '#f59e0b' + name: "TinaCloud Configuration", + status: "CONFIG ERROR", + details: + "NEXT_PUBLIC_TINA_CLIENT_ID is not set in environment variables", + color: "#f59e0b", }); } else { tests.push({ - name: 'TinaCloud Configuration', - status: 'CONFIGURED', + name: "TinaCloud Configuration", + status: "CONFIGURED", details: `Client ID configured. Note: TINA_TOKEN is server-side only (this is correct for security).`, - color: '#059669' + color: "#059669", }); } } catch (err) { tests.push({ - name: 'TinaCloud Configuration', - status: 'ERROR', + name: "TinaCloud Configuration", + status: "ERROR", details: `Error checking configuration: ${err.message}`, - color: '#dc2626' + color: "#dc2626", }); } @@ -77,60 +84,69 @@ const Dashboard3 = () => { try { const siteUrl = docusaurusSettings.url.siteUrl; const url = new URL(siteUrl); - + // According to Tina docs, the GraphQL API is at /admin/api/graphql const correctGraphQLUrl = `https://${url.hostname}/admin/api/graphql`; - + const response3 = await fetch(correctGraphQLUrl, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query: '{ __typename }' }), + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "{ __typename }" }), }); tests.push({ name: `Live Site GraphQL (${correctGraphQLUrl})`, - status: response3.ok ? 'SUCCESS' : response3.status === 405 ? 'SECURED āœ“' : `FAILED (${response3.status})`, - details: response3.ok - ? 'Connected to live site GraphQL' - : response3.status === 405 - ? 'šŸ”’ HTTP 405 - Site is properly secured. Direct GraphQL access blocked (this is correct!)' + status: response3.ok + ? "SUCCESS" + : response3.status === 405 + ? "SECURED āœ“" + : `FAILED (${response3.status})`, + details: response3.ok + ? "Connected to live site GraphQL" + : response3.status === 405 + ? "šŸ”’ HTTP 405 - Site is properly secured. Direct GraphQL access blocked (this is correct!)" : `HTTP ${response3.status} - This is normal for production sites`, - color: response3.ok ? '#059669' : response3.status === 405 ? '#059669' : '#f59e0b' + color: response3.ok + ? "#059669" + : response3.status === 405 + ? "#059669" + : "#f59e0b", }); - } catch (err) { + } catch (_err) { tests.push({ - name: 'Live Site GraphQL', - status: 'SECURED āœ“', - details: 'šŸ”’ Network blocked - Production sites properly block direct GraphQL access for security. Use TinaCMS Generated Client instead.', - color: '#059669' + name: "Live Site GraphQL", + status: "SECURED āœ“", + details: + "šŸ”’ Network blocked - Production sites properly block direct GraphQL access for security. Use TinaCMS Generated Client instead.", + color: "#059669", }); } // Test 4: Check if we can import the Tina client try { - const { client } = await import('../../../tina/__generated__/client'); + const { client } = await import("../../../tina/__generated__/client"); if (client) { tests.push({ - name: 'Tina Generated Client', - status: 'AVAILABLE', - details: 'Client imported successfully', - color: '#059669' + name: "Tina Generated Client", + status: "AVAILABLE", + details: "Client imported successfully", + color: "#059669", }); // Test 5: Try using the Tina client try { const result = await client.queries.docConnection(); tests.push({ - name: 'Tina Client Query', - status: 'SUCCESS', + name: "Tina Client Query", + status: "SUCCESS", details: `Found ${result.data.docConnection.edges.length} documents`, - color: '#059669' + color: "#059669", }); } catch (clientErr) { tests.push({ - name: 'Tina Client Query', - status: 'ERROR', + name: "Tina Client Query", + status: "ERROR", details: clientErr.message, - color: '#dc2626' + color: "#dc2626", }); } @@ -138,151 +154,180 @@ const Dashboard3 = () => { try { const docResult = await client.queries.docConnection({ first: 3, - sort: 'title' + sort: "title", }); - + const docs = docResult.data.docConnection.edges; - const sampleDocs = docs.slice(0, 3).map(edge => edge.node.title || edge.node._sys.filename).join(', '); - + const sampleDocs = docs + .slice(0, 3) + .map((edge) => edge.node.title || edge.node._sys.filename) + .join(", "); + // Determine data source based on environment - const isLocalDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; + const isLocalDev = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const dataSource = isLocalDev - ? 'Local files (localhost GraphQL server)' - : clientId - ? 'ā˜ļø TinaCloud (live site via content.tinajs.io)' - : 'ā“ Unknown source'; - + const dataSource = isLocalDev + ? "Local files (localhost GraphQL server)" + : clientId + ? "ā˜ļø TinaCloud (live site via content.tinajs.io)" + : "ā“ Unknown source"; + tests.push({ - name: 'Tina Admin Data Access', - status: 'SUCCESS', - details: `Retrieved ${docs.length} documents. Source: ${dataSource}. Sample: ${sampleDocs || 'No titles available'}`, - color: '#059669' + name: "Tina Admin Data Access", + status: "SUCCESS", + details: `Retrieved ${docs.length} documents. Source: ${dataSource}. Sample: ${sampleDocs || "No titles available"}`, + color: "#059669", }); // Test 7: Try to get a specific document if (docs.length > 0) { try { const firstDoc = docs[0].node; - const docQuery = await client.queries.doc({ - relativePath: firstDoc._sys.relativePath + const docQuery = await client.queries.doc({ + relativePath: firstDoc._sys.relativePath, }); - + tests.push({ - name: 'Tina Document Query', - status: 'SUCCESS', + name: "Tina Document Query", + status: "SUCCESS", details: `Successfully fetched full document: "${docQuery.data.doc.title || docQuery.data.doc._sys.filename}"`, - color: '#059669' + color: "#059669", }); } catch (docErr) { tests.push({ - name: 'Tina Document Query', - status: 'PARTIAL', + name: "Tina Document Query", + status: "PARTIAL", details: `Document list works but single doc query failed: ${docErr.message}`, - color: '#f59e0b' + color: "#f59e0b", }); } } } catch (dataErr) { tests.push({ - name: 'Tina Admin Data Access', - status: 'ERROR', + name: "Tina Admin Data Access", + status: "ERROR", details: `Failed to fetch documents from admin context: ${dataErr.message}`, - color: '#dc2626' + color: "#dc2626", }); } } } catch (err) { tests.push({ - name: 'Tina Generated Client', - status: 'NOT AVAILABLE', + name: "Tina Generated Client", + status: "NOT AVAILABLE", details: err.message, - color: '#f59e0b' + color: "#f59e0b", }); } // Test 8: Environment detection and context - const isLocalDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; - const isProduction = process.env.NODE_ENV === 'production'; + const isLocalDev = + window.location.hostname === "localhost" || + window.location.hostname === "127.0.0.1"; + const _isProduction = process.env.NODE_ENV === "production"; const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - + tests.push({ - name: 'Environment Detection', - status: 'INFO', - details: `${isLocalDev ? 'Local Development' : 'Cloud/Production'} | Node ENV: ${process.env.NODE_ENV} | Client ID: ${clientId ? 'Set' : 'Not Set'}`, - color: '#2563eb' + name: "Environment Detection", + status: "INFO", + details: `${isLocalDev ? "Local Development" : "Cloud/Production"} | Node ENV: ${process.env.NODE_ENV} | Client ID: ${clientId ? "Set" : "Not Set"}`, + color: "#2563eb", }); setConnectionTests(tests); } catch (globalErr) { - console.error('Global test error:', globalErr); - setConnectionTests([{ - name: 'Global Error', - status: 'ERROR', - details: globalErr.message, - color: '#dc2626' - }]); + setConnectionTests([ + { + name: "Global Error", + status: "ERROR", + details: globalErr.message, + color: "#dc2626", + }, + ]); } finally { + runningRef.current = false; setLoading(false); } - }; + }, []); useEffect(() => { testConnections(); - }, []); + }, [testConnections]); return ( -
    -
    -

    šŸ”Œ GraphQL Connection Test

    -
    - -
    + +
    {connectionTests.map((test, index) => ( -
    -
    -
    {test.name}
    -
    +
    +
    + {test.name} +
    +
    {test.status}
    -
    +
    {test.details}
    @@ -290,11 +335,13 @@ const Dashboard3 = () => {
    {loading && ( -
    +
    Running connection tests...
    )} @@ -302,4 +349,4 @@ const Dashboard3 = () => { ); }; -export default GraphQLtest; \ No newline at end of file +export default GraphQLtest; diff --git a/template/src/components/Dashboard/MediaDashboard.jsx b/template/src/components/Dashboard/MediaDashboard.jsx index 03a4bdd9..662c933f 100644 --- a/template/src/components/Dashboard/MediaDashboard.jsx +++ b/template/src/components/Dashboard/MediaDashboard.jsx @@ -1,822 +1,1054 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const MediaDashboard = () => { - const [mediaData, setMediaData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [mediaFiles, setMediaFiles] = useState([]); - const [filterType, setFilterType] = useState('all'); - const [imageUsages, setImageUsages] = useState({}); - const [expandedFile, setExpandedFile] = useState(null); - const [lightboxImage, setLightboxImage] = useState(null); - - // Helper: get extension from filename - const getExtension = (filename) => { - const match = filename.match(/\.([^.]+)$/); - return match ? match[1].toLowerCase() : ''; - }; - - // Helper: guess type from extension - const getType = (filename) => { - const ext = getExtension(filename); - if (["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "tiff", "ico", "avif"].includes(ext)) return "image"; - if (["mp4", "webm", "mov", "avi", "mkv"].includes(ext)) return "video"; - if (["mp3", "wav", "ogg", "flac"].includes(ext)) return "audio"; - return "file"; - }; - - const openLightbox = (file) => { - setLightboxImage(file); - }; - - const closeLightbox = () => { - setLightboxImage(null); - }; - - const extractTextFromAST = (node) => { - if (!node) return ''; - - let text = ''; - - if (typeof node === 'string') { - return node; - } - - if (typeof node === 'object') { - // Handle different node types - if (node.type === 'text' && node.value) { - text += node.value; - } - - // Handle nodes with props (like Figure components) - if (node.props) { - // Extract props as text for searching - text += JSON.stringify(node.props); - } - - // Handle JSX elements - if (node.type === 'element' && node.props) { - text += JSON.stringify(node.props); - } - - // Handle MDX JSX elements - if (node.name === 'Figure' && node.props) { - text += JSON.stringify(node.props); - } - - // Recursively process children - if (node.children && Array.isArray(node.children)) { - for (const child of node.children) { - text += extractTextFromAST(child); - } - } - - // Handle other array-like structures - if (Array.isArray(node)) { - for (const item of node) { - text += extractTextFromAST(item); - } - } - } - - return text; - }; - - const scanDocumentsForImageUsage = async (mediaFiles) => { - try { - const { client } = await import('../../../tina/__generated__/client'); - // Fetch all documents to scan for image usage using connection query - const docsResult = await client.queries.docConnection({ - sort: 'title', - first: 500 // Request more documents - }); - const docs = docsResult.data.docConnection.edges || []; - const usages = {}; - mediaFiles.forEach(file => { usages[file.path] = []; }); - docs.forEach(edge => { - const node = edge.node; - const title = node.title || node._sys.filename; - const relativePath = node._sys.relativePath; - let content = ''; - if (node.body && typeof node.body === 'object') { - content = extractTextFromAST(node.body); - } else if (typeof node.body === 'string') { - content = node.body; - } - if (content && (relativePath.includes('figures.mdx') || relativePath.includes('assets.mdx'))) { - console.log(`Main scan - ${relativePath}, content length: ${content.length}`); - } - mediaFiles.forEach(file => { - if (content.includes(file.filename) || content.includes(file.path)) { - usages[file.path].push({ - title, - relativePath, - filename: node._sys.filename, - lastModified: node.lastmod || node._sys?.lastModified, - editUrl: `/admin/#/collections/edit/doc/${relativePath.replace(/\.[^/.]+$/, '')}` - }); - } - }); - }); - setImageUsages(usages); - return usages; - } catch (err) { - console.error('Error scanning documents for image usage:', err); - return {}; - } - }; - - const fetchMediaFiles = async () => { - setLoading(true); - setError(null); - try { - const { client } = await import('../../../tina/__generated__/client'); - // Query Tina's MediaCollection (reuse/media/index.json) - const mediaResult = await client.queries.media({ relativePath: "index.json" }); - const mediaList = (mediaResult?.data?.media?.media) || []; - // Add type, extension, url, and name fields for UI compatibility - const files = mediaList.map((file) => { - const ext = getExtension(file.filename); - const type = getType(file.filename); - // Use file.path for correct subfolder support - const url = `/img/${file.path}`; - return { - ...file, - name: file.filename, - extension: ext, - type, - url, - lastModified: file.lastModified || '', - dimensions: file.dimensions || '', - }; - }); - setMediaFiles(files); - const mediaStats = { - total: files.length, - images: files.filter(f => f.type === 'image').length, - totalSize: files.reduce((acc, file) => acc + (typeof file.size === 'number' ? file.size / 1024 : 0), 0), - }; - setMediaData({ - files, - stats: mediaStats - }); - await scanDocumentsForImageUsage(files); - } catch (err) { - console.error('Error fetching media files:', err); - setError('Failed to load media files from Tina MediaCollection.'); - } finally { - setLoading(false); - } - }; - - - - const getFilteredFiles = () => { - if (filterType === 'all') return mediaFiles; - return mediaFiles.filter(file => { - switch (filterType) { - case 'images': - return file.type === 'image'; - case 'recent': - const oneWeekAgo = new Date(); - oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); - return new Date(file.lastModified) > oneWeekAgo; - case 'used': - return (imageUsages[file.path] || []).length > 0; - case 'unused': - return (imageUsages[file.path] || []).length === 0; - default: - return true; - } - }); - }; - - const formatFileSize = (size) => { - // size is in bytes (number) - if (typeof size !== 'number') return size; - if (size >= 1024 * 1024) { - return `${(size / (1024 * 1024)).toFixed(1)} MB`; - } - if (size >= 1024) { - return `${(size / 1024).toFixed(1)} KB`; - } - return `${size} B`; - }; - - const formatDate = (dateStr) => { - return new Date(dateStr).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric' - }); - }; - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!mediaData && !loading && !error) { - return ( -
    -
    -
    - - - - - - - -

    - Media Usage Dashboard -

    -
    - -
    -
    - ); - } - - if (loading) { - return ( -
    -
    -
    - Loading Dashboard -
    -
    - Loading media files... -
    - - {/* Progress Bar for Loading */} -
    -
    -
    -
    - -
    - ); - } - - if (error) { - return ( -
    -
    -

    Error

    -

    {error}

    -
    -
    - ); - } - - if (!mediaData) { - return null; - } - - const filteredFiles = getFilteredFiles(); - - return ( -
    - {/* Header */} -
    -
    -
    - - - - - - - -

    - Media Usage Dashboard -

    -
    - -
    - - {/* Media Statistics Cards */} -
    -
    -
    - - - - -
    -
    -

    Total Files

    -

    {mediaData.stats.total}

    -
    -
    - -
    -
    - - - - - -
    -
    -

    Images

    -

    {mediaData.stats.images}

    -
    -
    - -
    -
    - - - -
    -
    -

    Used

    -

    {Object.values(imageUsages).filter(usages => usages.length > 0).length}

    -
    -
    - -
    -
    - - - - -
    -
    -

    Unused

    -

    {Object.values(imageUsages).filter(usages => usages.length === 0).length}

    -
    -
    - -
    -
    - - - - -
    -
    -

    Total Size

    -

    {mediaData.stats.totalSize.toFixed(1)} KB

    -
    -
    -
    - - {/* Filter Controls */} -
    - Filter: - {['all', 'images', 'recent', 'used', 'unused'].map((filter) => ( - - ))} -
    -
    - - {/* Media Files List */} -
    - {filteredFiles.length === 0 ? ( -
    -

    No media files found for the current filter.

    -
    - ) : ( -
    - {filteredFiles.map((file, index) => ( -
    { - e.currentTarget.style.backgroundColor = '#f6f8fa'; - e.currentTarget.style.borderColor = '#8c959f'; - }} - onMouseLeave={(e) => { - e.currentTarget.style.backgroundColor = '#ffffff'; - e.currentTarget.style.borderColor = '#d1d9e0'; - }} - > - {/* File preview */} -
    - {file.type === 'image' ? ( - {file.filename} openLightbox(file)} - onError={(e) => { - e.target.style.display = 'none'; - e.target.nextSibling.style.display = 'flex'; - }} - onMouseOver={(e) => e.target.style.opacity = '0.8'} - onMouseOut={(e) => e.target.style.opacity = '1'} - /> - ) : null} -
    - {file.extension ? file.extension.toUpperCase() : ''} -
    -
    - - {/* File details */} -
    -
    - {file.filename} -
    -
    - {file.path} -
    -
    - {formatFileSize(file.size)} - {file.extension === 'svg' ? ( - vector - ) : ( - file.dimensions && {file.dimensions} - )} - {file.lastModified && Modified: {formatDate(file.lastModified)}} -
    -
    - - {/* Actions */} -
    - -
    - - {/* Usage Details - Expandable */} - {expandedFile === file.path && ( -
    -

    - Used in {(imageUsages[file.path] || []).length} document{(imageUsages[file.path] || []).length !== 1 ? 's' : ''}: -

    - - {(imageUsages[file.path] || []).length === 0 ? ( -

    - This image is not currently used in any documents. -

    - ) : ( -
    - {(imageUsages[file.path] || []).map((usage, usageIndex) => ( -
    -
    -
    - {usage.title} -
    -
    - {usage.relativePath} - {usage.lastModified && ( - • Modified: {formatDate(usage.lastModified)} - )} -
    -
    - e.target.style.backgroundColor = '#d97706'} - onMouseOut={(e) => e.target.style.backgroundColor = '#f59e0b'} - > - Edit - -
    - ))} -
    - )} -
    - )} -
    - ))} -
    - )} -
    - - {/* Lightbox */} - {lightboxImage && ( -
    -
    e.stopPropagation()} - > - - {lightboxImage.filename} -
    - {lightboxImage.filename} {lightboxImage.dimensions ? `• ${lightboxImage.dimensions}` : ''} • {formatFileSize(lightboxImage.size)} -
    -
    -
    - )} -
    - ); -}; - -export default MediaDashboard; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; + +const MediaDashboard = () => { + const [mediaData, setMediaData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [mediaFiles, setMediaFiles] = useState([]); + const [filterType, setFilterType] = useState("all"); + const [imageUsages, setImageUsages] = useState({}); + const [expandedFile, setExpandedFile] = useState(null); + const [lightboxImage, setLightboxImage] = useState(null); + + // Helper: get extension from filename + const getExtension = (filename) => { + const match = filename.match(/\.([^.]+)$/); + return match ? match[1].toLowerCase() : ""; + }; + + // Helper: guess type from extension + const getType = (filename) => { + const ext = getExtension(filename); + if ( + [ + "jpg", + "jpeg", + "png", + "gif", + "webp", + "svg", + "bmp", + "tiff", + "ico", + "avif", + ].includes(ext) + ) + return "image"; + if (["mp4", "webm", "mov", "avi", "mkv"].includes(ext)) return "video"; + if (["mp3", "wav", "ogg", "flac"].includes(ext)) return "audio"; + return "file"; + }; + + const openLightbox = (file) => { + setLightboxImage(file); + }; + + const closeLightbox = () => { + setLightboxImage(null); + }; + + const extractTextFromAST = (node) => { + if (!node) return ""; + + let text = ""; + + if (typeof node === "string") { + return node; + } + + if (typeof node === "object") { + // Handle different node types + if (node.type === "text" && node.value) { + text += node.value; + } + + // Handle nodes with props (like Figure components) + if (node.props) { + // Extract props as text for searching + text += JSON.stringify(node.props); + } + + // Handle JSX elements + if (node.type === "element" && node.props) { + text += JSON.stringify(node.props); + } + + // Handle MDX JSX elements + if (node.name === "Figure" && node.props) { + text += JSON.stringify(node.props); + } + + // Recursively process children + if (node.children && Array.isArray(node.children)) { + for (const child of node.children) { + text += extractTextFromAST(child); + } + } + + // Handle other array-like structures + if (Array.isArray(node)) { + for (const item of node) { + text += extractTextFromAST(item); + } + } + } + + return text; + }; + + const scanDocumentsForImageUsage = async (mediaFiles) => { + try { + const { client } = await import("../../../tina/__generated__/client"); + // Fetch all documents to scan for image usage using connection query + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 500, // Request more documents + }); + const docs = docsResult.data.docConnection.edges || []; + const usages = {}; + for (const file of mediaFiles) { + usages[file.path] = []; + } + for (const edge of docs) { + const node = edge.node; + const title = node.title || node._sys.filename; + const relativePath = node._sys.relativePath; + let content = ""; + if (node.body && typeof node.body === "object") { + content = extractTextFromAST(node.body); + } else if (typeof node.body === "string") { + content = node.body; + } + for (const file of mediaFiles) { + if (content.includes(file.filename) || content.includes(file.path)) { + usages[file.path].push({ + title, + relativePath, + filename: node._sys.filename, + lastModified: node.lastmod || node._sys?.lastModified, + editUrl: `/admin/#/collections/edit/doc/${relativePath.replace(/\.[^/.]+$/, "")}`, + }); + } + } + } + setImageUsages(usages); + return usages; + } catch (_err) { + return {}; + } + }; + + const fetchMediaFiles = async () => { + setLoading(true); + setError(null); + try { + const { client } = await import("../../../tina/__generated__/client"); + // Query Tina's MediaCollection (reuse/media/index.json) + const mediaResult = await client.queries.media({ + relativePath: "index.json", + }); + const mediaList = mediaResult?.data?.media?.media || []; + // Add type, extension, url, and name fields for UI compatibility + const files = mediaList.map((file) => { + const ext = getExtension(file.filename); + const type = getType(file.filename); + // Use file.path for correct subfolder support + const url = `/img/${file.path}`; + return { + ...file, + name: file.filename, + extension: ext, + type, + url, + lastModified: file.lastModified || "", + dimensions: file.dimensions || "", + }; + }); + setMediaFiles(files); + const mediaStats = { + total: files.length, + images: files.filter((f) => f.type === "image").length, + totalSize: files.reduce( + (acc, file) => + acc + (typeof file.size === "number" ? file.size / 1024 : 0), + 0 + ), + }; + setMediaData({ + files, + stats: mediaStats, + }); + await scanDocumentsForImageUsage(files); + } catch (_err) { + setError("Failed to load media files from Tina MediaCollection."); + } finally { + setLoading(false); + } + }; + + const getFilteredFiles = () => { + if (filterType === "all") return mediaFiles; + return mediaFiles.filter((file) => { + switch (filterType) { + case "images": + return file.type === "image"; + case "recent": { + const oneWeekAgo = new Date(); + oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); + return new Date(file.lastModified) > oneWeekAgo; + } + case "used": + return (imageUsages[file.path] || []).length > 0; + case "unused": + return (imageUsages[file.path] || []).length === 0; + default: + return true; + } + }); + }; + + const formatFileSize = (size) => { + // size is in bytes (number) + if (typeof size !== "number") return size; + if (size >= 1024 * 1024) { + return `${(size / (1024 * 1024)).toFixed(1)} MB`; + } + if (size >= 1024) { + return `${(size / 1024).toFixed(1)} KB`; + } + return `${size} B`; + }; + + const formatDate = (dateStr) => { + return new Date(dateStr).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!mediaData && !loading && !error) { + return ( +
    +
    +
    + + + + + + + +

    + Media Usage Dashboard +

    +
    + +
    +
    + ); + } + + if (loading) { + return ( +
    +
    +
    + Loading Dashboard +
    +
    + Loading media files... +
    + + {/* Progress Bar for Loading */} +
    +
    +
    +
    + +
    + ); + } + + if (error) { + return ( +
    +
    +

    + Error +

    +

    {error}

    +
    +
    + ); + } + + if (!mediaData) { + return null; + } + + const filteredFiles = getFilteredFiles(); + + return ( +
    + {/* Header */} +
    +
    +
    + + + + + + + +

    + Media Usage Dashboard +

    +
    + +
    + + {/* Media Statistics Cards */} +
    +
    +
    + + + + +
    +
    +

    Total Files

    +

    + {mediaData.stats.total} +

    +
    +
    + +
    +
    + + + + + +
    +
    +

    Images

    +

    + {mediaData.stats.images} +

    +
    +
    + +
    +
    + + + +
    +
    +

    Used

    +

    + { + Object.values(imageUsages).filter( + (usages) => usages.length > 0 + ).length + } +

    +
    +
    + +
    +
    + + + + +
    +
    +

    Unused

    +

    + { + Object.values(imageUsages).filter( + (usages) => usages.length === 0 + ).length + } +

    +
    +
    + +
    +
    + + + + +
    +
    +

    Total Size

    +

    + {mediaData.stats.totalSize.toFixed(1)} KB +

    +
    +
    +
    + + {/* Filter Controls */} +
    + + Filter: + + {["all", "images", "recent", "used", "unused"].map((filter) => ( + + ))} +
    +
    + + {/* Media Files List */} +
    + {filteredFiles.length === 0 ? ( +
    +

    + No media files found for the current filter. +

    +
    + ) : ( +
    + {filteredFiles.map((file, index) => ( + // biome-ignore lint/a11y/noStaticElementInteractions: hover styling only, nothing here is activatable +
    { + e.currentTarget.style.backgroundColor = "#f6f8fa"; + e.currentTarget.style.borderColor = "#8c959f"; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = "#ffffff"; + e.currentTarget.style.borderColor = "#d1d9e0"; + }} + > + {/* File preview */} +
    + {file.type === "image" ? ( + {file.filename} openLightbox(file)} + onError={(e) => { + e.target.style.display = "none"; + e.target.nextSibling.style.display = "flex"; + }} + onMouseOver={(e) => (e.target.style.opacity = "0.8")} + onFocus={(e) => (e.target.style.opacity = "0.8")} + onMouseOut={(e) => (e.target.style.opacity = "1")} + onBlur={(e) => (e.target.style.opacity = "1")} + /> + ) : null} +
    + {file.extension ? file.extension.toUpperCase() : ""} +
    +
    + + {/* File details */} +
    +
    + {file.filename} +
    +
    + {file.path} +
    +
    + {formatFileSize(file.size)} + {file.extension === "svg" ? ( + vector + ) : ( + file.dimensions && {file.dimensions} + )} + {file.lastModified && ( + Modified: {formatDate(file.lastModified)} + )} +
    +
    + + {/* Actions */} +
    + +
    + + {/* Usage Details - Expandable */} + {expandedFile === file.path && ( +
    +

    + Used in {(imageUsages[file.path] || []).length} document + {(imageUsages[file.path] || []).length !== 1 ? "s" : ""}: +

    + + {(imageUsages[file.path] || []).length === 0 ? ( +

    + This image is not currently used in any documents. +

    + ) : ( +
    + {(imageUsages[file.path] || []).map( + (usage, usageIndex) => ( + + ) + )} +
    + )} +
    + )} +
    + ))} +
    + )} +
    + + {/* Lightbox */} + {lightboxImage && ( + // biome-ignore lint/a11y/noStaticElementInteractions: click-to-dismiss backdrop; the close button provides the keyboard path +
    +
    e.stopPropagation()} + > + + {lightboxImage.filename} +
    + {lightboxImage.filename}{" "} + {lightboxImage.dimensions ? `• ${lightboxImage.dimensions}` : ""}{" "} + • {formatFileSize(lightboxImage.size)} +
    +
    +
    + )} +
    + ); +}; + +export default MediaDashboard; diff --git a/template/src/components/Dashboard/StatusBar.jsx b/template/src/components/Dashboard/StatusBar.jsx index 1eb16d7b..f56338a8 100644 --- a/template/src/components/Dashboard/StatusBar.jsx +++ b/template/src/components/Dashboard/StatusBar.jsx @@ -1,209 +1,241 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; - -const StatusBar = () => { - const [status, setStatus] = useState({ - connection: { type: 'loading', message: 'Checking connection...' }, - environment: { type: 'unknown', message: 'Detecting environment...' }, - settings: { type: 'loading', message: 'Validating settings...' } - }); - - useEffect(() => { - checkStatus(); - }, []); - - const checkStatus = async () => { - // Check GraphQL connection - let connectionStatus = { type: 'error', message: 'No connection' }; - let environmentStatus = { type: 'unknown', message: 'Unknown' }; - - try { - // Test localhost GraphQL first - const localhostResponse = await fetch('http://localhost:4001/graphql', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query: '{ __typename }' }), - }); - - if (localhostResponse.ok) { - connectionStatus = { type: 'success', message: 'Connected' }; - environmentStatus = { type: 'localhost', message: 'localhost:4001' }; - } - } catch (err) { - // If localhost fails, check for TinaCloud configuration - const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const token = process.env.NEXT_PUBLIC_TINA_TOKEN; - - if (clientId) { - // Try to import and check TinaCMS client for TinaCloud - try { - const { client } = await import('../../../tina/__generated__/client'); - // If we have a client and clientId, assume TinaCloud is configured - connectionStatus = { type: 'success', message: 'TinaCloud configured' }; - environmentStatus = { type: 'tinacloud', message: `TinaCloud (${clientId.substring(0, 8)}...)` }; - } catch (clientErr) { - connectionStatus = { type: 'error', message: 'Configuration error' }; - environmentStatus = { type: 'error', message: 'Client not found' }; - } - } else { - connectionStatus = { type: 'error', message: 'Not configured' }; - environmentStatus = { type: 'error', message: 'No environment set' }; - } - } - - // Check required settings - let settingsStatus = { type: 'success', message: 'All settings OK' }; - const missingSettings = []; - - // Check for essential environment variables - const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; - const token = process.env.NEXT_PUBLIC_TINA_TOKEN; - - // NEXT_PUBLIC_TINA_TOKEN is not required for TinaCloud environments - // Only check for token if using local development with specific requirements - // if (environmentStatus.type === 'tinacloud' && !token) { - // missingSettings.push('NEXT_PUBLIC_TINA_TOKEN'); - // } - - // Check for essential config files - try { - const { default: docusaurusConfig } = await import('../../../config/docusaurus/index.json'); - if (!docusaurusConfig || Object.keys(docusaurusConfig).length === 0) { - missingSettings.push('Docusaurus config'); - } - } catch (err) { - missingSettings.push('Docusaurus config'); - } - - // Check if TinaCMS client is properly generated - try { - await import('../../../tina/__generated__/client'); - } catch (err) { - missingSettings.push('TinaCMS client (run: yarn tina-build)'); - } - - if (missingSettings.length > 0) { - settingsStatus = { - type: 'warning', - message: `Missing: ${missingSettings.join(', ')}` - }; - } - - setStatus({ - connection: connectionStatus, - environment: environmentStatus, - settings: settingsStatus - }); - }; - - const getStatusColor = (type) => { - switch (type) { - case 'success': return '#059669'; // green - case 'warning': return '#f59e0b'; // yellow - case 'error': return '#dc2626'; // red - case 'localhost': return '#3b82f6'; // blue - case 'tinacloud': return '#8b5cf6'; // purple - case 'loading': return '#6b7280'; // gray - default: return '#6b7280'; // gray - } - }; - - const getStatusIcon = (type) => { - switch (type) { - case 'success': return 'āœ“'; - case 'warning': return '⚠'; - case 'error': return 'āœ—'; - case 'localhost': return ( - - - - - ); - case 'tinacloud': return '☁'; - case 'loading': return '⟳'; - default: return '?'; - } - }; - - // Inject status into existing element if it exists - useEffect(() => { - // Hide Reset and Save buttons on this dashboard page - const hideButtonsStyle = document.createElement('style'); - hideButtonsStyle.id = 'statusbar-hide-buttons'; - hideButtonsStyle.textContent = ` - .relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end button.icon-parent.items-center.font-medium.focus\\:outline-none.focus\\:ring-2.focus\\:shadow-outline.text-center.inline-flex.justify-center.transition-all.duration-150.ease-out.shadow { - display: none !important; - } - `; - - // Add the style if it doesn't exist - if (!document.getElementById('statusbar-hide-buttons')) { - document.head.appendChild(hideButtonsStyle); - } - - const targetElement = document.querySelector('.relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end'); - if (targetElement) { - const statusContainer = targetElement.querySelector('.status-bar-injected'); - if (!statusContainer) { - const statusDiv = document.createElement('div'); - statusDiv.className = 'status-bar-injected flex items-center gap-4 mr-auto'; - statusDiv.style.fontSize = '0.75rem'; - statusDiv.innerHTML = ` -
    - ${getStatusIcon(status.connection.type)} - GraphQL: - ${status.connection.message} -
    -
    - ${getStatusIcon(status.environment.type)} - Environment: - ${status.environment.message} -
    -
    - ${getStatusIcon(status.settings.type)} - Settings: - ${status.settings.message} -
    - `; - targetElement.insertBefore(statusDiv, targetElement.firstChild); - } else { - // Update existing status - statusContainer.innerHTML = ` -
    - ${getStatusIcon(status.connection.type)} - GraphQL: - ${status.connection.message} -
    -
    - ${getStatusIcon(status.environment.type)} - Environment: - ${status.environment.message} -
    -
    - ${getStatusIcon(status.settings.type)} - Settings: - ${status.settings.message} -
    - `; - } - } - - // Cleanup function to remove the style when component unmounts - return () => { - const existingStyle = document.getElementById('statusbar-hide-buttons'); - if (existingStyle) { - existingStyle.remove(); - } - }; - }, [status]); - - return null; // Only inject into existing element, don't render standalone -}; - -export default StatusBar; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useCallback, useEffect, useState } from "react"; + +const getStatusColor = (type) => { + switch (type) { + case "success": + return "#059669"; // green + case "warning": + return "#f59e0b"; // yellow + case "error": + return "#dc2626"; // red + case "localhost": + return "#3b82f6"; // blue + case "tinacloud": + return "#8b5cf6"; // purple + case "loading": + return "#6b7280"; // gray + default: + return "#6b7280"; // gray + } +}; + +const getStatusIcon = (type) => { + switch (type) { + case "success": + return "āœ“"; + case "warning": + return "⚠"; + case "error": + return "āœ—"; + case "localhost": + // Every caller interpolates this into an HTML string, so returning JSX + // here rendered as "[object Object]" in the status bar. + return ( + '' + + '' + + '' + + "" + ); + case "tinacloud": + return "☁"; + case "loading": + return "⟳"; + default: + return "?"; + } +}; + +const StatusBar = () => { + const [status, setStatus] = useState({ + connection: { type: "loading", message: "Checking connection..." }, + environment: { type: "unknown", message: "Detecting environment..." }, + settings: { type: "loading", message: "Validating settings..." }, + }); + + const checkStatus = useCallback(async () => { + // Check GraphQL connection + let connectionStatus = { type: "error", message: "No connection" }; + let environmentStatus = { type: "unknown", message: "Unknown" }; + + try { + // Test localhost GraphQL first + const localhostResponse = await fetch("http://localhost:4001/graphql", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ query: "{ __typename }" }), + }); + + if (localhostResponse.ok) { + connectionStatus = { type: "success", message: "Connected" }; + environmentStatus = { type: "localhost", message: "localhost:4001" }; + } + } catch (_err) { + // If localhost fails, check for TinaCloud configuration + const clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; + const _token = process.env.NEXT_PUBLIC_TINA_TOKEN; + + if (clientId) { + // Try to import and check TinaCMS client for TinaCloud + try { + await import("../../../tina/__generated__/client"); + // If we have a client and clientId, assume TinaCloud is configured + connectionStatus = { + type: "success", + message: "TinaCloud configured", + }; + environmentStatus = { + type: "tinacloud", + message: `TinaCloud (${clientId.substring(0, 8)}...)`, + }; + } catch (_clientErr) { + connectionStatus = { type: "error", message: "Configuration error" }; + environmentStatus = { type: "error", message: "Client not found" }; + } + } else { + connectionStatus = { type: "error", message: "Not configured" }; + environmentStatus = { type: "error", message: "No environment set" }; + } + } + + // Check required settings + let settingsStatus = { type: "success", message: "All settings OK" }; + const missingSettings = []; + + // Check for essential environment variables + const _clientId = process.env.NEXT_PUBLIC_TINA_CLIENT_ID; + const _token = process.env.NEXT_PUBLIC_TINA_TOKEN; + + // NEXT_PUBLIC_TINA_TOKEN is not required for TinaCloud environments + // Only check for token if using local development with specific requirements + // if (environmentStatus.type === 'tinacloud' && !token) { + // missingSettings.push('NEXT_PUBLIC_TINA_TOKEN'); + // } + + // Check for essential config files + try { + const { default: docusaurusConfig } = await import( + "../../../config/docusaurus/index.json" + ); + if (!docusaurusConfig || Object.keys(docusaurusConfig).length === 0) { + missingSettings.push("Docusaurus config"); + } + } catch (_err) { + missingSettings.push("Docusaurus config"); + } + + // Check if TinaCMS client is properly generated + try { + await import("../../../tina/__generated__/client"); + } catch (_err) { + missingSettings.push("TinaCMS client (run: yarn tina-build)"); + } + + if (missingSettings.length > 0) { + settingsStatus = { + type: "warning", + message: `Missing: ${missingSettings.join(", ")}`, + }; + } + + setStatus({ + connection: connectionStatus, + environment: environmentStatus, + settings: settingsStatus, + }); + }, []); + + useEffect(() => { + checkStatus(); + }, [checkStatus]); + + // Inject status into existing element if it exists + useEffect(() => { + // Hide Reset and Save buttons on this dashboard page + const hideButtonsStyle = document.createElement("style"); + hideButtonsStyle.id = "statusbar-hide-buttons"; + hideButtonsStyle.textContent = ` + .relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end button.icon-parent.items-center.font-medium.focus\\:outline-none.focus\\:ring-2.focus\\:shadow-outline.text-center.inline-flex.justify-center.transition-all.duration-150.ease-out.shadow { + display: none !important; + } + `; + + // Add the style if it doesn't exist + if (!document.getElementById("statusbar-hide-buttons")) { + document.head.appendChild(hideButtonsStyle); + } + + const targetElement = document.querySelector( + ".relative.flex-none.w-full.h-16.px-6.bg-white.border-t.border-gray-100.flex.items-center.justify-end" + ); + if (targetElement) { + const statusContainer = targetElement.querySelector( + ".status-bar-injected" + ); + if (!statusContainer) { + const statusDiv = document.createElement("div"); + statusDiv.className = + "status-bar-injected flex items-center gap-4 mr-auto"; + statusDiv.style.fontSize = "0.75rem"; + statusDiv.innerHTML = ` +
    + ${getStatusIcon(status.connection.type)} + GraphQL: + ${status.connection.message} +
    +
    + ${getStatusIcon(status.environment.type)} + Environment: + ${status.environment.message} +
    +
    + ${getStatusIcon(status.settings.type)} + Settings: + ${status.settings.message} +
    + `; + targetElement.insertBefore(statusDiv, targetElement.firstChild); + } else { + // Update existing status + statusContainer.innerHTML = ` +
    + ${getStatusIcon(status.connection.type)} + GraphQL: + ${status.connection.message} +
    +
    + ${getStatusIcon(status.environment.type)} + Environment: + ${status.environment.message} +
    +
    + ${getStatusIcon(status.settings.type)} + Settings: + ${status.settings.message} +
    + `; + } + } + + // Cleanup function to remove the style when component unmounts + return () => { + const existingStyle = document.getElementById("statusbar-hide-buttons"); + if (existingStyle) { + existingStyle.remove(); + } + }; + }, [status]); + + return null; // Only inject into existing element, don't render standalone +}; + +export default StatusBar; diff --git a/template/src/components/Dashboard/TranslationDashboard.jsx b/template/src/components/Dashboard/TranslationDashboard.jsx index 04ac9ceb..36129bd5 100644 --- a/template/src/components/Dashboard/TranslationDashboard.jsx +++ b/template/src/components/Dashboard/TranslationDashboard.jsx @@ -1,1439 +1,2210 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { useState, useEffect } from 'react'; -import * as xliffUtils from '../../utils/xliff'; -import docusaurusData from '../../../config/docusaurus/index.json'; - -const TranslationDashboard = () => { - const [status, setStatus] = useState(''); - // Delete all orphan topics - const handleDeleteOrphanTopics = async () => { - setStatus(''); - try { - const { client } = await import('../../../tina/__generated__/client'); - const lang = selectedLanguage; - const docOrphaned = translationData && translationData[lang] ? translationData[lang].orphaned : []; - const snippetOrphaned = translationData && translationData[lang] ? (translationData[lang].snippets?.orphaned || []) : []; - const orphaned = [...docOrphaned, ...snippetOrphaned]; - for (const item of orphaned) { - await client.request({ - query: ` - mutation DeleteI18n($collection: String!, $relativePath: String!) { - deleteDocument(collection: $collection, relativePath: $relativePath) { - ... on I18n { - id - } - } - } - `, - variables: { - collection: 'i18n', - relativePath: item.file - } - }); - } - setStatus(`Deleted ${orphaned.length} orphan topics for ${lang}`); - await scanTranslations(); - } catch (err) { - setStatus(`Error: ${err.message}`); - } - }; - - // Add all missing topics - const handleAddMissingTopics = async () => { - setStatus(''); - try { - const { client } = await import('../../../tina/__generated__/client'); - const lang = selectedLanguage; - const missingDocs = translationData && translationData[lang] ? translationData[lang].missing : []; - const missingSnippets = translationData && translationData[lang] ? (translationData[lang].snippets?.missing || []) : []; - const missing = [ - ...missingDocs.map(item => ({ ...item, _isSnippet: false })), - ...missingSnippets.map(item => ({ ...item, _isSnippet: true })) - ]; - if (!missing || missing.length === 0) { - setStatus('No missing topics to add'); - return; - } - setAdding(true); - setAddProgress(0); - for (const [idx, item] of missing.entries()) { - // copy full metadata and body from sourceNode when available - const sourceNode = item.sourceNode || null; - let relPath; - if (item._isSnippet) { - const baseFile = item.file; - const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); - relPath = `${lang}/snippets/${baseFile}${hasExt ? '' : '.mdx'}`; - } else { - const baseFile = item.file.replace(/^docs\//, ''); - const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); - relPath = `${lang}/docusaurus-plugin-content-docs/current/${baseFile}${hasExt ? '' : '.mdx'}`; - } - const paramsBody = {}; - if (sourceNode) { - paramsBody.title = sourceNode.title || item.title; - if (sourceNode.body) paramsBody.body = sourceNode.body; - if (item._isSnippet) { - if (sourceNode.description) paramsBody.description = sourceNode.description; - } else { - if (sourceNode.modifiedBy) paramsBody.modifiedBy = sourceNode.modifiedBy; - if (sourceNode.help !== undefined) paramsBody.help = sourceNode.help; - if (sourceNode.slug) paramsBody.slug = sourceNode.slug; - if (sourceNode.tags) paramsBody.tags = sourceNode.tags; - if (sourceNode.draft !== undefined) paramsBody.draft = sourceNode.draft; - if (sourceNode.review !== undefined) paramsBody.review = sourceNode.review; - if (sourceNode.translate !== undefined) paramsBody.translate = sourceNode.translate; - if (sourceNode.approved !== undefined) paramsBody.approved = sourceNode.approved; - if (sourceNode.published !== undefined) paramsBody.published = sourceNode.published; - if (sourceNode.unlisted !== undefined) paramsBody.unlisted = sourceNode.unlisted; - } - } else { - paramsBody.title = item.title; - } - // ensure created translations start with required workflow metadata - paramsBody.draft = false; - paramsBody.review = false; - paramsBody.translate = true; - paramsBody.approved = false; - paramsBody.published = false; - paramsBody.unlisted = true; - // set lastmod to one day earlier than source (or yesterday) - let lastmodSource = null; - if (sourceNode && sourceNode.lastmod) { - lastmodSource = new Date(sourceNode.lastmod); - } else if (item.sourceLastMod && item.sourceLastMod !== 'No date') { - try { - const parsed = new Date(item.sourceLastMod); - if (!isNaN(parsed.getTime())) lastmodSource = parsed; - } catch (e) { - // ignore parse errors - } - } - paramsBody.lastmod = lastmodSource ? new Date(lastmodSource.getTime() - 1000).toISOString() : new Date(Date.now() - 1000).toISOString(); - - await client.request({ - query: ` - mutation CreateI18n($collection: String!, $relativePath: String!, $params: DocumentMutation!) { - createDocument(collection: $collection, relativePath: $relativePath, params: $params) { - ... on I18n { - id - } - } - } - `, - variables: { - collection: 'i18n', - relativePath: relPath, - params: { i18n: paramsBody } - } - }); - - // update progress - try { - const pct = missing.length > 0 ? Math.round(((idx + 1) / missing.length) * 100) : 100; - setAddProgress(pct); - setStatus(`Adding ${idx + 1}/${missing.length} translations (${pct}%)`); - } catch (e) { - // ignore progress errors - } - } - setStatus(`Added ${missing.length} missing topics for ${lang}`); - await scanTranslations(); - setAddProgress(100); - setTimeout(() => setAddProgress(null), 800); - setAdding(false); - } catch (err) { - setStatus(`Error: ${err.message}`); - setAdding(false); - setAddProgress(null); - } - }; - - // Edit out-of-date doc - const handleEditOutOfDateDoc = (file) => { - const cleanFile = file.replace(/^docs\//, '').replace(/\.mdx$/, '').replace(/\.md$/, ''); - window.open(`/admin#/collections/edit/i18n/${selectedLanguage}/docusaurus-plugin-content-docs/current/${cleanFile}`, '_blank'); - }; - - // Edit out-of-date snippet - const handleEditOutOfDateSnippet = (file) => { - const cleanFile = file.replace(/\.mdx$/, '').replace(/\.md$/, ''); - window.open(`/admin#/collections/edit/i18n/${selectedLanguage}/snippets/${cleanFile}`, '_blank'); - }; - const [translationData, setTranslationData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [importing, setImporting] = useState(false); - const [importProgress, setImportProgress] = useState(null); - const [adding, setAdding] = useState(false); - const [addProgress, setAddProgress] = useState(null); - const [selectedLanguage, setSelectedLanguage] = useState('fr'); - - // Handle Import button: open file picker and run verbose GraphQL import - const handleImportClick = async () => { - try { - setImporting(true); - setImportProgress(null); - const input = document.getElementById('xliff-upload'); - if (!input) return; - input.value = ''; - input.click(); - const file = await new Promise((resolve) => { - const onChange = () => { - input.removeEventListener('change', onChange); - const f = input.files && input.files[0]; - resolve(f); - }; - input.addEventListener('change', onChange); - }); - if (!file) return; - setStatus(`Importing: ${file.name}`); - const text = await file.text(); - const { client } = await import('../../../tina/__generated__/client'); - console.log('[debug-import] reading file', file.name, file.size); - const results = await xliffUtils.importXliffBundle(client, text, selectedLanguage, (p) => { - console.log('[debug-import] progress', p); - if (p && p.id) setStatus(`Import ${p.id}: ${p.status}${p.error ? ' - ' + p.error : ''}`); - if (p && p.progress !== undefined) setImportProgress(p.progress); - }); - console.log('[debug-import] results', results); - setStatus('Import complete'); - setImportProgress(100); - setTimeout(() => setImportProgress(null), 800); - setImporting(false); - await scanTranslations(); - } catch (err) { - console.error('[import] error', err); - setStatus(`Import error: ${err && err.message ? err.message : String(err)}`); - setImporting(false); - setImportProgress(null); - } - }; - - // (removed separate debug-upload handler) single Import button handles import - - const scanTranslations = async () => { - setLoading(true); - setError(null); - try { - // Build results container - const results = {}; - const { client } = await import('../../../tina/__generated__/client'); - - // Helper to normalize paths for comparison (strip extensions and index/readme) - const canonicalize = (p) => { - if (!p) return p; - let s = p.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); - return s; - }; - - // Fetch docs (source files) with pagination - let docsEdges = []; - let docsAfter = null; - while (true) { - const docsResult = await client.queries.docConnection({ sort: 'title', first: 100, after: docsAfter }); - const chunk = docsResult.data?.docConnection?.edges || []; - docsEdges = docsEdges.concat(chunk); - const pageInfo = docsResult.data?.docConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - docsAfter = pageInfo.endCursor; - } - const sourceMap = {}; // canonical -> node - for (const edge of docsEdges) { - const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; - // derive clean path by removing only a leading 'docs/' prefix - let clean = rel; - if (rel.startsWith('docs/')) { - clean = rel.replace(/^docs\//, ''); - } - // exclude generated API folder - if (clean.startsWith('api/')) continue; - const canonical = canonicalize(clean || rel); - sourceMap[canonical] = node; - } - - - - // Fetch snippets with pagination - let snippetsEdges = []; - let snippetsAfter = null; - while (true) { - const snippetsResult = await client.queries.snippetsConnection({ first: 100, after: snippetsAfter }); - const chunk = snippetsResult.data?.snippetsConnection?.edges || []; - snippetsEdges = snippetsEdges.concat(chunk); - const pageInfo = snippetsResult.data?.snippetsConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - snippetsAfter = pageInfo.endCursor; - } - const snippetSourceMap = {}; - for (const edge of snippetsEdges) { - const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; - const canonical = canonicalize(rel); - snippetSourceMap[canonical] = node; - } - - // Fetch translations and build map for the selected language with pagination - let i18nEdges = []; - let i18nAfter = null; - while (true) { - const i18nResult = await client.queries.i18nConnection({ sort: 'title', first: 100, after: i18nAfter }); - const chunk = i18nResult.data?.i18nConnection?.edges || []; - i18nEdges = i18nEdges.concat(chunk); - const pageInfo = i18nResult.data?.i18nConnection?.pageInfo; - if (!pageInfo || !pageInfo.hasNextPage) break; - i18nAfter = pageInfo.endCursor; - } - // Build translation maps grouped by language - const translationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } - const snippetTranslationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } - for (const edge of i18nEdges) { - const node = edge.node; - const relPath = node._sys?.relativePath || node._sys?.filename || ''; - const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); - if (!m) continue; - const lang = m[1]; - const after = m[2]; - const prefix = 'docusaurus-plugin-content-docs/current/'; - if (after.startsWith('snippets/')) { - const snippetRel = after.replace(/^snippets\//, ''); - const canonical = canonicalize(snippetRel); - snippetTranslationsByLang[lang] = snippetTranslationsByLang[lang] || {}; - snippetTranslationsByLang[lang][canonical] = { node, originalPath: snippetRel, rawPath: snippetRel }; - continue; - } - if (!after.startsWith(prefix)) continue; - let cleanAfter = after.replace(new RegExp(`^${prefix}`), ''); - // Keep the raw path (before stripping docs/) for Tina API operations - const rawPath = cleanAfter; - // Strip leading 'docs/' to match source doc paths - if (cleanAfter.startsWith('docs/')) { - cleanAfter = cleanAfter.replace(/^docs\//, ''); - } - if (cleanAfter.startsWith('api/') || cleanAfter.startsWith('wiki/')) continue; - const canonical = canonicalize(cleanAfter); - - translationsByLang[lang] = translationsByLang[lang] || {}; - const translationsMap = translationsByLang[lang]; - - if (translationsMap[canonical]) { - const existing = translationsMap[canonical]; - const isExistingIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(existing.originalPath || ''); - const isNewIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(cleanAfter); - if (isExistingIndex && !isNewIndex) { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } else { - try { - const existingDate = existing.node?.lastmod ? new Date(existing.node.lastmod) : null; - const newDate = node?.lastmod ? new Date(node.lastmod) : null; - if (newDate && (!existingDate || newDate > existingDate)) { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } - } catch (e) { - // keep existing on errors - } - } - } else { - translationsMap[canonical] = { node, originalPath: cleanAfter, rawPath }; - } - } - - // For each language, compare with source map and build results - const sourceKeys = new Set(Object.keys(sourceMap)); - // Pre-build a 'missing all' list so empty languages can be shown - const missingAll = []; - for (const key of sourceKeys) { - const src = sourceMap[key]; - const title = src.title || key; - missingAll.push({ file: `docs/${key}`, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - } - for (const lang of Object.keys(translationsByLang)) { - const translationsMap = translationsByLang[lang] || {}; - const translationKeys = new Set(Object.keys(translationsMap)); - - const missing = []; - const outdated = []; - const upToDate = []; - const orphaned = []; - - for (const key of sourceKeys) { - const src = sourceMap[key]; - const srcDate = src.lastmod ? new Date(src.lastmod) : null; - const title = src.title || key; - if (!translationKeys.has(key)) { - missing.push({ file: `docs/${key}`, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - continue; - } - const tr = translationsMap[key].node; - const trDate = tr.lastmod ? new Date(tr.lastmod) : null; - if (!srcDate && !trDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: 'No date', translationLastMod: 'No date', title }); - } else if (srcDate && !trDate) { - outdated.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: 'No date', title }); - } else if (!srcDate && trDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: 'No date', translationLastMod: tr.lastmod, title }); - } else { - if (trDate >= srcDate) { - upToDate.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title }); - } else { - outdated.push({ file: `docs/${key}`, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title, daysBehind: Math.ceil((srcDate - trDate) / (1000*60*60*24)) }); - } - } - } - - for (const key of translationKeys) { - if (!sourceKeys.has(key)) { - const entry = translationsMap[key]; - const node = entry.node; - const orig = entry.rawPath || entry.originalPath || key; - orphaned.push({ file: `${lang}/docusaurus-plugin-content-docs/current/${orig}`, translationLastMod: node.lastmod || 'No date', title: node.title || orig }); - } - } - - results[lang] = { - missing, - outdated, - upToDate, - orphaned, - errors: [], - total: Object.keys(sourceMap).length - }; - } - - // Get supported languages from the imported docusaurus config, excluding - // the default locale and any English variants (en-*). - const supported = docusaurusData.languages?.supported || []; - const defaultLocale = docusaurusData.languages?.default || 'en'; - const langsFromConfig = supported - .filter(l => l.code !== defaultLocale && !l.code.startsWith('en')) - .map(l => ({ code: l.code, label: l.label })); - - for (const langEntry of langsFromConfig) { - const fsLang = langEntry.code; - if (!results[fsLang]) { - results[fsLang] = { - missing: missingAll.slice(), - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length - }; - } - } - - // If no translations found at all, ensure we still populate selectedLanguage key so UI remains consistent - if (Object.keys(results).length === 0) { - results[selectedLanguage] = { - missing: [], - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length - }; - } - - // Build snippet translation results for all languages - const snippetSourceKeys = new Set(Object.keys(snippetSourceMap)); - const missingAllSnippets = []; - for (const key of snippetSourceKeys) { - const src = snippetSourceMap[key]; - missingAllSnippets.push({ file: key, sourceLastMod: src.lastmod || 'No date', title: src.title || key, sourceNode: src }); - } - for (const lang of Object.keys(results)) { - const snTrMap = snippetTranslationsByLang[lang] || {}; - const snTrKeys = new Set(Object.keys(snTrMap)); - const snMissing = [], snOutdated = [], snUpToDate = [], snOrphaned = []; - for (const key of snippetSourceKeys) { - const src = snippetSourceMap[key]; - const srcDate = src.lastmod ? new Date(src.lastmod) : null; - const title = src.title || key; - if (!snTrKeys.has(key)) { - snMissing.push({ file: key, sourceLastMod: src.lastmod || 'No date', title, sourceNode: src }); - continue; - } - const tr = snTrMap[key].node; - const trDate = tr.lastmod ? new Date(tr.lastmod) : null; - if (!srcDate && !trDate) { - snUpToDate.push({ file: key, sourceLastMod: 'No date', translationLastMod: 'No date', title }); - } else if (srcDate && !trDate) { - snOutdated.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: 'No date', title }); - } else if (!srcDate && trDate) { - snUpToDate.push({ file: key, sourceLastMod: 'No date', translationLastMod: tr.lastmod, title }); - } else { - if (trDate >= srcDate) { - snUpToDate.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title }); - } else { - snOutdated.push({ file: key, sourceLastMod: src.lastmod, translationLastMod: tr.lastmod, title, daysBehind: Math.ceil((srcDate - trDate) / (1000 * 60 * 60 * 24)) }); - } - } - } - for (const key of snTrKeys) { - if (!snippetSourceKeys.has(key)) { - const entry = snTrMap[key]; - const node = entry.node; - const orig = entry.rawPath || entry.originalPath || key; - snOrphaned.push({ file: `${lang}/snippets/${orig}`, translationLastMod: node.lastmod || 'No date', title: node.title || orig }); - } - } - results[lang].snippets = { missing: snMissing, outdated: snOutdated, upToDate: snUpToDate, orphaned: snOrphaned, total: snippetSourceKeys.size }; - } - // Handle any snippet-only languages not yet in results - for (const lang of Object.keys(snippetTranslationsByLang)) { - if (!results[lang]) { - results[lang] = { - missing: missingAll.slice(), - outdated: [], - upToDate: [], - orphaned: [], - errors: [], - total: Object.keys(sourceMap).length, - snippets: { - missing: missingAllSnippets.slice(), - outdated: [], - upToDate: [], - orphaned: [], - total: snippetSourceKeys.size - } - }; - } - } - - // Ensure selectedLanguage is present in results (pick first available if not) - const langsFound = Object.keys(results); - if (langsFound.length > 0 && !results[selectedLanguage]) { - setSelectedLanguage(langsFound[0]); - } - - setTranslationData(results); - } catch (error) { - console.error('Error scanning translations:', error); - setError(`Failed to scan translations: ${error.message}`); - } finally { - setLoading(false); - } - }; - - - - const formatDate = (dateString) => { - try { - return new Date(dateString).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric' - }); - } catch (error) { - return dateString; - } - }; - - const getStatusColor = (status) => { - switch (status) { - case 'outdated': return '#f59e0b'; - case 'missing': return '#ff6b6b'; - case 'upToDate': return '#2ed573'; - case 'orphaned': return '#9c88ff'; - default: return '#747d8c'; - } - }; - - const getTotalCounts = () => { - if (!translationData) return {}; - - return Object.keys(translationData).reduce((acc, lang) => { - const data = translationData[lang]; - const sn = data.snippets || { missing: [], outdated: [], upToDate: [], orphaned: [], total: 0 }; - acc[lang] = { - total: (data.total || (data.missing.length + data.outdated.length + data.upToDate.length)) + (sn.total || 0), - missing: data.missing.length + sn.missing.length, - outdated: data.outdated.length + sn.outdated.length, - upToDate: data.upToDate.length + sn.upToDate.length, - orphaned: data.orphaned.length + sn.orphaned.length, - errors: data.errors.length - }; - return acc; - }, {}); - }; - - - // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) - if (!translationData && !loading && !error) { - return ( -
    -
    -
    - - - - - - - -

    - Translation Dashboard -

    -
    - -
    -
    - ); - } - - if (loading) { - return ( -
    -
    -
    - Loading Dashboard -
    -
    - Scanning translations... -
    - - {/* Progress Bar for Loading */} -
    -
    -
    -
    - -
    - ); - } - - if (error) { - return ( -
    -
    -
    - Error: {error} -
    - -
    -
    - ); - } - - if (!translationData) { - return ( -
    -
    - No translation data available -
    -
    - ); - } - - const totalCounts = getTotalCounts(); - const languages = Object.keys(translationData); - - return ( -
    -
    -
    - - - - - - - -

    - Translation Dashboard -

    -
    -
    - - - - - - - {/* Debug import now runs immediately when a file is selected via Import XLIFF */} - -
    -
    - {status &&
    {status}
    } - - {/* Progress Bars for Async Operations */} - {addProgress !== null && ( -
    -
    - Adding Missing Topics: {addProgress}% -
    -
    -
    -
    -
    - )} - - {importProgress !== null && ( -
    -
    - Importing XLIFF: {importProgress}% -
    -
    -
    -
    -
    - )} - - {loading && ( -
    -
    - Scanning translations... -
    -
    -
    -
    -
    - )} - - - - {/* Translation Statistics Cards */} -
    - {(() => { - const counts = totalCounts[selectedLanguage]; - if (!counts) return null; - - return [ - { - label: 'Up to Date', - value: counts.upToDate, - icon: ( - - - - ), - bgColor: 'bg-green-100', - iconColor: 'text-green-600', - textColor: 'text-green-600' - }, - { - label: 'Outdated', - value: counts.outdated, - icon: ( - - - - - ), - bgColor: 'bg-orange-100', - iconColor: 'text-orange-600', - textColor: 'text-orange-600' - }, - { - label: 'Missing', - value: counts.missing, - icon: ( - - - - - - ), - bgColor: 'bg-red-100', - iconColor: 'text-red-600', - textColor: 'text-red-600' - }, - { - label: 'Orphaned', - value: counts.orphaned, - icon: ( - - - - - ), - bgColor: 'bg-purple-100', - iconColor: 'text-purple-600', - textColor: 'text-purple-600' - } - ].map((stat, index) => ( -
    -
    -
    {stat.icon}
    -
    -
    -

    {stat.label}

    -

    {stat.value}

    -
    -
    - )); - })()} -
    - - {/* Language Selection */} -
    -
    - - -
    -
    - - {/* Detailed View */} - {(() => { - const data = translationData[selectedLanguage]; - if (!data) return null; - - return ( -
    - - {/* Missing Files */} - {data.missing.length > 0 && ( -
    -

    - - - - - Missing Translations ({data.missing.length}) -

    -
    - {data.missing.map((item, index) => ( -
    -
    - {item.title} -
    - {item.file} -
    -
    -
    - Source: {formatDate(item.sourceLastMod)} -
    -
    - ))} -
    -
    - )} - - {/* Outdated Files */} - {data.outdated.length > 0 && ( -
    -

    - - - - - Outdated Translations ({data.outdated.length}) -

    -
    - {data.outdated.map((item, index) => ( -
    -
    - {item.title} - -
    -
    - {item.file} - Source: {formatDate(item.sourceLastMod)} -
    -
    - {item.daysBehind ? `${item.daysBehind} days behind` : ''} - Translation: {formatDate(item.translationLastMod)} -
    -
    - ))} -
    -
    - )} - - {/* Up to Date Files */} - {data.upToDate.length > 0 && selectedLanguage !== 'all' && ( -
    -

    - - - - Up to Date Translations ({data.upToDate.length}) -

    -
    - {data.upToDate.map((item, index) => ( -
    -
    - {item.title} -
    - {item.file} -
    -
    -
    - {formatDate(item.translationLastMod)} -
    -
    - ))} -
    -
    - )} - - {/* Orphaned Files */} - {data.orphaned.length > 0 && ( -
    -

    - - - - - Orphan Topics ({data.orphaned.length}) -

    -
    - {data.orphaned.map((item, index) => ( -
    -
    - {item.title} -
    - {item.file} -
    -
    - Translation exists but no source file found -
    -
    -
    - Translation: {formatDate(item.translationLastMod)} -
    -
    - ))} -
    -
    - )} - - {/* Errors */} - {data.errors.length > 0 && ( -
    -

    - - - - - - Errors ({data.errors.length}) -

    -
    - {data.errors.map((item, index) => ( -
    -
    {item.file}
    -
    {item.error}
    -
    - ))} -
    -
    - )} - - {/* Snippets Section */} - {data.snippets && data.snippets.total > 0 && ( -
    -

    - - - - - - - - Snippets -

    - - {/* Missing Snippets */} - {data.snippets.missing.length > 0 && ( -
    -

    - - - - - Missing Snippet Translations ({data.snippets.missing.length}) -

    -
    - {data.snippets.missing.map((item, index) => ( -
    -
    - {item.title} -
    {item.file}
    -
    -
    - ))} -
    -
    - )} - - {/* Outdated Snippets */} - {data.snippets.outdated.length > 0 && ( -
    -

    - - - - - Outdated Snippet Translations ({data.snippets.outdated.length}) -

    -
    - {data.snippets.outdated.map((item, index) => ( -
    -
    - {item.title} - -
    -
    - {item.file} - Source: {formatDate(item.sourceLastMod)} -
    -
    - {item.daysBehind ? `${item.daysBehind} days behind` : ''} - Translation: {formatDate(item.translationLastMod)} -
    -
    - ))} -
    -
    - )} - - {/* Up to Date Snippets */} - {data.snippets.upToDate.length > 0 && ( -
    -

    - - - - Up to Date Snippet Translations ({data.snippets.upToDate.length}) -

    -
    - {data.snippets.upToDate.map((item, index) => ( -
    -
    - {item.title} -
    {item.file}
    -
    -
    {formatDate(item.translationLastMod)}
    -
    - ))} -
    -
    - )} - - {/* Orphaned Snippets */} - {data.snippets.orphaned.length > 0 && ( -
    -

    - - - - - Orphan Snippets ({data.snippets.orphaned.length}) -

    -
    - {data.snippets.orphaned.map((item, index) => ( -
    -
    - {item.title} -
    {item.file}
    -
    Translation exists but no source snippet found
    -
    -
    Translation: {formatDate(item.translationLastMod)}
    -
    - ))} -
    -
    - )} -
    - )} -
    - ); - })()} -
    - ); -}; - -export default TranslationDashboard; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { useState } from "react"; +import docusaurusData from "../../../config/docusaurus/index.json"; +import * as xliffUtils from "../../utils/xliff"; + +const TranslationDashboard = () => { + const [status, setStatus] = useState(""); + // Delete all orphan topics + const handleDeleteOrphanTopics = async () => { + setStatus(""); + try { + const { client } = await import("../../../tina/__generated__/client"); + const lang = selectedLanguage; + const docOrphaned = translationData?.[lang] + ? translationData[lang].orphaned + : []; + const snippetOrphaned = translationData?.[lang] + ? translationData[lang].snippets?.orphaned || [] + : []; + const orphaned = [...docOrphaned, ...snippetOrphaned]; + for (const item of orphaned) { + await client.request({ + query: ` + mutation DeleteI18n($collection: String!, $relativePath: String!) { + deleteDocument(collection: $collection, relativePath: $relativePath) { + ... on I18n { + id + } + } + } + `, + variables: { + collection: "i18n", + relativePath: item.file, + }, + }); + } + setStatus(`Deleted ${orphaned.length} orphan topics for ${lang}`); + await scanTranslations(); + } catch (err) { + setStatus(`Error: ${err.message}`); + } + }; + + // Add all missing topics + const handleAddMissingTopics = async () => { + setStatus(""); + try { + const { client } = await import("../../../tina/__generated__/client"); + const lang = selectedLanguage; + const missingDocs = translationData?.[lang] + ? translationData[lang].missing + : []; + const missingSnippets = translationData?.[lang] + ? translationData[lang].snippets?.missing || [] + : []; + const missing = [ + ...missingDocs.map((item) => ({ ...item, _isSnippet: false })), + ...missingSnippets.map((item) => ({ ...item, _isSnippet: true })), + ]; + if (!missing || missing.length === 0) { + setStatus("No missing topics to add"); + return; + } + setAdding(true); + setAddProgress(0); + for (const [idx, item] of missing.entries()) { + // copy full metadata and body from sourceNode when available + const sourceNode = item.sourceNode || null; + let relPath; + if (item._isSnippet) { + const baseFile = item.file; + const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); + relPath = `${lang}/snippets/${baseFile}${hasExt ? "" : ".mdx"}`; + } else { + const baseFile = item.file.replace(/^docs\//, ""); + const hasExt = /\.(mdx?|MDX?)$/.test(baseFile); + relPath = `${lang}/docusaurus-plugin-content-docs/current/${baseFile}${hasExt ? "" : ".mdx"}`; + } + const paramsBody = {}; + if (sourceNode) { + paramsBody.title = sourceNode.title || item.title; + if (sourceNode.body) paramsBody.body = sourceNode.body; + if (item._isSnippet) { + if (sourceNode.description) + paramsBody.description = sourceNode.description; + } else { + if (sourceNode.modifiedBy) + paramsBody.modifiedBy = sourceNode.modifiedBy; + if (sourceNode.help !== undefined) + paramsBody.help = sourceNode.help; + if (sourceNode.slug) paramsBody.slug = sourceNode.slug; + if (sourceNode.tags) paramsBody.tags = sourceNode.tags; + if (sourceNode.draft !== undefined) + paramsBody.draft = sourceNode.draft; + if (sourceNode.review !== undefined) + paramsBody.review = sourceNode.review; + if (sourceNode.translate !== undefined) + paramsBody.translate = sourceNode.translate; + if (sourceNode.approved !== undefined) + paramsBody.approved = sourceNode.approved; + if (sourceNode.published !== undefined) + paramsBody.published = sourceNode.published; + if (sourceNode.unlisted !== undefined) + paramsBody.unlisted = sourceNode.unlisted; + } + } else { + paramsBody.title = item.title; + } + // ensure created translations start with required workflow metadata + paramsBody.draft = false; + paramsBody.review = false; + paramsBody.translate = true; + paramsBody.approved = false; + paramsBody.published = false; + paramsBody.unlisted = true; + // set lastmod to one day earlier than source (or yesterday) + let lastmodSource = null; + if (sourceNode?.lastmod) { + lastmodSource = new Date(sourceNode.lastmod); + } else if (item.sourceLastMod && item.sourceLastMod !== "No date") { + try { + const parsed = new Date(item.sourceLastMod); + if (!Number.isNaN(parsed.getTime())) lastmodSource = parsed; + } catch (_e) { + // ignore parse errors + } + } + paramsBody.lastmod = lastmodSource + ? new Date(lastmodSource.getTime() - 1000).toISOString() + : new Date(Date.now() - 1000).toISOString(); + + await client.request({ + query: ` + mutation CreateI18n($collection: String!, $relativePath: String!, $params: DocumentMutation!) { + createDocument(collection: $collection, relativePath: $relativePath, params: $params) { + ... on I18n { + id + } + } + } + `, + variables: { + collection: "i18n", + relativePath: relPath, + params: { i18n: paramsBody }, + }, + }); + + // update progress + try { + const pct = + missing.length > 0 + ? Math.round(((idx + 1) / missing.length) * 100) + : 100; + setAddProgress(pct); + setStatus( + `Adding ${idx + 1}/${missing.length} translations (${pct}%)` + ); + } catch (_e) { + // ignore progress errors + } + } + setStatus(`Added ${missing.length} missing topics for ${lang}`); + await scanTranslations(); + setAddProgress(100); + setTimeout(() => setAddProgress(null), 800); + setAdding(false); + } catch (err) { + setStatus(`Error: ${err.message}`); + setAdding(false); + setAddProgress(null); + } + }; + + // Edit out-of-date doc + const handleEditOutOfDateDoc = (file) => { + const cleanFile = file + .replace(/^docs\//, "") + .replace(/\.mdx$/, "") + .replace(/\.md$/, ""); + window.open( + `/admin#/collections/edit/i18n/${selectedLanguage}/docusaurus-plugin-content-docs/current/${cleanFile}`, + "_blank" + ); + }; + + // Edit out-of-date snippet + const handleEditOutOfDateSnippet = (file) => { + const cleanFile = file.replace(/\.mdx$/, "").replace(/\.md$/, ""); + window.open( + `/admin#/collections/edit/i18n/${selectedLanguage}/snippets/${cleanFile}`, + "_blank" + ); + }; + const [translationData, setTranslationData] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [importing, setImporting] = useState(false); + const [importProgress, setImportProgress] = useState(null); + const [adding, setAdding] = useState(false); + const [addProgress, setAddProgress] = useState(null); + const [selectedLanguage, setSelectedLanguage] = useState("fr"); + + // Handle Import button: open file picker and run verbose GraphQL import + const handleImportClick = async () => { + try { + setImporting(true); + setImportProgress(null); + const input = document.getElementById("xliff-upload"); + if (!input) return; + input.value = ""; + input.click(); + const file = await new Promise((resolve) => { + const onChange = () => { + input.removeEventListener("change", onChange); + const f = input.files?.[0]; + resolve(f); + }; + input.addEventListener("change", onChange); + }); + if (!file) return; + setStatus(`Importing: ${file.name}`); + const text = await file.text(); + const { client } = await import("../../../tina/__generated__/client"); + const _results = await xliffUtils.importXliffBundle( + client, + text, + selectedLanguage, + (p) => { + if (p?.id) + setStatus( + `Import ${p.id}: ${p.status}${p.error ? ` - ${p.error}` : ""}` + ); + if (p && p.progress !== undefined) setImportProgress(p.progress); + } + ); + setStatus("Import complete"); + setImportProgress(100); + setTimeout(() => setImportProgress(null), 800); + setImporting(false); + await scanTranslations(); + } catch (err) { + setStatus(`Import error: ${err?.message ? err.message : String(err)}`); + setImporting(false); + setImportProgress(null); + } + }; + + // (removed separate debug-upload handler) single Import button handles import + + const scanTranslations = async () => { + setLoading(true); + setError(null); + try { + // Build results container + const results = {}; + const { client } = await import("../../../tina/__generated__/client"); + + // Helper to normalize paths for comparison (strip extensions and index/readme) + const canonicalize = (p) => { + if (!p) return p; + let s = p.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); + return s; + }; + + // Fetch docs (source files) with pagination + let docsEdges = []; + let docsAfter = null; + while (true) { + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 100, + after: docsAfter, + }); + const chunk = docsResult.data?.docConnection?.edges || []; + docsEdges = docsEdges.concat(chunk); + const pageInfo = docsResult.data?.docConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + docsAfter = pageInfo.endCursor; + } + const sourceMap = {}; // canonical -> node + for (const edge of docsEdges) { + const node = edge.node; + const rel = node._sys?.relativePath || node._sys?.filename || ""; + // derive clean path by removing only a leading 'docs/' prefix + let clean = rel; + if (rel.startsWith("docs/")) { + clean = rel.replace(/^docs\//, ""); + } + // exclude generated API folder + if (clean.startsWith("api/")) continue; + const canonical = canonicalize(clean || rel); + sourceMap[canonical] = node; + } + + // Fetch snippets with pagination + let snippetsEdges = []; + let snippetsAfter = null; + while (true) { + const snippetsResult = await client.queries.snippetsConnection({ + first: 100, + after: snippetsAfter, + }); + const chunk = snippetsResult.data?.snippetsConnection?.edges || []; + snippetsEdges = snippetsEdges.concat(chunk); + const pageInfo = snippetsResult.data?.snippetsConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + snippetsAfter = pageInfo.endCursor; + } + const snippetSourceMap = {}; + for (const edge of snippetsEdges) { + const node = edge.node; + const rel = node._sys?.relativePath || node._sys?.filename || ""; + const canonical = canonicalize(rel); + snippetSourceMap[canonical] = node; + } + + // Fetch translations and build map for the selected language with pagination + let i18nEdges = []; + let i18nAfter = null; + while (true) { + const i18nResult = await client.queries.i18nConnection({ + sort: "title", + first: 100, + after: i18nAfter, + }); + const chunk = i18nResult.data?.i18nConnection?.edges || []; + i18nEdges = i18nEdges.concat(chunk); + const pageInfo = i18nResult.data?.i18nConnection?.pageInfo; + if (!pageInfo?.hasNextPage) break; + i18nAfter = pageInfo.endCursor; + } + // Build translation maps grouped by language + const translationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } + const snippetTranslationsByLang = {}; // lang -> { canonical -> { node, originalPath, rawPath } } + for (const edge of i18nEdges) { + const node = edge.node; + const relPath = node._sys?.relativePath || node._sys?.filename || ""; + const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); + if (!m) continue; + const lang = m[1]; + const after = m[2]; + const prefix = "docusaurus-plugin-content-docs/current/"; + if (after.startsWith("snippets/")) { + const snippetRel = after.replace(/^snippets\//, ""); + const canonical = canonicalize(snippetRel); + snippetTranslationsByLang[lang] = + snippetTranslationsByLang[lang] || {}; + snippetTranslationsByLang[lang][canonical] = { + node, + originalPath: snippetRel, + rawPath: snippetRel, + }; + continue; + } + if (!after.startsWith(prefix)) continue; + let cleanAfter = after.replace(new RegExp(`^${prefix}`), ""); + // Keep the raw path (before stripping docs/) for Tina API operations + const rawPath = cleanAfter; + // Strip leading 'docs/' to match source doc paths + if (cleanAfter.startsWith("docs/")) { + cleanAfter = cleanAfter.replace(/^docs\//, ""); + } + if (cleanAfter.startsWith("api/") || cleanAfter.startsWith("wiki/")) + continue; + const canonical = canonicalize(cleanAfter); + + translationsByLang[lang] = translationsByLang[lang] || {}; + const translationsMap = translationsByLang[lang]; + + if (translationsMap[canonical]) { + const existing = translationsMap[canonical]; + const isExistingIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test( + existing.originalPath || "" + ); + const isNewIndex = /(?:^|\/)index$|(?:^|\/)readme$/i.test(cleanAfter); + if (isExistingIndex && !isNewIndex) { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } else { + try { + const existingDate = existing.node?.lastmod + ? new Date(existing.node.lastmod) + : null; + const newDate = node?.lastmod ? new Date(node.lastmod) : null; + if (newDate && (!existingDate || newDate > existingDate)) { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } + } catch (_e) { + // keep existing on errors + } + } + } else { + translationsMap[canonical] = { + node, + originalPath: cleanAfter, + rawPath, + }; + } + } + + // For each language, compare with source map and build results + const sourceKeys = new Set(Object.keys(sourceMap)); + // Pre-build a 'missing all' list so empty languages can be shown + const missingAll = []; + for (const key of sourceKeys) { + const src = sourceMap[key]; + const title = src.title || key; + missingAll.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + } + for (const lang of Object.keys(translationsByLang)) { + const translationsMap = translationsByLang[lang] || {}; + const translationKeys = new Set(Object.keys(translationsMap)); + + const missing = []; + const outdated = []; + const upToDate = []; + const orphaned = []; + + for (const key of sourceKeys) { + const src = sourceMap[key]; + const srcDate = src.lastmod ? new Date(src.lastmod) : null; + const title = src.title || key; + if (!translationKeys.has(key)) { + missing.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + continue; + } + const tr = translationsMap[key].node; + const trDate = tr.lastmod ? new Date(tr.lastmod) : null; + if (!srcDate && !trDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: "No date", + translationLastMod: "No date", + title, + }); + } else if (srcDate && !trDate) { + outdated.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: "No date", + title, + }); + } else if (!srcDate && trDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: "No date", + translationLastMod: tr.lastmod, + title, + }); + } else { + if (trDate >= srcDate) { + upToDate.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + }); + } else { + outdated.push({ + file: `docs/${key}`, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + daysBehind: Math.ceil( + (srcDate - trDate) / (1000 * 60 * 60 * 24) + ), + }); + } + } + } + + for (const key of translationKeys) { + if (!sourceKeys.has(key)) { + const entry = translationsMap[key]; + const node = entry.node; + const orig = entry.rawPath || entry.originalPath || key; + orphaned.push({ + file: `${lang}/docusaurus-plugin-content-docs/current/${orig}`, + translationLastMod: node.lastmod || "No date", + title: node.title || orig, + }); + } + } + + results[lang] = { + missing, + outdated, + upToDate, + orphaned, + errors: [], + total: Object.keys(sourceMap).length, + }; + } + + // Get supported languages from the imported docusaurus config, excluding + // the default locale and any English variants (en-*). + const supported = docusaurusData.languages?.supported || []; + const defaultLocale = docusaurusData.languages?.default || "en"; + const langsFromConfig = supported + .filter((l) => l.code !== defaultLocale && !l.code.startsWith("en")) + .map((l) => ({ code: l.code, label: l.label })); + + for (const langEntry of langsFromConfig) { + const fsLang = langEntry.code; + if (!results[fsLang]) { + results[fsLang] = { + missing: missingAll.slice(), + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + }; + } + } + + // If no translations found at all, ensure we still populate selectedLanguage key so UI remains consistent + if (Object.keys(results).length === 0) { + results[selectedLanguage] = { + missing: [], + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + }; + } + + // Build snippet translation results for all languages + const snippetSourceKeys = new Set(Object.keys(snippetSourceMap)); + const missingAllSnippets = []; + for (const key of snippetSourceKeys) { + const src = snippetSourceMap[key]; + missingAllSnippets.push({ + file: key, + sourceLastMod: src.lastmod || "No date", + title: src.title || key, + sourceNode: src, + }); + } + for (const lang of Object.keys(results)) { + const snTrMap = snippetTranslationsByLang[lang] || {}; + const snTrKeys = new Set(Object.keys(snTrMap)); + const snMissing = [], + snOutdated = [], + snUpToDate = [], + snOrphaned = []; + for (const key of snippetSourceKeys) { + const src = snippetSourceMap[key]; + const srcDate = src.lastmod ? new Date(src.lastmod) : null; + const title = src.title || key; + if (!snTrKeys.has(key)) { + snMissing.push({ + file: key, + sourceLastMod: src.lastmod || "No date", + title, + sourceNode: src, + }); + continue; + } + const tr = snTrMap[key].node; + const trDate = tr.lastmod ? new Date(tr.lastmod) : null; + if (!srcDate && !trDate) { + snUpToDate.push({ + file: key, + sourceLastMod: "No date", + translationLastMod: "No date", + title, + }); + } else if (srcDate && !trDate) { + snOutdated.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: "No date", + title, + }); + } else if (!srcDate && trDate) { + snUpToDate.push({ + file: key, + sourceLastMod: "No date", + translationLastMod: tr.lastmod, + title, + }); + } else { + if (trDate >= srcDate) { + snUpToDate.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + }); + } else { + snOutdated.push({ + file: key, + sourceLastMod: src.lastmod, + translationLastMod: tr.lastmod, + title, + daysBehind: Math.ceil( + (srcDate - trDate) / (1000 * 60 * 60 * 24) + ), + }); + } + } + } + for (const key of snTrKeys) { + if (!snippetSourceKeys.has(key)) { + const entry = snTrMap[key]; + const node = entry.node; + const orig = entry.rawPath || entry.originalPath || key; + snOrphaned.push({ + file: `${lang}/snippets/${orig}`, + translationLastMod: node.lastmod || "No date", + title: node.title || orig, + }); + } + } + results[lang].snippets = { + missing: snMissing, + outdated: snOutdated, + upToDate: snUpToDate, + orphaned: snOrphaned, + total: snippetSourceKeys.size, + }; + } + // Handle any snippet-only languages not yet in results + for (const lang of Object.keys(snippetTranslationsByLang)) { + if (!results[lang]) { + results[lang] = { + missing: missingAll.slice(), + outdated: [], + upToDate: [], + orphaned: [], + errors: [], + total: Object.keys(sourceMap).length, + snippets: { + missing: missingAllSnippets.slice(), + outdated: [], + upToDate: [], + orphaned: [], + total: snippetSourceKeys.size, + }, + }; + } + } + + // Ensure selectedLanguage is present in results (pick first available if not) + const langsFound = Object.keys(results); + if (langsFound.length > 0 && !results[selectedLanguage]) { + setSelectedLanguage(langsFound[0]); + } + + setTranslationData(results); + } catch (error) { + setError(`Failed to scan translations: ${error.message}`); + } finally { + setLoading(false); + } + }; + + const formatDate = (dateString) => { + try { + return new Date(dateString).toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + } catch (_error) { + return dateString; + } + }; + + const _getStatusColor = (status) => { + switch (status) { + case "outdated": + return "#f59e0b"; + case "missing": + return "#ff6b6b"; + case "upToDate": + return "#2ed573"; + case "orphaned": + return "#9c88ff"; + default: + return "#747d8c"; + } + }; + + const getTotalCounts = () => { + if (!translationData) return {}; + + return Object.keys(translationData).reduce((acc, lang) => { + const data = translationData[lang]; + const sn = data.snippets || { + missing: [], + outdated: [], + upToDate: [], + orphaned: [], + total: 0, + }; + acc[lang] = { + total: + (data.total || + data.missing.length + data.outdated.length + data.upToDate.length) + + (sn.total || 0), + missing: data.missing.length + sn.missing.length, + outdated: data.outdated.length + sn.outdated.length, + upToDate: data.upToDate.length + sn.upToDate.length, + orphaned: data.orphaned.length + sn.orphaned.length, + errors: data.errors.length, + }; + return acc; + }, {}); + }; + + // Always show the heading and button row, but if not loaded, only show the Load button (no dashboard content) + if (!translationData && !loading && !error) { + return ( +
    +
    +
    + + + + + + + +

    + Translation Dashboard +

    +
    + +
    +
    + ); + } + + if (loading) { + return ( +
    +
    +
    + Loading Dashboard +
    +
    + Scanning translations... +
    + + {/* Progress Bar for Loading */} +
    +
    +
    +
    + +
    + ); + } + + if (error) { + return ( +
    +
    +
    + Error: {error} +
    + +
    +
    + ); + } + + if (!translationData) { + return ( +
    +
    + No translation data available +
    +
    + ); + } + + const totalCounts = getTotalCounts(); + const languages = Object.keys(translationData); + + return ( +
    +
    +
    + + + + + + + +

    + Translation Dashboard +

    +
    +
    + + + + + + + {/* Debug import now runs immediately when a file is selected via Import XLIFF */} +
    +
    + {status && ( +
    {status}
    + )} + + {/* Progress Bars for Async Operations */} + {addProgress !== null && ( +
    +
    + Adding Missing Topics: {addProgress}% +
    +
    +
    +
    +
    + )} + + {importProgress !== null && ( +
    +
    + Importing XLIFF: {importProgress}% +
    +
    +
    +
    +
    + )} + + {loading && ( +
    +
    + Scanning translations... +
    +
    +
    +
    +
    + )} + + + + {/* Translation Statistics Cards */} +
    + {(() => { + const counts = totalCounts[selectedLanguage]; + if (!counts) return null; + + return [ + { + label: "Up to Date", + value: counts.upToDate, + icon: ( + + + + ), + bgColor: "bg-green-100", + iconColor: "text-green-600", + textColor: "text-green-600", + }, + { + label: "Outdated", + value: counts.outdated, + icon: ( + + + + + ), + bgColor: "bg-orange-100", + iconColor: "text-orange-600", + textColor: "text-orange-600", + }, + { + label: "Missing", + value: counts.missing, + icon: ( + + + + + + ), + bgColor: "bg-red-100", + iconColor: "text-red-600", + textColor: "text-red-600", + }, + { + label: "Orphaned", + value: counts.orphaned, + icon: ( + + + + + ), + bgColor: "bg-purple-100", + iconColor: "text-purple-600", + textColor: "text-purple-600", + }, + ].map((stat, index) => ( +
    +
    +
    {stat.icon}
    +
    +
    +

    + {stat.label} +

    +

    + {stat.value} +

    +
    +
    + )); + })()} +
    + + {/* Language Selection */} +
    +
    + + +
    +
    + + {/* Detailed View */} + {(() => { + const data = translationData[selectedLanguage]; + if (!data) return null; + + return ( +
    + {/* Missing Files */} + {data.missing.length > 0 && ( +
    +

    + + + + + Missing Translations ({data.missing.length}) +

    +
    + {data.missing.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    +
    + Source: {formatDate(item.sourceLastMod)} +
    +
    + ))} +
    +
    + )} + + {/* Outdated Files */} + {data.outdated.length > 0 && ( +
    +

    + + + + + Outdated Translations ({data.outdated.length}) +

    +
    + {data.outdated.map((item, index) => ( +
    +
    + {item.title} + +
    +
    + {item.file} + Source: {formatDate(item.sourceLastMod)} +
    +
    + + {item.daysBehind + ? `${item.daysBehind} days behind` + : ""} + + + Translation: {formatDate(item.translationLastMod)} + +
    +
    + ))} +
    +
    + )} + + {/* Up to Date Files */} + {data.upToDate.length > 0 && selectedLanguage !== "all" && ( +
    +

    + + + + Up to Date Translations ({data.upToDate.length}) +

    +
    + {data.upToDate.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    +
    + {formatDate(item.translationLastMod)} +
    +
    + ))} +
    +
    + )} + + {/* Orphaned Files */} + {data.orphaned.length > 0 && ( +
    +

    + + + + + Orphan Topics ({data.orphaned.length}) +

    +
    + {data.orphaned.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    + Translation exists but no source file found +
    +
    +
    + Translation: {formatDate(item.translationLastMod)} +
    +
    + ))} +
    +
    + )} + + {/* Errors */} + {data.errors.length > 0 && ( +
    +

    + + + + + + Errors ({data.errors.length}) +

    +
    + {data.errors.map((item, index) => ( +
    +
    + {item.file} +
    +
    + {item.error} +
    +
    + ))} +
    +
    + )} + + {/* Snippets Section */} + {data.snippets && data.snippets.total > 0 && ( +
    +

    + + + + + + + + Snippets +

    + + {/* Missing Snippets */} + {data.snippets.missing.length > 0 && ( +
    +

    + + + + + Missing Snippet Translations ( + {data.snippets.missing.length}) +

    +
    + {data.snippets.missing.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    +
    + ))} +
    +
    + )} + + {/* Outdated Snippets */} + {data.snippets.outdated.length > 0 && ( +
    +

    + + + + + Outdated Snippet Translations ( + {data.snippets.outdated.length}) +

    +
    + {data.snippets.outdated.map((item, index) => ( +
    +
    + + {item.title} + + +
    +
    + {item.file} + + Source: {formatDate(item.sourceLastMod)} + +
    +
    + + {item.daysBehind + ? `${item.daysBehind} days behind` + : ""} + + + Translation: {formatDate(item.translationLastMod)} + +
    +
    + ))} +
    +
    + )} + + {/* Up to Date Snippets */} + {data.snippets.upToDate.length > 0 && ( +
    +

    + + + + Up to Date Snippet Translations ( + {data.snippets.upToDate.length}) +

    +
    + {data.snippets.upToDate.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    +
    + {formatDate(item.translationLastMod)} +
    +
    + ))} +
    +
    + )} + + {/* Orphaned Snippets */} + {data.snippets.orphaned.length > 0 && ( +
    +

    + + + + + Orphan Snippets ({data.snippets.orphaned.length}) +

    +
    + {data.snippets.orphaned.map((item, index) => ( +
    +
    + {item.title} +
    + {item.file} +
    +
    + Translation exists but no source snippet found +
    +
    +
    + Translation: {formatDate(item.translationLastMod)} +
    +
    + ))} +
    +
    + )} +
    + )} +
    + ); + })()} +
    + ); +}; + +export default TranslationDashboard; diff --git a/template/src/components/Dashboard/template.jsx b/template/src/components/Dashboard/template.jsx index c691933e..c2818611 100644 --- a/template/src/components/Dashboard/template.jsx +++ b/template/src/components/Dashboard/template.jsx @@ -1,144 +1,152 @@ -/** - * Copyright (c) Source Solutions, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React from 'react'; -import Dashboard1 from './Dashboard1'; -import MediaDashboard from './MediaDashboard'; -import TranslationDashboard from './TranslationDashboard'; -import BrokenLinksDashboard from './BrokenLinksDashboard'; -import ContentReuseDashboard from './ContentReuseDashboard'; -import StatusBar from './StatusBar'; -import HelpButton from '../HelpButton'; -//. import DocumentMutationDashboard from './DocumentMutationDashboard'; - -export const DashboardsCollection = { - name: "dashboards", - label: "Dashboards", - path: "static/dashboards", - format: "json", - ui: { - allowedActions: { - create: false, - delete: false, - }, - }, - fields: [ - { - type: "boolean", - name: "statusBar", - label: "", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - { - type: "boolean", - name: "help", - label: "Help", - required: false, - ui: { - component: (props) => ( - - ), - }, - }, - { - type: "boolean", - name: "dashboard1", - label: "Content Overview", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - { - type: "boolean", - name: "contentReuseDashboard", - label: "Content Reuse Overview", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - { - type: "boolean", - name: "mediaDashboard", - label: "Media Library", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - { - type: "boolean", - name: "translationDashboard", - label: "Translation Status", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - { - type: "boolean", - name: "brokenLinksDashboard", - label: "Broken Links", - required: false, - ui: { - component: (props) => ( -
    - -
    - ), - }, - }, - - // { - // type: "boolean", - // name: "documentMutationDashboard", - // label: "Document Mutations", - // required: false, - // ui: { - // component: (props) => ( - // - // ), - // }, - // }, - ], -}; - -export { Dashboard1, MediaDashboard, TranslationDashboard, BrokenLinksDashboard, StatusBar }; +/** + * Copyright (c) Source Solutions, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from "react"; +import HelpButton from "../HelpButton"; +import BrokenLinksDashboard from "./BrokenLinksDashboard"; +import ContentReuseDashboard from "./ContentReuseDashboard"; +import Dashboard1 from "./Dashboard1"; +import MediaDashboard from "./MediaDashboard"; +import StatusBar from "./StatusBar"; +import TranslationDashboard from "./TranslationDashboard"; +//. import DocumentMutationDashboard from './DocumentMutationDashboard'; + +export const DashboardsCollection = { + name: "dashboards", + label: "Dashboards", + path: "static/dashboards", + format: "json", + ui: { + allowedActions: { + create: false, + delete: false, + }, + }, + fields: [ + { + type: "boolean", + name: "statusBar", + label: "", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + { + type: "boolean", + name: "help", + label: "Help", + required: false, + ui: { + component: (props) => ( + + ), + }, + }, + { + type: "boolean", + name: "dashboard1", + label: "Content Overview", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + { + type: "boolean", + name: "contentReuseDashboard", + label: "Content Reuse Overview", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + { + type: "boolean", + name: "mediaDashboard", + label: "Media Library", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + { + type: "boolean", + name: "translationDashboard", + label: "Translation Status", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + { + type: "boolean", + name: "brokenLinksDashboard", + label: "Broken Links", + required: false, + ui: { + component: (_props) => ( +
    + +
    + ), + }, + }, + + // { + // type: "boolean", + // name: "documentMutationDashboard", + // label: "Document Mutations", + // required: false, + // ui: { + // component: (props) => ( + // + // ), + // }, + // }, + ], +}; + +export { + BrokenLinksDashboard, + Dashboard1, + MediaDashboard, + StatusBar, + TranslationDashboard, +}; diff --git a/template/src/components/Features/template.jsx b/template/src/components/Features/template.jsx index 3e287e23..97b15ff7 100644 --- a/template/src/components/Features/template.jsx +++ b/template/src/components/Features/template.jsx @@ -1,3 +1,4 @@ +import React from "react"; /** * Copyright (c) Source Solutions, Inc. * @@ -5,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -import React from "react"; - export const FeaturesBlockTemplate = { name: "features", label: "Features", diff --git a/template/src/components/Figure/index.jsx b/template/src/components/Figure/index.jsx index c6a00792..6fe17052 100644 --- a/template/src/components/Figure/index.jsx +++ b/template/src/components/Figure/index.jsx @@ -5,7 +5,63 @@ * LICENSE file in the root directory of this source tree. */ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; + +// Depends on nothing, so it lives at module scope rather than being rebuilt on +// every render. +const lightboxStyles = { + overlay: { + position: "fixed", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "rgba(0, 0, 0, 0.8)", + display: "flex", + alignItems: "center", + justifyContent: "center", + zIndex: 9999, + cursor: "pointer", + border: "none", + padding: 0, + }, + content: { + maxWidth: "90vw", + maxHeight: "90vh", + position: "relative", + }, + image: { + maxWidth: "100%", + maxHeight: "100%", + objectFit: "contain", + }, + closeButton: { + position: "absolute", + top: "-40px", + right: "0", + color: "white", + fontSize: "24px", + cursor: "pointer", + background: "none", + border: "none", + padding: "8px", + }, + caption: { + color: "white", + textAlign: "center", + marginTop: "10px", + fontSize: "14px", + }, + thumbnailButton: { + background: "none", + border: "none", + padding: 0, + cursor: "pointer", + display: "inline", + font: "inherit", + color: "inherit", + }, +}; const Figure = ({ img, caption, size, hideCaption = false, align }) => { const [isLightboxOpen, setIsLightboxOpen] = useState(false); @@ -24,77 +80,74 @@ const Figure = ({ img, caption, size, hideCaption = false, align }) => { return "center"; }; - const lightboxStyles = { - overlay: { - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0, 0, 0, 0.8)", - display: "flex", - alignItems: "center", - justifyContent: "center", - zIndex: 9999, - cursor: "pointer", - }, - content: { - maxWidth: "90vw", - maxHeight: "90vh", - position: "relative", - }, - image: { - maxWidth: "100%", - maxHeight: "100%", - objectFit: "contain", - }, - closeButton: { - position: "absolute", - top: "-40px", - right: "0", - color: "white", - fontSize: "24px", - cursor: "pointer", - background: "none", - border: "none", - padding: "8px", - }, - caption: { - color: "white", - textAlign: "center", - marginTop: "10px", - fontSize: "14px", - }, - }; + // Close on Escape and lock background scrolling while the lightbox is open. + useEffect(() => { + if (!isLightboxOpen) return; + + const onKeyDown = (e) => { + if (e.key === "Escape") setIsLightboxOpen(false); + }; + document.addEventListener("keydown", onKeyDown); + + const previousOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + + return () => { + document.removeEventListener("keydown", onKeyDown); + document.body.style.overflow = previousOverflow; + }; + }, [isLightboxOpen]); + + // An image with no caption would otherwise render with no alt text at all. + const altText = caption || "Figure"; return ( <>
    - {caption} + aria-label={`Enlarge image: ${altText}`} + style={{ ...lightboxStyles.thumbnailButton, width: imageWidth }} + > + {altText} + {!hideCaption &&
    {caption}
    }
    {isLightboxOpen && ( -
    + // biome-ignore lint/a11y/noStaticElementInteractions: click-to-dismiss backdrop; Escape and the close button provide the keyboard path +
    e.stopPropagation()} + role="dialog" + aria-modal="true" + aria-label={altText} > - {caption} + {altText} {caption &&
    {caption}
    }
    diff --git a/template/src/components/Figure/template.jsx b/template/src/components/Figure/template.jsx index 5d52a98c..756cd0d4 100644 --- a/template/src/components/Figure/template.jsx +++ b/template/src/components/Figure/template.jsx @@ -32,13 +32,15 @@ export const FigureBlockTemplate = { name: "size", label: "Size (%)", type: "number", - description: "Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)", + description: + "Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)", }, { name: "align", label: "Alignment", type: "string", - description: "Align the image left or right (only applies when size is less than 100)", + description: + "Align the image left or right (only applies when size is less than 100)", options: [ { value: "left", label: "Left" }, { value: "center", label: "Center" }, diff --git a/template/src/components/Footnote/FootnotesList.jsx b/template/src/components/Footnote/FootnotesList.jsx index d82faa6b..45431f44 100644 --- a/template/src/components/Footnote/FootnotesList.jsx +++ b/template/src/components/Footnote/FootnotesList.jsx @@ -12,33 +12,18 @@ const FootnotesList = () => { const context = useContext(FootnotesContext); const [footnotes, setFootnotes] = useState([]); + // As in Footnote/index.jsx, the context default always supplies these, so the + // former window.globalFootnotes fallbacks were unreachable. useEffect(() => { - if (context?.footnotes) { - // Use context footnotes if available - setFootnotes(context.footnotes); - } else if (typeof window !== "undefined" && window.globalFootnotes) { - // Fallback to global footnotes - setFootnotes(window.globalFootnotes); - } else { - setFootnotes([]); - } - }, [context?.footnotes]); + setFootnotes(context.footnotes); + }, [context.footnotes]); // Clear footnotes when component unmounts (page navigation) useEffect(() => { - if (context?.clearFootnotes) { - return () => { - context.clearFootnotes(); - }; - } - // Clear global footnotes return () => { - if (typeof window !== "undefined") { - window.globalFootnotes = []; - window.globalFootnoteMap = new Map(); - } + context.clearFootnotes(); }; - }, [context?.clearFootnotes]); + }, [context.clearFootnotes]); if (!footnotes || footnotes.length === 0) { return null; diff --git a/template/src/components/Footnote/FootnotesProvider.jsx b/template/src/components/Footnote/FootnotesProvider.jsx index 69c26567..0374b89e 100644 --- a/template/src/components/Footnote/FootnotesProvider.jsx +++ b/template/src/components/Footnote/FootnotesProvider.jsx @@ -5,7 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -import React, { createContext, useCallback, useRef, useState } from "react"; +import React, { + createContext, + useCallback, + useMemo, + useRef, + useState, +} from "react"; import { generateFootnoteKey } from "./utils"; // Create context with default values @@ -48,15 +54,22 @@ export const FootnotesProvider = ({ children }) => { footnoteCountRef.current = 0; }, []); - const value = { - footnotes, - addFootnote, - clearFootnotes, - getFootnoteNumber: (content) => { - const contentKey = generateFootnoteKey(content); - return footnoteMapRef.current.get(contentKey); - }, - }; + const getFootnoteNumber = useCallback((content) => { + const contentKey = generateFootnoteKey(content); + return footnoteMapRef.current.get(contentKey); + }, []); + + // Memoised: rebuilding this object every render re-rendered every consumer + // and defeated the useCallback wrappers above it. + const value = useMemo( + () => ({ + footnotes, + addFootnote, + clearFootnotes, + getFootnoteNumber, + }), + [footnotes, addFootnote, clearFootnotes, getFootnoteNumber] + ); return ( diff --git a/template/src/components/Footnote/index.jsx b/template/src/components/Footnote/index.jsx index 7102928d..d6442381 100644 --- a/template/src/components/Footnote/index.jsx +++ b/template/src/components/Footnote/index.jsx @@ -7,45 +7,17 @@ import React, { useContext, useEffect, useState } from "react"; import { FootnotesContext } from "./FootnotesProvider"; -import { generateFootnoteKey } from "./utils"; const Footnote = ({ children }) => { const context = useContext(FootnotesContext); const [footnoteNumber, setFootnoteNumber] = useState(null); + // FootnotesContext is created with a default value that already provides + // addFootnote, so this is always defined — the previous window.globalFootnotes + // fallback below it was unreachable and has been removed. useEffect(() => { - // Safely convert content to string for comparison - const contentKey = generateFootnoteKey(children); - - if (context?.addFootnote) { - // Use context if available - const number = context.addFootnote(children); - setFootnoteNumber(number); - } else { - // Fallback to global state - if (typeof window !== "undefined") { - if (!window.globalFootnotes) window.globalFootnotes = []; - if (!window.globalFootnoteMap) window.globalFootnoteMap = new Map(); - - if (window.globalFootnoteMap.has(contentKey)) { - const number = window.globalFootnoteMap.get(contentKey); - setFootnoteNumber(number); - } else { - const newNumber = window.globalFootnotes.length + 1; - window.globalFootnotes.push({ - number: newNumber, - content: children, - key: contentKey, - }); - window.globalFootnoteMap.set(contentKey, newNumber); - setFootnoteNumber(newNumber); - } - } else { - // Server-side rendering fallback - setFootnoteNumber(1); - } - } - }, [children, context?.addFootnote]); + setFootnoteNumber(context.addFootnote(children)); + }, [children, context.addFootnote]); const handleClick = (e) => { e.preventDefault(); diff --git a/template/src/components/Footnote/utils.jsx b/template/src/components/Footnote/utils.jsx index f5670d0f..cf2c138d 100644 --- a/template/src/components/Footnote/utils.jsx +++ b/template/src/components/Footnote/utils.jsx @@ -24,7 +24,7 @@ export const generateFootnoteKey = (content) => { } if (typeof content === "object" && content !== null) { // For objects, try to stringify safely - return JSON.stringify(content, (key, value) => { + return JSON.stringify(content, (_key, value) => { if (typeof value === "object" && value !== null) { // Skip React internal properties that can cause circular references if (value._owner || value._store || value._source || value._self) { @@ -39,8 +39,8 @@ export const generateFootnoteKey = (content) => { }); } return String(content); - } catch (error) { - return `fallback-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + } catch { + return `fallback-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`; } }; diff --git a/template/src/components/GlossaryTerm/index.jsx b/template/src/components/GlossaryTerm/index.jsx index 5b95b5e6..700a9293 100644 --- a/template/src/components/GlossaryTerm/index.jsx +++ b/template/src/components/GlossaryTerm/index.jsx @@ -57,11 +57,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { // Add debug mode - uncomment next line to force touch mode for testing // return true; // TEMPORARY: Force touch mode for testing - return ( - "ontouchstart" in window || - navigator.maxTouchPoints > 0 || - navigator.msMaxTouchPoints > 0 - ); + return "ontouchstart" in window || navigator.maxTouchPoints > 0; }; setIsTouchDevice(checkTouchDevice()); @@ -94,52 +90,6 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { } }, [showDefinition, isTouchDevice]); - // Position the definition box to avoid screen overflow - const getDefinitionStyle = () => { - if (!termRef.current || !showDefinition) return {}; - - const termRect = termRef.current.getBoundingClientRect(); - const viewportWidth = window.innerWidth; - const viewportHeight = window.innerHeight; - - // Default positioning below the term - let top = termRect.bottom + 8; - let left = termRect.left; - - // Estimated definition box width (will be adjusted by CSS max-width) - const estimatedWidth = Math.min(300, viewportWidth - 20); - - // Check if definition would overflow right edge - if (left + estimatedWidth > viewportWidth - 10) { - left = viewportWidth - estimatedWidth - 10; - } - - // Check if definition would overflow left edge - if (left < 10) { - left = 10; - } - - // Check if definition would overflow bottom edge - // Estimate height as roughly 100px (will be adjusted by content) - const estimatedHeight = 100; - if (top + estimatedHeight > viewportHeight - 10) { - // Position above the term instead - top = termRect.top - estimatedHeight - 8; - - // If still overflowing top, position at top of viewport - if (top < 10) { - top = 10; - } - } - - return { - position: "fixed", - top: `${top}px`, - left: `${left}px`, - zIndex: 2147483647, // Maximum z-index value - }; - }; - const handleTermClick = () => { if (isTouchDevice) { setShowDefinition(!showDefinition); @@ -212,9 +162,15 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { }; const { term, definition } = getTermData(); - - // Create the definition box component - const DefinitionBox = () => { + const displayTerm = + initcap && term !== "TERM NOT FOUND" + ? term.charAt(0).toUpperCase() + term.slice(1) + : term; + + // Rendered inline rather than declared as a component: a component defined + // in the render body gets a new identity every render, which made React + // unmount and remount the popup continuously while it was open. + const renderDefinitionBox = () => { if (!termRef.current) return null; const termRect = termRef.current.getBoundingClientRect(); @@ -261,6 +217,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { return (
    { color: textColor, }} > - {initcap && term !== "TERM NOT FOUND" - ? term.charAt(0).toUpperCase() + term.slice(1) - : term} + {displayTerm}
    {definition}
    @@ -301,10 +256,18 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { return ( <> - { onClick={handleTermClick} onTouchStart={isTouchDevice ? (e) => e.stopPropagation() : undefined} > - {initcap && term !== "TERM NOT FOUND" - ? term.charAt(0).toUpperCase() + term.slice(1) - : term} - + {displayTerm} + {isTouchDevice && showDefinition && @@ -335,7 +296,7 @@ const GlossaryTerm = ({ termKey, lang, initcap, bold }) => { zIndex: "999999999", }} > - + {renderDefinitionBox()}
    , portalElement )} diff --git a/template/src/components/HelpButton/index.jsx b/template/src/components/HelpButton/index.jsx index 81b3e523..0533dabd 100644 --- a/template/src/components/HelpButton/index.jsx +++ b/template/src/components/HelpButton/index.jsx @@ -99,14 +99,14 @@ export default function HelpButton({ url }) { const unwantedLinks = document.querySelectorAll( 'a[href="#/collections/generated/~"], a[href="#/collections/media/~"]' ); - unwantedLinks.forEach((link) => { + for (const link of unwantedLinks) { const li = link.closest("li"); if (li) { li.remove(); } else { link.remove(); } - }); + } }; // Inject custom TinaCMS styles @@ -189,8 +189,9 @@ export default function HelpButton({ url }) { // which bypasses beforeunload (e.g. TinaCMS left nav links). const originalPushState = history.pushState.bind(history); const originalReplaceState = history.replaceState.bind(history); - const guardNavigation = (original) => - function (...args) { + const guardNavigation = + (original) => + (...args) => { if (hasUnsavedChanges()) { const confirmed = window.confirm( "You have unsaved changes. Leave without saving?" @@ -207,23 +208,24 @@ export default function HelpButton({ url }) { window.location.hostname === "127.0.0.1" ) { const autoSaveTimeout = setTimeout(() => { - autoSaveInterval = setInterval(() => { - if (isNewDocumentPage()) return; - const saveBtn = Array.from(document.querySelectorAll("button")).find( - (b) => - b.textContent?.trim() === "Save" && - !b.disabled && - b.offsetParent !== null - ); - if (saveBtn) { - saveBtn.click(); - lastAutoSaveAt = Date.now(); - console.log( - `[TinaCMS Auto-Save] Saved at ${new Date().toLocaleTimeString()}` + autoSaveInterval = setInterval( + () => { + if (isNewDocumentPage()) return; + const saveBtn = Array.from( + document.querySelectorAll("button") + ).find( + (b) => + b.textContent?.trim() === "Save" && + !b.disabled && + b.offsetParent !== null ); - } - }, 5 * 60 * 1000); - console.log("[TinaCMS Auto-Save] Active — checking every 5m (local only, skips new documents)"); + if (saveBtn) { + saveBtn.click(); + lastAutoSaveAt = Date.now(); + } + }, + 5 * 60 * 1000 + ); }, 3000); return () => { @@ -245,7 +247,7 @@ export default function HelpButton({ url }) { history.pushState = originalPushState; history.replaceState = originalReplaceState; }; - }, []); + }, [url]); return null; } diff --git a/template/src/components/Hero/template.jsx b/template/src/components/Hero/template.jsx index 64f5ab63..a30114bf 100644 --- a/template/src/components/Hero/template.jsx +++ b/template/src/components/Hero/template.jsx @@ -1,3 +1,4 @@ +import React from "react"; /** * Copyright (c) Source Solutions, Inc. * @@ -5,8 +6,6 @@ * LICENSE file in the root directory of this source tree. */ -import React from "react"; - export const HeroBlockTemplate = { name: "hero", label: "Hero", diff --git a/template/src/components/Passthrough/index.jsx b/template/src/components/Passthrough/index.jsx index 4d3cbcfe..05653d84 100644 --- a/template/src/components/Passthrough/index.jsx +++ b/template/src/components/Passthrough/index.jsx @@ -10,8 +10,8 @@ import Markdown from "react-markdown"; import rehypeKatex from "rehype-katex"; import rehypeRaw from "rehype-raw"; import remarkBreaks from "remark-breaks"; -import remarkMath from "remark-math"; import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; import "katex/dist/katex.min.css"; // Import KaTeX CSS // Import available components that can be used in JSX @@ -23,62 +23,66 @@ import ColorGenerator from "@site/src/components/ColorGenerator"; * @param {string} string - The content to render * @param {string} type - The content type: 'jsx', 'html', 'markdown', 'code', or 'auto' (default) */ -const Passthrough = ({ summary, string, type }) => { - // Custom input renderer to make task list checkboxes interactive - const CustomInput = ({ disabled, style, ...props }) => { - // Remove disabled attribute from task list checkboxes and add readOnly - if (props.type === "checkbox") { - return ; - } - return ; - }; +const Passthrough = ({ string, type }) => { + // Custom input renderer to make task list checkboxes interactive + const CustomInput = ({ disabled, style, ...props }) => { + // Remove disabled attribute from task list checkboxes and add readOnly + if (props.type === "checkbox") { + return ; + } + return ; + }; - // Custom ul renderer with static CSS-only indentation - const CustomUl = ({ className, children, ...props }) => { - const isTaskList = className?.includes('contains-task-list'); - - if (isTaskList) { - return ( -
      - {children} -
    - ); - } - - return ( -
      - {children} -
    - ); - }; + // Custom ul renderer with static CSS-only indentation + const CustomUl = ({ className, children, ...props }) => { + const isTaskList = className?.includes("contains-task-list"); - // Custom li renderer with proper task list styling - const CustomLi = ({ className, children, ...props }) => { - const isTaskListItem = className?.includes('task-list-item'); - + if (isTaskList) { return ( -
  • {children} -
  • + ); - }; + } + + return ( +
      + {children} +
    + ); + }; + + // Custom li renderer with proper task list styling + const CustomLi = ({ className, children, ...props }) => { + const isTaskListItem = className?.includes("task-list-item"); + + return ( +
  • + {children} +
  • + ); + }; if (!string) return null; - + // Process ^ symbols for indentation (each ^ = 2 spaces) const processedString = string.replace(/\^/g, " "); diff --git a/template/src/components/RelatedTopics/index.jsx b/template/src/components/RelatedTopics/index.jsx index 7c54a6be..8a020d7e 100644 --- a/template/src/components/RelatedTopics/index.jsx +++ b/template/src/components/RelatedTopics/index.jsx @@ -5,12 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import { useLocation } from "@docusaurus/router"; -import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Link from "@docusaurus/Link"; -import React from "react"; +import { useLocation } from "@docusaurus/router"; // Import the generated static metadata import docsMetadata from "@site/src/data/docs-metadata.json"; +import React from "react"; /** * RelatedTopics component for Tina CMS @@ -26,19 +25,21 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Get current page metadata from static data const getCurrentPageMetadata = () => { const currentPath = location.pathname; - + // Remove /docs prefix if present to match metadata format - const normalizedPath = currentPath.startsWith('/docs') - ? currentPath.replace('/docs', '') + const normalizedPath = currentPath.startsWith("/docs") + ? currentPath.replace("/docs", "") : currentPath; - + // Find current page in static docs metadata - const currentDoc = docsMetadata.find(doc => { + const currentDoc = docsMetadata.find((doc) => { // Handle different path variations const docPath = doc.path; - return docPath === normalizedPath || - docPath === normalizedPath.replace(/\/$/, '') || - `${docPath}/` === normalizedPath; + return ( + docPath === normalizedPath || + docPath === normalizedPath.replace(/\/$/, "") || + `${docPath}/` === normalizedPath + ); }); return currentDoc; @@ -46,26 +47,33 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Calculate tag similarity between two arrays of tags const calculateSimilarity = (currentTags, otherTags) => { - if (!currentTags || !otherTags || !currentTags.length || !otherTags.length) { + if ( + !currentTags || + !otherTags || + !currentTags.length || + !otherTags.length + ) { return 0; } const currentTagsSet = new Set(currentTags); const otherTagsSet = new Set(otherTags); - + // Calculate intersection - const intersection = new Set([...currentTagsSet].filter(tag => otherTagsSet.has(tag))); - + const intersection = new Set( + [...currentTagsSet].filter((tag) => otherTagsSet.has(tag)) + ); + // Calculate union const union = new Set([...currentTagsSet, ...otherTagsSet]); - + // Jaccard similarity coefficient return intersection.size / union.size; }; // Get related topics based on tag similarity const getRelatedTopics = (currentDoc) => { - if (!currentDoc || !currentDoc.tags) { + if (!currentDoc?.tags) { return []; } @@ -74,17 +82,15 @@ const RelatedTopics = ({ maxResults = 5 }) => { // Find related docs const relatedDocs = docsMetadata - .filter(doc => { + .filter((doc) => { // Exclude current document and docs without tags - return doc.path !== currentPath && - doc.tags && - Array.isArray(doc.tags); + return doc.path !== currentPath && doc.tags && Array.isArray(doc.tags); }) - .map(doc => ({ + .map((doc) => ({ ...doc, - similarity: calculateSimilarity(currentTags, doc.tags) + similarity: calculateSimilarity(currentTags, doc.tags), })) - .filter(doc => doc.similarity > 0) // Only include docs with some similarity + .filter((doc) => doc.similarity > 0) // Only include docs with some similarity .sort((a, b) => { // Sort by similarity first, then by title for consistent ordering if (b.similarity !== a.similarity) { @@ -98,8 +104,8 @@ const RelatedTopics = ({ maxResults = 5 }) => { }; const currentDoc = getCurrentPageMetadata(); - - if (!currentDoc || !currentDoc.tags) { + + if (!currentDoc?.tags) { return null; } @@ -115,12 +121,11 @@ const RelatedTopics = ({ maxResults = 5 }) => {
      {relatedTopics.map((topic, index) => (
    • - - {topic.title} - + {topic.title} {topic.description && ( - {" – "}{topic.description} + {" – "} + {topic.description} )}
    • @@ -130,4 +135,4 @@ const RelatedTopics = ({ maxResults = 5 }) => { ); }; -export default RelatedTopics; \ No newline at end of file +export default RelatedTopics; diff --git a/template/src/components/RelatedTopics/template.jsx b/template/src/components/RelatedTopics/template.jsx index 08bbc8bd..8dd3bb5a 100644 --- a/template/src/components/RelatedTopics/template.jsx +++ b/template/src/components/RelatedTopics/template.jsx @@ -12,8 +12,8 @@ export const RelatedTopicsBlockTemplate = { ui: { itemProps: (item) => { const maxResults = item?.maxResults || 5; - return { - label: `Related Topics (max: ${maxResults})` + return { + label: `Related Topics (max: ${maxResults})`, }; }, }, @@ -32,4 +32,4 @@ export const RelatedTopicsBlockTemplate = { }, }, ], -}; \ No newline at end of file +}; diff --git a/template/src/components/Settings/template.jsx b/template/src/components/Settings/template.jsx index 2d77d750..0fc61d82 100644 --- a/template/src/components/Settings/template.jsx +++ b/template/src/components/Settings/template.jsx @@ -7,32 +7,15 @@ import React from "react"; import { ImageField, ReferenceField, TextField } from "tinacms"; -import docusaurusData from "../../../config/docusaurus/index.json"; import CollapsibleField from "../CollapsibleField"; import HelpButton from "../HelpButton"; -// Function to create language options from config data -function createLanguageOptions(configData = docusaurusData) { - const supportedLanguages = configData.languages?.supported || [ - { code: "en", label: "English" }, - ]; - - return supportedLanguages.map((langObj) => { - return { - value: langObj.code, - label: `${langObj.label} (${langObj.code})`, - }; - }); -} - -const languageOptions = createLanguageOptions(); - const WarningIcon = (props) => { return ( { const RestartWarning = () => { return ( -

      +

      @@ -55,10 +38,37 @@ const RestartWarning = () => { after saving (local development only).
      -

      +
      ); }; +// Navbar item fields live inside an object list, so each component receives a +// `field.name` such as "navbar.items.3.docLink". Which of the link-detail +// fields is shown depends on the sibling `link` value on the same item. +// (`doc` intentionally shows two: the reference picker and the anchor id.) +const showWhenLinkIs = (expected, Field) => (props) => { + const link = React.useMemo(() => { + const fieldName = props.field.name; + const parentPath = + fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; + // Guarded walk: an incomplete path used to throw and take the whole + // settings form down. + const parent = parentPath + .split(".") + .reduce( + (o, key) => (o == null ? undefined : o[key]), + props.tinaForm.values + ); + return parent?.link; + }, [props.tinaForm.values, props.field.name]); + + if (link !== expected) { + return null; + } + + return Field(props); +}; + const NavbarItemFields = [ { name: "label", @@ -120,23 +130,7 @@ const NavbarItemFields = [ type: "reference", collections: ["doc"], ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "doc") { - return null; - } - - return ReferenceField(props); - }, + component: showWhenLinkIs("doc", ReferenceField), }, }, { @@ -145,23 +139,7 @@ const NavbarItemFields = [ type: "reference", collections: ["pages"], ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "page") { - return null; - } - - return ReferenceField(props); - }, + component: showWhenLinkIs("page", ReferenceField), }, }, { @@ -169,23 +147,7 @@ const NavbarItemFields = [ label: "URL", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "external") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("external", TextField), }, }, { @@ -193,23 +155,7 @@ const NavbarItemFields = [ label: "Manual Path", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "manualPath") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("manualPath", TextField), }, }, { @@ -217,23 +163,7 @@ const NavbarItemFields = [ label: "Document ID", type: "string", ui: { - component: (props) => { - const link = React.useMemo(() => { - let fieldName = props.field.name; - fieldName = - fieldName.substring(0, fieldName.lastIndexOf(".")) || fieldName; - - return fieldName - .split(".") - .reduce((o, i) => o[i], props.tinaForm.values).link; - }, [props.tinaForm.values, props.field.name]); - - if (link !== "doc") { - return null; - } - - return TextField(props); - }, + component: showWhenLinkIs("doc", TextField), }, }, { diff --git a/template/src/components/Snippet/index.jsx b/template/src/components/Snippet/index.jsx index 74b4b6d1..df83f7a2 100644 --- a/template/src/components/Snippet/index.jsx +++ b/template/src/components/Snippet/index.jsx @@ -32,14 +32,14 @@ const Snippet = ({ filepath }) => { ); } if (isMounted) setSnippetMDX(() => mod.default); - } catch (e) { + } catch (_e) { try { const mod = await import( /* webpackInclude: /\.mdx$/ */ `@site/reuse/snippets/${filepath}` ); if (isMounted) setSnippetMDX(() => mod.default); - } catch (e2) { + } catch (_e2) { if (isMounted) setError("Error: Snippet not found."); } } diff --git a/template/src/components/StatusField/index.jsx b/template/src/components/StatusField/index.jsx index f2d0bd4a..aede97a6 100644 --- a/template/src/components/StatusField/index.jsx +++ b/template/src/components/StatusField/index.jsx @@ -8,7 +8,7 @@ import React from "react"; import { wrapFieldsWithMeta } from "tinacms"; -const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { +const StatusField = wrapFieldsWithMeta(({ tinaForm }) => { // All boolean field names involved in the workflow const allBooleans = [ "draft", @@ -21,16 +21,65 @@ const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { // Each workflow status maps to exactly which booleans should be true const statusMap = { - draft: { draft: true, review: false, translate: false, approved: false, published: false, unlisted: false }, - review: { draft: false, review: true, translate: false, approved: false, published: false, unlisted: true }, - translate: { draft: false, review: false, translate: true, approved: false, published: false, unlisted: true }, - approved: { draft: false, review: false, translate: false, approved: true, published: true, unlisted: false }, - published: { draft: false, review: false, translate: false, approved: false, published: true, unlisted: false }, - unlisted: { draft: false, review: false, translate: false, approved: false, published: false, unlisted: true }, + draft: { + draft: true, + review: false, + translate: false, + approved: false, + published: false, + unlisted: false, + }, + review: { + draft: false, + review: true, + translate: false, + approved: false, + published: false, + unlisted: true, + }, + translate: { + draft: false, + review: false, + translate: true, + approved: false, + published: false, + unlisted: true, + }, + approved: { + draft: false, + review: false, + translate: false, + approved: true, + published: true, + unlisted: false, + }, + published: { + draft: false, + review: false, + translate: false, + approved: false, + published: true, + unlisted: false, + }, + unlisted: { + draft: false, + review: false, + translate: false, + approved: false, + published: false, + unlisted: true, + }, }; // The UI options in display order - const statusOptions = ["draft", "review", "translate", "approved", "published", "unlisted"]; + const statusOptions = [ + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", + ]; // Determine which single workflow status is currently active based on the boolean combination const getCurrentStatus = () => { @@ -41,7 +90,14 @@ const StatusField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { // Match against statusMap in reverse-priority order (most specific first) // Order matters: approved (published+approved) must be checked before published (published only) - const checkOrder = ["review", "translate", "approved", "published", "unlisted", "draft"]; + const checkOrder = [ + "review", + "translate", + "approved", + "published", + "unlisted", + "draft", + ]; for (const status of checkOrder) { const expected = statusMap[status]; const match = allBooleans.every((b) => !!expected[b] === !!vals[b]); diff --git a/template/src/components/TagsField/index.jsx b/template/src/components/TagsField/index.jsx index ae978bee..809f84e0 100644 --- a/template/src/components/TagsField/index.jsx +++ b/template/src/components/TagsField/index.jsx @@ -8,14 +8,18 @@ import React, { useMemo, useState } from "react"; import { wrapFieldsWithMeta } from "tinacms"; -const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { +// Module-level constants: `field.options || []` produced a fresh array identity +// on every render, so the memos below never hit their cache. +const NO_TAGS = []; + +const TagsField = wrapFieldsWithMeta(({ input, field }) => { const [searchTerm, setSearchTerm] = useState(""); const [isOpen, setIsOpen] = useState(false); const [expandedNodes, setExpandedNodes] = useState(new Set()); const [viewMode, setViewMode] = useState("search"); // 'tree' or 'search' - const allTags = field.options || []; - const selectedTags = input.value || []; + const allTags = field.options || NO_TAGS; + const selectedTags = input.value || NO_TAGS; // Build tree structure from tags const tagTree = useMemo(() => { @@ -35,8 +39,6 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { name: part, fullPath: path, children: {}, - isLeaf: index === parts.length - 1, - level: index, }; } @@ -69,6 +71,20 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { return groups; }, [filteredTags]); + // Top-level segments present in the taxonomy, most-used first. Previously a + // hardcoded list carried over from one specific site's tags. + const popularCategories = useMemo(() => { + const counts = new Map(); + for (const tag of allTags) { + const top = tag.split("_")[0]; + if (top) counts.set(top, (counts.get(top) || 0) + 1); + } + return [...counts.entries()] + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])) + .slice(0, 5) + .map(([name]) => name); + }, [allTags]); + // Get all parent paths for a given tag const getParentPaths = (tagPath) => { const parts = tagPath.split("_"); @@ -330,25 +346,28 @@ const TagsField = wrapFieldsWithMeta(({ input, field, tinaForm }) => { Popular Tags
      - {["customers", "teams", "a3-features", "components", "regions"] - .filter((tag) => allTags.some((t) => t.startsWith(tag))) - .map((category) => ( - - ))} + {popularCategories.map((category) => ( + + ))}
    )} {/* Click outside handler for search mode */} {viewMode === "search" && isOpen && ( -
    setIsOpen(false)} /> +
    ); diff --git a/template/src/css/custom.css b/template/src/css/custom.css index 1eca1a6d..16c21f0b 100644 --- a/template/src/css/custom.css +++ b/template/src/css/custom.css @@ -732,9 +732,6 @@ h6, } } -/* Mermaid Zoom Functionality */ -@import "../theme/Mermaid/mermaid-zoom.css"; - /* Ordered list styling */ ol { list-style-type: decimal; /* First level: 1, 2, 3, ... */ @@ -819,7 +816,6 @@ main s, transform: rotate(45deg); } - /* * Merge consecutive lists separated by ConditionalText components. * Also handle cases where empty elements are between lists diff --git a/template/src/pages/404.js b/template/src/pages/404.js index e1690735..90f62369 100644 --- a/template/src/pages/404.js +++ b/template/src/pages/404.js @@ -5,41 +5,48 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useEffect} from 'react'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import Layout from '@theme/Layout'; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import Layout from "@theme/Layout"; +import React, { useEffect } from "react"; export default function NotFound() { - const {i18n} = useDocusaurusContext(); + const { i18n } = useDocusaurusContext(); useEffect(() => { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; const tryFallback = async () => { - const {pathname, search, hash} = window.location; - const parts = pathname.split('/').filter(Boolean); + const { pathname, search, hash } = window.location; + const parts = pathname.split("/").filter(Boolean); if (!parts.length) return; const first = parts[0]; - if (!i18n || !i18n.locales || !i18n.locales.includes(first)) return; + if (!i18n?.locales?.includes(first)) return; if (first === i18n.defaultLocale) return; // Remove locale prefix to build default-locale path parts.shift(); - let fallbackPath = '/' + parts.join('/'); - if (fallbackPath === '/') fallbackPath = '/'; + let fallbackPath = `/${parts.join("/")}`; + if (fallbackPath === "/") fallbackPath = "/"; - const tryUrls = [fallbackPath, `${fallbackPath}.html`, `${fallbackPath}/index.html`]; + const tryUrls = [ + fallbackPath, + `${fallbackPath}.html`, + `${fallbackPath}/index.html`, + ]; for (const url of tryUrls) { try { - const res = await fetch(url, {method: 'GET', credentials: 'same-origin'}); + const res = await fetch(url, { + method: "GET", + credentials: "same-origin", + }); if (res && res.status === 200) { // Redirect to the URL that exists (preserve search + hash) window.location.replace(url + search + hash); return; } - } catch (e) { + } catch (_e) { // ignore network errors } } @@ -50,9 +57,12 @@ export default function NotFound() { return ( -
    +

    404 — Page not found

    -

    The page you requested does not exist in this language. Trying the default language...

    +

    + The page you requested does not exist in this language. Trying the + default language... +

    ); diff --git a/template/src/plugins/blog-date-filter.js b/template/src/plugins/blog-date-filter.js index 18802452..1a2dd8ba 100644 --- a/template/src/plugins/blog-date-filter.js +++ b/template/src/plugins/blog-date-filter.js @@ -1,6 +1,6 @@ -const fs = require('fs'); -const path = require('path'); -const matter = require('gray-matter'); +const fs = require("node:fs"); +const path = require("node:path"); +const matter = require("gray-matter"); /** * Get list of future-dated blog files that should be excluded @@ -9,75 +9,71 @@ const matter = require('gray-matter'); */ function getFutureDatedBlogFiles(blogDir) { const futureDatedFiles = []; - + // Only exclude future-dated files in production builds // Allow them in development for preview purposes - const isProduction = process.env.NODE_ENV === 'production'; - + const isProduction = process.env.NODE_ENV === "production"; + if (!isProduction) { - console.log('šŸš€ Development mode: Including future-dated blog posts for preview'); - return []; // Return empty array in development - include all posts + // Development: include all posts so future-dated drafts stay previewable + return []; } - + try { if (!fs.existsSync(blogDir)) { - console.warn(`Blog directory ${blogDir} does not exist`); return []; } const currentDate = new Date(); - const currentDateString = currentDate.toISOString().split('T')[0]; // YYYY-MM-DD format + const currentDateString = currentDate.toISOString().split("T")[0]; // YYYY-MM-DD format // Read all blog files - const allFiles = fs.readdirSync(blogDir) - .filter(file => file.endsWith('.md') || file.endsWith('.mdx')) - .filter(file => !file.startsWith('.')); + const allFiles = fs + .readdirSync(blogDir) + .filter((file) => file.endsWith(".md") || file.endsWith(".mdx")) + .filter((file) => !file.startsWith(".")); for (const file of allFiles) { try { const fullPath = path.join(blogDir, file); - const fileContent = fs.readFileSync(fullPath, 'utf8'); + const fileContent = fs.readFileSync(fullPath, "utf8"); const { data: frontmatter } = matter(fileContent); - + if (!frontmatter.date) { continue; // Skip files without dates } - + let postDateString; - + // Handle different date formats if (frontmatter.date instanceof Date) { - postDateString = frontmatter.date.toISOString().split('T')[0]; - } else if (typeof frontmatter.date === 'string') { + postDateString = frontmatter.date.toISOString().split("T")[0]; + } else if (typeof frontmatter.date === "string") { // Try to parse the date string const parsedDate = new Date(frontmatter.date); - if (!isNaN(parsedDate.getTime())) { - postDateString = parsedDate.toISOString().split('T')[0]; + if (!Number.isNaN(parsedDate.getTime())) { + postDateString = parsedDate.toISOString().split("T")[0]; } else { // Assume YYYY-MM-DD format if parsing fails - postDateString = frontmatter.date.split('T')[0]; + postDateString = frontmatter.date.split("T")[0]; } } - + // Add to exclude list if post date is in the future if (postDateString && postDateString > currentDateString) { futureDatedFiles.push(file); - console.log(`šŸ“… Excluding future-dated blog post: ${file} (date: ${postDateString})`); } - - } catch (error) { - console.warn(`Error checking blog post date for ${file}:`, error.message); + } catch { // Skip files with parsing errors (don't exclude them) } } - - } catch (error) { - console.warn(`Error reading blog directory ${blogDir}:`, error.message); + } catch { + // Unreadable blog directory: exclude nothing } return futureDatedFiles; } module.exports = { - getFutureDatedBlogFiles -}; \ No newline at end of file + getFutureDatedBlogFiles, +}; diff --git a/template/src/theme/template.jsx b/template/src/theme/template.jsx index b0c45e21..11ba1e5b 100644 --- a/template/src/theme/template.jsx +++ b/template/src/theme/template.jsx @@ -6,8 +6,6 @@ */ import React from "react"; -import codeFiles from "../../reuse/code-files.json"; -import { slugify } from "../../scripts/util"; import { CodeSnippetBlockTemplate } from "../components/CodeSnippet/template"; import { CommentBlockTemplate } from "../components/Comment/template"; import { ConditionalTextBlockTemplate } from "../components/ConditionalText/template"; @@ -145,21 +143,11 @@ const TruncateTemplate = { ], }; -// Get the last segment of the path as the slug -const usePageSlug = () => { - if (typeof window === "undefined") return ""; - const path = window.location.pathname; - const segments = path.split("/").filter(Boolean); - return segments[segments.length - 1] || ""; -}; - -const slug = usePageSlug(); - const ContextHelpTemplate = { name: "a", label: "Context Help", ui: { - itemProps: (item, slug) => { + itemProps: (item) => { return { label: item?.title }; }, }, @@ -178,7 +166,7 @@ const TabsTemplate = { name: "Tabs", label: "Tabs", ui: { - itemProps: (item) => { + itemProps: (_item) => { return { label: "Tabs" }; }, }, diff --git a/template/src/utils/editorIdentity.js b/template/src/utils/editorIdentity.js index fa3b90de..7d269039 100644 --- a/template/src/utils/editorIdentity.js +++ b/template/src/utils/editorIdentity.js @@ -17,7 +17,7 @@ function decodeJwtPayload(token) { const [, payload] = token.split("."); // atob works in browsers; guard against Unicode issues if needed return JSON.parse(atob(payload)); - } catch (e) { + } catch (_e) { return null; } } @@ -76,7 +76,11 @@ export async function getEditorIdentity() { if (gitLocal) return gitLocal; // 3) Env-provided local user - if (typeof process !== "undefined" && process.env && process.env.NEXT_PUBLIC_LOCAL_USER) { + if ( + typeof process !== "undefined" && + process.env && + process.env.NEXT_PUBLIC_LOCAL_USER + ) { return process.env.NEXT_PUBLIC_LOCAL_USER; } diff --git a/template/src/utils/themeUtils.js b/template/src/utils/themeUtils.js index 03a72bd5..2746eab6 100644 --- a/template/src/utils/themeUtils.js +++ b/template/src/utils/themeUtils.js @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require("fs"); -const path = require("path"); +const fs = require("node:fs"); +const path = require("node:path"); /** * Generate CSS variables from theme configuration @@ -119,10 +119,12 @@ function updateThemeCSS() { // Write CSS file fs.writeFileSync(cssPath, css); - - console.log("Theme CSS updated successfully!"); } catch (error) { - console.error("Error updating theme CSS:", error); + // Let the caller (scripts/update-theme-css.js) report and set the exit + // code — swallowing this here made the script print success on failure. + throw new Error(`Failed to update theme CSS: ${error.message}`, { + cause: error, + }); } } diff --git a/template/src/utils/xliff.js b/template/src/utils/xliff.js index 0c414a09..52176f56 100644 --- a/template/src/utils/xliff.js +++ b/template/src/utils/xliff.js @@ -9,59 +9,44 @@ // Exports title and body as JSON string in so MDX/React content is preserved. function escapeXml(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; + if (unsafe === null || unsafe === undefined) return ""; return String(unsafe) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - -function escapeXmlWithLineBreaks(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; - // Normalize newlines - let s = String(unsafe); - // Match all common newline sequences (CRLF, CR, LF) and normalize to a - // placeholder so we can safely escape XML and then restore XLIFF tags. - const LB = '___XLIFF_LB___'; - s = s.replace(/\r\n|\r|\n/g, LB); - s = s - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - // restore real XLIFF line-break tags - return s.replace(new RegExp(LB, 'g'), ''); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } // Escape XML but preserve real newline characters so XLIFF consumers // (and CAT tools like Swordfish) can round-trip actual line breaks. function escapeXmlPreserveNewlines(unsafe) { - if (unsafe === null || unsafe === undefined) return ''; + if (unsafe === null || unsafe === undefined) return ""; return String(unsafe) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/\"/g, '"') - .replace(/'/g, '''); + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); } // Remove control characters that may be embedded in AST serializations // (keep tab, LF, CR). This prevents NULs and other controls from // corrupting XLIFF consumers or terminal output. function stripControlChars(s) { - if (s === null || s === undefined) return ''; + if (s === null || s === undefined) return ""; try { // Remove BOM and all Unicode C0/C1 control characters (U+0000..U+001F, U+007F..U+009F) // but keep tab (\x09), LF (\x0A), and CR (\x0D) so line breaks are preserved. // This avoids leaving high-bit control bytes that show up as M-^@ sequences // in some terminals or when processed by CAT tools. - return String(s) - .replace(/\uFEFF/g, '') - .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, ''); - } catch (e) { + return ( + String(s) + .replace(/\uFEFF/g, "") + // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping control characters is the entire point of this function + .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "") + ); + } catch { return String(s); } } @@ -70,12 +55,14 @@ function stripControlChars(s) { // blocks (``` or ~~~). This prevents link conversion, JSX marker conversion, // and other transformations from modifying code examples. function outsideCodeFences(fn) { - return function (s) { - if (!s || typeof s !== 'string') return fn(s); + return (s) => { + if (!s || typeof s !== "string") return fn(s); // Split on fenced code blocks (``` or ~~~). The regex captures the // complete fenced block (including opening/closing fences) so that // odd-numbered parts are code blocks and even-numbered parts are prose. - const parts = s.split(/(^`{3,}[^\n]*\n[\s\S]*?^`{3,}\s*$|^~{3,}[^\n]*\n[\s\S]*?^~{3,}\s*$)/m); + const parts = s.split( + /(^`{3,}[^\n]*\n[\s\S]*?^`{3,}\s*$|^~{3,}[^\n]*\n[\s\S]*?^~{3,}\s*$)/m + ); for (let i = 0; i < parts.length; i++) { if (i % 2 === 0) { // Outside code fence – apply the transformation @@ -83,128 +70,74 @@ function outsideCodeFences(fn) { } // Odd indices are fenced code blocks – leave them untouched } - return parts.join(''); + return parts.join(""); }; } -// Annotate JSX component occurrences inside raw MDX/markdown strings so that -// stringy prop values and simple children are included in the exported -// source text (translators need to see prop text even when it's inside an -// attribute). This works on plain strings and is intentionally conservative — -// it only tries to extract simple quoted/templated prop values. -function annotateJsxPropsAndChildren(text) { - if (!text || typeof text !== 'string') return text; - - // regex to capture simple prop string forms: "..." or '...' or `{`...`}` or {"..."} - const propStringRe = /([a-zA-Z0-9_:-]+)=?(?:"([^"]*)"|'([^']*)'|\{`([^`]*)`\}|\{\s*"([^"]*)"\s*\}|\{\s*'([^']*)'\s*\})/g; - - // 1) handle self-closing tags: -> append annotation after tag - text = text.replace(/<([A-Z][\w]*)\b([^>]*)\/>/g, (m, name, propsPart) => { - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m} (${vals.join(', ')})`; - return m; - }); - - // 2) handle open tags with attributes: -> inject annotation immediately after the opening tag - text = text.replace(/<([A-Z][\w]*)\b([^>]*)>/g, (m, name, propsPart) => { - // skip closing tags which also match pattern (they start with { - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m} (${vals.join(', ')})`; - return m; - }); - // open marker: (jsx:Name prop="x") -> append annotation after marker - text = text.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)/g, (m, name, propsPart) => { - // skip closing markers which look like (/jsx:Name) - if (/^\(\/jsx:/.test(m)) return m; - const vals = []; - let p; - while ((p = propStringRe.exec(propsPart)) !== null) { - const v = p[2] || p[3] || p[4] || p[5] || p[6] || ''; - if (v) vals.push(`${p[1]}:${v}`); - } - if (vals.length) return `${m}${vals.length ? ' (' + vals.join(', ') + ')' : ''}`; - return m; - }); - return text; -} - // Convert angle-bracket JSX/MDX to a robust marker form that begins with // `(jsx:` so CAT tools like Swordfish won't treat tags as HTML and drop the // component name. Examples: //
    -> (jsx:Figure img="x" caption="y"/) // child -> (jsx:Comp prop="v")child(/jsx:Comp) function angleToMarker(source) { - if (!source || typeof source !== 'string') return source; + if (!source || typeof source !== "string") return source; // Robust pass: convert tags that include a children={...} prop where the // prop value may contain nested braces or newlines. Regex alone can fail // on nested braces, so scan for balanced braces and replace each occurrence. source = (function scanChildrenProps(s) { - let out = ''; + let out = ""; let idx = 0; while (true) { const m = s.slice(idx).match(/<([A-Z][\w-]*)\b[^>]*?\bchildren=\{/); - if (!m) { out += s.slice(idx); break; } + if (!m) { + out += s.slice(idx); + break; + } const matchIndex = idx + m.index; out += s.slice(idx, matchIndex); const tagStart = matchIndex; // find position of '{' that starts the children value - const bracePos = s.indexOf('{', tagStart + m[0].length - 1); - if (bracePos === -1) { out += s.slice(matchIndex); break; } + const bracePos = s.indexOf("{", tagStart + m[0].length - 1); + if (bracePos === -1) { + out += s.slice(matchIndex); + break; + } // scan for matching closing '}' with nesting let depth = 0; let j = bracePos; for (; j < s.length; j++) { const ch = s[j]; - if (ch === '{') depth++; - else if (ch === '}') { + if (ch === "{") depth++; + else if (ch === "}") { depth--; - if (depth === 0) { j++; break; } + if (depth === 0) { + j++; + break; + } } } - if (depth !== 0) { out += s.slice(matchIndex); break; } + if (depth !== 0) { + out += s.slice(matchIndex); + break; + } const children = s.slice(bracePos + 1, j - 1 + 1); // content inside braces // now find end of tag '>' after the children prop - const tagEnd = s.indexOf('>', j); - if (tagEnd === -1) { out += s.slice(matchIndex); break; } + const tagEnd = s.indexOf(">", j); + if (tagEnd === -1) { + out += s.slice(matchIndex); + break; + } const fullTag = s.slice(tagStart, tagEnd + 1); // remove the children={...} piece from fullTag - const withoutChildren = fullTag.replace(/\bchildren=\{[\s\S]*?\}/, '').replace(/\s+/g, ' ').trim(); - // determine if it was self-closing - const selfClosing = /\/>\s*$/.test(fullTag); - const propsStr = withoutChildren.replace(/^<[^\s]+/, '').replace(/^[\s>]+|[\s>]+$/g, '').trim(); - const p = propsStr ? ' ' + propsStr : ''; + const withoutChildren = fullTag + .replace(/\bchildren=\{[\s\S]*?\}/, "") + .replace(/\s+/g, " ") + .trim(); + const propsStr = withoutChildren + .replace(/^<[^\s]+/, "") + .replace(/^[\s>]+|[\s>]+$/g, "") + .trim(); + const p = propsStr ? ` ${propsStr}` : ""; out += `(jsx:${m[1]}${p})${children}(/jsx:${m[1]})`; idx = tagEnd + 1; } @@ -212,21 +145,27 @@ function angleToMarker(source) { })(source); // self-closing source = source.replace(/<([A-Z][\w-]*)\b([^>]*)\/>/g, (_m, name, props) => { - const p = props.trim().replace(/\s+/g, ' '); - return `(jsx:${name}${p ? ' ' + p : ''}/)`; + const p = props.trim().replace(/\s+/g, " "); + return `(jsx:${name}${p ? ` ${p}` : ""}/)`; }); // tags that pass content via a children={...} prop (no inner text) - source = source.replace(/<([A-Z][\w-]*)\b([^>]*)\bchildren=\{([\s\S]*?)\}([^>]*)\/?>/g, (_m, name, before, child, after) => { - // merge remaining props (before + after) and trim - const props = (before + ' ' + after).trim().replace(/\s+/g, ' '); - const p = props ? ' ' + props : ''; - return `(jsx:${name}${p})${child}(/jsx:${name})`; - }); + source = source.replace( + /<([A-Z][\w-]*)\b([^>]*)\bchildren=\{([\s\S]*?)\}([^>]*)\/?>/g, + (_m, name, before, child, after) => { + // merge remaining props (before + after) and trim + const props = `${before} ${after}`.trim().replace(/\s+/g, " "); + const p = props ? ` ${props}` : ""; + return `(jsx:${name}${p})${child}(/jsx:${name})`; + } + ); // paired tags (non-greedy children) - source = source.replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, (_m, name, props, children) => { - const p = props.trim().replace(/\s+/g, ' '); - return `(jsx:${name}${p ? ' ' + p : ''})${children}(/jsx:${name})`; - }); + source = source.replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + (_m, name, props, children) => { + const p = props.trim().replace(/\s+/g, " "); + return `(jsx:${name}${p ? ` ${p}` : ""})${children}(/jsx:${name})`; + } + ); return source; } @@ -239,13 +178,16 @@ function angleToMarker(source) { // backslash-escape, destroying all formatting). // --------------------------------------------------------------------------- function parseMarkdownToTinaAst(md) { - if (!md || typeof md !== 'string') { - return { type: 'root', children: [{ type: 'p', children: [{ type: 'text', text: '' }] }] }; + if (!md || typeof md !== "string") { + return { + type: "root", + children: [{ type: "p", children: [{ type: "text", text: "" }] }], + }; } // ---- inline parser ---- function parseInline(text) { - if (!text) return [{ type: 'text', text: '' }]; + if (!text) return [{ type: "text", text: "" }]; const nodes = []; let remaining = text; @@ -255,18 +197,20 @@ function parseMarkdownToTinaAst(md) { let earliestIdx = remaining.length; // Inline JSX marker (paired): (jsx:Name props)content(/jsx:Name) - const jsxInlinePairedRe = /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/; + const jsxInlinePairedRe = + /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/; const jsxInlinePairedM = jsxInlinePairedRe.exec(remaining); if (jsxInlinePairedM && jsxInlinePairedM.index < earliestIdx) { - earliest = { type: 'jsxPaired', match: jsxInlinePairedM }; + earliest = { type: "jsxPaired", match: jsxInlinePairedM }; earliestIdx = jsxInlinePairedM.index; } // Inline JSX marker (self-closing): (jsx:Name props/) - const jsxInlineSelfRe = /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/; + const jsxInlineSelfRe = + /\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/; const jsxInlineSelfM = jsxInlineSelfRe.exec(remaining); if (jsxInlineSelfM && jsxInlineSelfM.index < earliestIdx) { - earliest = { type: 'jsxSelf', match: jsxInlineSelfM }; + earliest = { type: "jsxSelf", match: jsxInlineSelfM }; earliestIdx = jsxInlineSelfM.index; } @@ -274,7 +218,7 @@ function parseMarkdownToTinaAst(md) { const linkRe = /\[([^\]]*)\]\(([^)]*)\)/; const linkM = linkRe.exec(remaining); if (linkM && linkM.index < earliestIdx) { - earliest = { type: 'link', match: linkM }; + earliest = { type: "link", match: linkM }; earliestIdx = linkM.index; } @@ -282,7 +226,7 @@ function parseMarkdownToTinaAst(md) { const codeRe = /`([^`]+)`/; const codeM = codeRe.exec(remaining); if (codeM && codeM.index < earliestIdx) { - earliest = { type: 'code', match: codeM }; + earliest = { type: "code", match: codeM }; earliestIdx = codeM.index; } @@ -290,15 +234,16 @@ function parseMarkdownToTinaAst(md) { const boldRe = /\*\*([^*]+)\*\*|__([^_]+)__/; const boldM = boldRe.exec(remaining); if (boldM && boldM.index < earliestIdx) { - earliest = { type: 'bold', match: boldM }; + earliest = { type: "bold", match: boldM }; earliestIdx = boldM.index; } // Italic: *text* or _text_ (but not ** or __) - const italicRe = /(? 0) { - nodes.push({ type: 'text', text: remaining.slice(0, earliestIdx) }); + nodes.push({ type: "text", text: remaining.slice(0, earliestIdx) }); } const m = earliest.match; switch (earliest.type) { - case 'jsxPaired': - case 'jsxSelf': { + case "jsxPaired": + case "jsxSelf": { const compName = m[1]; - let rawProps = (m[2] || '').trim(); - const innerText = earliest.type === 'jsxPaired' ? (m[3] || '') : ''; + let rawProps = (m[2] || "").trim(); + const innerText = earliest.type === "jsxPaired" ? m[3] || "" : ""; // Unescape HTML entities in prop values that CAT tools may have introduced - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); // Parse simple props: key="value" or key='value' or key={value} // Also handle bare boolean props (e.g. `initcap` without =value) const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop - if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { + if ( + pm[2] === undefined && + pm[3] === undefined && + pm[4] === undefined + ) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) // that were introduced by JSON.stringify during export. - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -371,46 +336,59 @@ function parseMarkdownToTinaAst(md) { } nodes.push({ - type: 'mdxJsxTextElement', + type: "mdxJsxTextElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); break; } - case 'link': { - const linkText = m[1] || ''; - const href = m[2] || ''; - const linkChildren = linkText ? [{ type: 'text', text: linkText }] : []; - nodes.push({ type: 'a', url: href, title: null, children: linkChildren }); + case "link": { + const linkText = m[1] || ""; + const href = m[2] || ""; + const linkChildren = linkText + ? [{ type: "text", text: linkText }] + : []; + nodes.push({ + type: "a", + url: href, + title: null, + children: linkChildren, + }); break; } - case 'code': - nodes.push({ type: 'text', text: m[1], code: true }); + case "code": + nodes.push({ type: "text", text: m[1], code: true }); break; - case 'bold': - nodes.push({ type: 'text', text: m[1] || m[2], bold: true }); + case "bold": + nodes.push({ type: "text", text: m[1] || m[2], bold: true }); break; - case 'italic': - nodes.push({ type: 'text', text: m[1] || m[2], italic: true }); + case "italic": + nodes.push({ type: "text", text: m[1] || m[2], italic: true }); break; - case 'strikethrough': - nodes.push({ type: 'text', text: m[1], strikethrough: true }); + case "strikethrough": + nodes.push({ type: "text", text: m[1], strikethrough: true }); break; - case 'image': { - const imgAlt = m[1] || ''; - const imgSrc = m[2] || ''; - nodes.push({ type: 'img', url: imgSrc, caption: imgAlt || null, alt: imgAlt || '', children: [{ type: 'text', text: '' }] }); + case "image": { + const imgAlt = m[1] || ""; + const imgSrc = m[2] || ""; + nodes.push({ + type: "img", + url: imgSrc, + caption: imgAlt || null, + alt: imgAlt || "", + children: [{ type: "text", text: "" }], + }); break; } } remaining = remaining.slice(earliestIdx + m[0].length); } - return nodes.length ? nodes : [{ type: 'text', text: '' }]; + return nodes.length ? nodes : [{ type: "text", text: "" }]; } // ---- block parser ---- - const lines = md.replace(/\r\n?/g, '\n').split('\n'); + const lines = md.replace(/\r\n?/g, "\n").split("\n"); const rootChildren = []; let i = 0; @@ -420,7 +398,7 @@ function parseMarkdownToTinaAst(md) { function consumeList(startIdx, ordered, sourceLines) { const src = sourceLines || lines; const items = []; - const marker = ordered ? /^(\d+)\.\s+(.*)$/ : /^[\*\-\+]\s+(.*)$/; + const marker = ordered ? /^(\d+)\.\s+(.*)$/ : /^[*\-+]\s+(.*)$/; let idx = startIdx; while (idx < src.length) { const line = src[idx]; @@ -428,20 +406,22 @@ function parseMarkdownToTinaAst(md) { if (!m) break; const content = ordered ? m[2] : m[1]; const currentItem = { - type: 'li', - children: [{ type: 'lic', children: parseInline(content) }] + type: "li", + children: [{ type: "lic", children: parseInline(content) }], }; items.push(currentItem); idx++; // Absorb continuation lines (indented or non-blank, non-block-start) while (idx < src.length) { const next = src[idx]; - if (next === '') break; + if (next === "") break; if (marker.test(next)) break; // next list item at same level // Detect indented nested list (2+ spaces followed by a list marker) const nestedOlMatch = next.match(/^\s{2,}(\d+)\.\s+(.*)$/); - const nestedUlMatch = !nestedOlMatch ? next.match(/^\s{2,}[\*\-\+]\s+(.*)$/) : null; + const nestedUlMatch = !nestedOlMatch + ? next.match(/^\s{2,}[*\-+]\s+(.*)$/) + : null; if (nestedOlMatch || nestedUlMatch) { // Gather all indented lines for the nested list, then strip // their leading whitespace and parse recursively. @@ -449,7 +429,7 @@ function parseMarkdownToTinaAst(md) { const baseIndent = next.match(/^(\s+)/)[1].length; while (idx < src.length) { const nl = src[idx]; - if (nl === '') break; + if (nl === "") break; const indentMatch = nl.match(/^(\s+)/); if (!indentMatch || indentMatch[1].length < baseIndent) break; nestedLines.push(nl.slice(baseIndent)); @@ -468,26 +448,29 @@ function parseMarkdownToTinaAst(md) { // Continuation of previous item – append to last lic's text const lastLic = currentItem.children[0]; const lastChild = lastLic.children[lastLic.children.length - 1]; - if (lastChild && lastChild.type === 'text') { - lastChild.text += '\n' + next.replace(/^\s+/, ''); + if (lastChild && lastChild.type === "text") { + lastChild.text += `\n${next.replace(/^\s+/, "")}`; } idx++; } } - return [{ type: ordered ? 'ol' : 'ul', children: items }, idx]; + return [{ type: ordered ? "ol" : "ul", children: items }, idx]; } while (i < lines.length) { const line = lines[i]; // Blank line – skip - if (line.trim() === '') { i++; continue; } + if (line.trim() === "") { + i++; + continue; + } // Fenced code block: ``` or ~~~ const fenceMatch = line.match(/^(`{3,}|~{3,})\s*(\S*)\s*$/); if (fenceMatch) { const fence = fenceMatch[1]; - const lang = fenceMatch[2] || ''; + const lang = fenceMatch[2] || ""; const codeLines = []; i++; while (i < lines.length && !lines[i].startsWith(fence)) { @@ -495,15 +478,15 @@ function parseMarkdownToTinaAst(md) { i++; } if (i < lines.length) i++; // skip closing fence - const value = codeLines.join('\n'); + const value = codeLines.join("\n"); rootChildren.push({ - type: 'code_block', + type: "code_block", lang: lang || undefined, value, - children: codeLines.map(cl => ({ - type: 'code_line', - children: [{ text: cl }] - })) + children: codeLines.map((cl) => ({ + type: "code_line", + children: [{ text: cl }], + })), }); continue; } @@ -513,8 +496,8 @@ function parseMarkdownToTinaAst(md) { if (headingMatch) { const depth = headingMatch[1].length; rootChildren.push({ - type: 'h' + depth, - children: parseInline(headingMatch[2]) + type: `h${depth}`, + children: parseInline(headingMatch[2]), }); i++; continue; @@ -522,13 +505,13 @@ function parseMarkdownToTinaAst(md) { // Horizontal rule: ---, ***, ___ if (/^(---|\*\*\*|___)\s*$/.test(line)) { - rootChildren.push({ type: 'hr', children: [{ type: 'text', text: '' }] }); + rootChildren.push({ type: "hr", children: [{ type: "text", text: "" }] }); i++; continue; } // Unordered list item: * , - , + - if (/^[\*\-\+]\s+/.test(line)) { + if (/^[*\-+]\s+/.test(line)) { const [listNode, nextIdx] = consumeList(i, false); rootChildren.push(listNode); i = nextIdx; @@ -547,24 +530,24 @@ function parseMarkdownToTinaAst(md) { if (/^>\s?/.test(line)) { const bqLines = []; while (i < lines.length && /^>\s?/.test(lines[i])) { - bqLines.push(lines[i].replace(/^>\s?/, '')); + bqLines.push(lines[i].replace(/^>\s?/, "")); i++; } // Recursively parse blockquote content - const inner = parseMarkdownToTinaAst(bqLines.join('\n')); + const inner = parseMarkdownToTinaAst(bqLines.join("\n")); // Tina expects blockquote children to be inline (text, a, etc.), // not block-level (p). Unwrap any p nodes produced by the recursive parse. const bqChildren = []; - for (const child of (inner.children || [])) { - if (child.type === 'p' && child.children) { + for (const child of inner.children || []) { + if (child.type === "p" && child.children) { bqChildren.push(...child.children); } else { bqChildren.push(child); } } rootChildren.push({ - type: 'blockquote', - children: bqChildren.length ? bqChildren : [{ type: 'text', text: '' }] + type: "blockquote", + children: bqChildren.length ? bqChildren : [{ type: "text", text: "" }], }); continue; } @@ -573,45 +556,64 @@ function parseMarkdownToTinaAst(md) { // or self-closing: (jsx:Name props/) // Detect on the current line and produce a proper mdxJsxFlowElement node. // Supports both single-line and multi-line paired elements. - const jsxPairedRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)$/; - const jsxSelfRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)$/; + const jsxPairedRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)$/; + const jsxSelfRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)$/; const jsxPairedM = jsxPairedRe.exec(line); const jsxSelfM = !jsxPairedM ? jsxSelfRe.exec(line) : null; // Also detect multi-line paired JSX: opening tag on this line, closing // on a subsequent line. (jsx:Name props) ... lines ... (/jsx:Name) - const jsxOpenRe = /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)(.*)$/; - const jsxOpenM = (!jsxPairedM && !jsxSelfM) ? jsxOpenRe.exec(line) : null; + const jsxOpenRe = + /^\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)(.*)$/; + const jsxOpenM = !jsxPairedM && !jsxSelfM ? jsxOpenRe.exec(line) : null; if (jsxPairedM || jsxSelfM) { // Single-line paired or self-closing const m = jsxPairedM || jsxSelfM; const compName = m[1]; - let rawProps = (m[2] || '').trim(); - const innerText = jsxPairedM ? (m[3] || '') : ''; + let rawProps = (m[2] || "").trim(); + const innerText = jsxPairedM ? m[3] || "" : ""; - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); // Parse simple props: key="value" or key={value} or bare boolean const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; // Try to parse JSON-like values (arrays, bools, numbers) - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -622,10 +624,10 @@ function parseMarkdownToTinaAst(md) { } rootChildren.push({ - type: 'mdxJsxFlowElement', + type: "mdxJsxFlowElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); i++; continue; @@ -635,8 +637,8 @@ function parseMarkdownToTinaAst(md) { // Multi-line paired JSX: opening tag on this line, gather content // until we find the matching closing tag (/jsx:Name). const compName = jsxOpenM[1]; - let rawProps = (jsxOpenM[2] || '').trim(); - const firstLineContent = jsxOpenM[3] || ''; + let rawProps = (jsxOpenM[2] || "").trim(); + const firstLineContent = jsxOpenM[3] || ""; const closingTag = `(/jsx:${compName})`; const contentLines = []; if (firstLineContent) contentLines.push(firstLineContent); @@ -654,28 +656,44 @@ function parseMarkdownToTinaAst(md) { contentLines.push(cur); i++; } - const innerText = contentLines.join('\n'); + const innerText = contentLines.join("\n"); - rawProps = rawProps.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + rawProps = rawProps + .replace(/"/g, '"') + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">"); const props = {}; - const propRe = /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; - let pm; - while ((pm = propRe.exec(rawProps)) !== null) { + const propRe = + /([a-zA-Z][\w-]*)(?:=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/g; + for (const pm of rawProps.matchAll(propRe)) { const key = pm[1]; // If no =value was matched, this is a bare boolean prop if (pm[2] === undefined && pm[3] === undefined && pm[4] === undefined) { props[key] = true; continue; } - let val = pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; - if (val !== undefined && /^[\[{]/.test(val)) { - try { val = JSON.parse(val); } catch (e) { /* keep string */ } - } else if (val === 'true') { val = true; } - else if (val === 'false') { val = false; } + let val = + pm[2] !== undefined ? pm[2] : pm[3] !== undefined ? pm[3] : pm[4]; + if (val !== undefined && /^[[{]/.test(val)) { + try { + val = JSON.parse(val); + } catch { + /* keep string */ + } + } else if (val === "true") { + val = true; + } else if (val === "false") { + val = false; + } // Unescape JSON string escapes (\n → newline, \t → tab, etc.) - if (typeof val === 'string' && val.includes('\\')) { - try { val = JSON.parse('"' + val.replace(/"/g, '\\"') + '"'); } catch (e) { /* keep as-is */ } + if (typeof val === "string" && val.includes("\\")) { + try { + val = JSON.parse(`"${val.replace(/"/g, '\\"')}"`); + } catch { + /* keep as-is */ + } } props[key] = val; } @@ -685,10 +703,10 @@ function parseMarkdownToTinaAst(md) { } rootChildren.push({ - type: 'mdxJsxFlowElement', + type: "mdxJsxFlowElement", name: compName, - children: [{ type: 'text', text: '' }], - props + children: [{ type: "text", text: "" }], + props, }); continue; } @@ -697,11 +715,11 @@ function parseMarkdownToTinaAst(md) { const paraLines = []; while (i < lines.length) { const cur = lines[i]; - if (cur.trim() === '') break; + if (cur.trim() === "") break; if (/^#{1,6}\s/.test(cur)) break; if (/^(`{3,}|~{3,})/.test(cur)) break; if (/^(---|\*\*\*|___)\s*$/.test(cur)) break; - if (/^[\*\-\+]\s+/.test(cur)) break; + if (/^[*\-+]\s+/.test(cur)) break; if (/^\d+\.\s+/.test(cur)) break; if (/^>\s/.test(cur)) break; if (/^\(jsx:[A-Z]/.test(cur)) break; @@ -712,321 +730,389 @@ function parseMarkdownToTinaAst(md) { // pattern) advance past the current line to prevent an infinite loop. if (paraLines.length === 0) { rootChildren.push({ - type: 'p', - children: parseInline(lines[i] || '') + type: "p", + children: parseInline(lines[i] || ""), }); i++; } else { rootChildren.push({ - type: 'p', - children: parseInline(paraLines.join('\n')) + type: "p", + children: parseInline(paraLines.join("\n")), }); } } return { - type: 'root', + type: "root", children: rootChildren.length ? rootChildren - : [{ type: 'p', children: [{ type: 'text', text: '' }] }] + : [{ type: "p", children: [{ type: "text", text: "" }] }], }; } -// Convert marker form back to angle-bracket JSX/MDX -function markerToAngle(source) { - if (!source || typeof source !== 'string') return source; - // paired tags first - source = source.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, (_m, name, props, children) => { - const p = props.trim(); - return `<${name}${p ? ' ' + p : ''}>${children}`; - }); - // self-closing marker - source = source.replace(/\(jsx:([A-Z][\w-]*)\b((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, (_m, name, props) => { - const p = props.trim(); - return `<${name}${p ? ' ' + p : ''} />`; - }); - return source; -} - // Read an XML element while treating XLIFF elements as newline characters. function readElementTextPreservingLineBreaks(el) { - if (!el) return ''; - let s = ''; + if (!el) return ""; + let s = ""; const nodes = Array.from(el.childNodes || []); for (const node of nodes) { if (node.nodeType === 3) { - s += node.nodeValue || ''; + s += node.nodeValue || ""; } else if (node.nodeType === 1) { - const tag = (node.tagName || '').toLowerCase(); - if (tag === 'lb') s += '\n'; - else s += node.textContent || ''; + const tag = (node.tagName || "").toLowerCase(); + if (tag === "lb") s += "\n"; + else s += node.textContent || ""; } } return s; } function extractFrontmatter(text) { - if (!text) return { metadata: {}, body: text || '' }; + if (!text) return { metadata: {}, body: text || "" }; const m = String(text).match(/^---\s*\n([\s\S]*?)\n---\s*\n?/); if (!m) return { metadata: {}, body: text }; const fmRaw = m[1]; const body = text.slice(m[0].length); const metadata = {}; - fmRaw.split(/\n/).forEach((line) => { - const kv = line.match(/^([A-Za-z0-9_\-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/); + for (const line of fmRaw.split(/\n/)) { + const kv = line.match( + /^([A-Za-z0-9_-]+):\s*(?:"([^"]+)"|'([^']+)'|(.+))?$/ + ); if (kv) { - metadata[kv[1]] = (kv[2] || kv[3] || (kv[4] || '')).trim(); + metadata[kv[1]] = (kv[2] || kv[3] || kv[4] || "").trim(); } - }); + } return { metadata, body }; } function serializeRichTextToMarkdown(node) { - if (!node) return ''; - if (typeof node === 'string') return node; - if (Array.isArray(node)) return node.map(serializeRichTextToMarkdown).join(''); + if (!node) return ""; + if (typeof node === "string") return node; + if (Array.isArray(node)) + return node.map(serializeRichTextToMarkdown).join(""); // Tina AST sometimes uses typeless leaf objects like { text: "..." } // (e.g. inside code_line children). Handle them before the switch. if (!node.type && (node.text != null || node.value != null)) { - return String(node.text ?? node.value ?? ''); + return String(node.text ?? node.value ?? ""); } const type = node.type; switch (type) { - case 'root': - return (node.children || []).map(serializeRichTextToMarkdown).join('\n\n'); - case 'p': - return (node.children || []).map(serializeRichTextToMarkdown).join(''); - case 'h1': - case 'h2': - case 'h3': - case 'h4': - case 'h5': - case 'h6': { + case "root": + return (node.children || []) + .map(serializeRichTextToMarkdown) + .join("\n\n"); + case "p": + return (node.children || []).map(serializeRichTextToMarkdown).join(""); + case "h1": + case "h2": + case "h3": + case "h4": + case "h5": + case "h6": { const depth = parseInt(type.slice(1), 10) || 1; - const prefix = '#'.repeat(Math.max(1, Math.min(6, depth))); - const content = (node.children || []).map(serializeRichTextToMarkdown).join(''); + const prefix = "#".repeat(Math.max(1, Math.min(6, depth))); + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join(""); return `${prefix} ${content}`; } - case 'heading': { + case "heading": { const depth = node.depth || 1; - const prefix = '#'.repeat(Math.max(1, Math.min(6, depth))); - const content = (node.children || []).map(serializeRichTextToMarkdown).join(''); + const prefix = "#".repeat(Math.max(1, Math.min(6, depth))); + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join(""); return `${prefix} ${content}`; } - case 'code': - case 'code_block': { - const lang = node.lang || ''; + case "code": + case "code_block": { + const lang = node.lang || ""; // Prefer the flat `value` string when available; otherwise join // code_line children with newlines to reconstruct the block content. - const content = node.value - || (node.children || []).map(c => serializeRichTextToMarkdown(c)).join('\n'); - return '\n\n```' + (lang ? ' ' + lang : '') + '\n' + content + '\n```\n\n'; + const content = + node.value || + (node.children || []) + .map((c) => serializeRichTextToMarkdown(c)) + .join("\n"); + return `\n\n\`\`\`${lang ? ` ${lang}` : ""}\n${content}\n\`\`\`\n\n`; } - case 'code_line': { + case "code_line": { // Individual line inside a code_block – return its raw text content. - return (node.children || []).map(serializeRichTextToMarkdown).join(''); + return (node.children || []).map(serializeRichTextToMarkdown).join(""); } - case 'hr': - return '\n\n---\n\n'; - case 'break': + case "hr": + return "\n\n---\n\n"; + case "break": // represent an explicit hard line-break within a paragraph - return '\n'; - case 'blockquote': { - const content = (node.children || []).map(serializeRichTextToMarkdown).join('\n'); - return content.split('\n').map(line => `> ${line}`).join('\n'); + return "\n"; + case "blockquote": { + const content = (node.children || []) + .map(serializeRichTextToMarkdown) + .join("\n"); + return content + .split("\n") + .map((line) => `> ${line}`) + .join("\n"); } - case 'text': { - let txt = node.text || node.value || ''; + case "text": { + let txt = node.text || node.value || ""; if (node.code) txt = `\`${txt}\``; if (node.bold) txt = `**${txt}**`; if (node.italic) txt = `_${txt}_`; if (node.strikethrough) txt = `~~${txt}~~`; return txt; } - case 'inlineCode': - return `\`${(node.value || node.text || node.literal || '')}\``; - case 'ol': { - const indent = node._indent || ''; - return (node.children || []).map((li, idx) => { - // Separate lic (inline content) from nested list children - const licParts = []; - const nestedLists = []; - for (const child of (li.children || [])) { - if (child.type === 'ol' || child.type === 'ul') { - nestedLists.push(child); - } else { - licParts.push(child); + case "inlineCode": + return `\`${node.value || node.text || node.literal || ""}\``; + case "ol": { + const indent = node._indent || ""; + return (node.children || []) + .map((li, idx) => { + // Separate lic (inline content) from nested list children + const licParts = []; + const nestedLists = []; + for (const child of li.children || []) { + if (child.type === "ol" || child.type === "ul") { + nestedLists.push(child); + } else { + licParts.push(child); + } } - } - const content = licParts.map(serializeRichTextToMarkdown).join(''); - let result = `${indent}${idx + 1}. ${content}`; - // Render nested lists indented under the parent item - for (const nested of nestedLists) { - // 3-char indent to align under ordered list content ("1. ") - const nestedCopy = Object.assign({}, nested, { _indent: indent + ' ' }); - result += '\n' + serializeRichTextToMarkdown(nestedCopy); - } - return result; - }).join('\n'); + const content = licParts.map(serializeRichTextToMarkdown).join(""); + let result = `${indent}${idx + 1}. ${content}`; + // Render nested lists indented under the parent item + for (const nested of nestedLists) { + // 3-char indent to align under ordered list content ("1. ") + const nestedCopy = Object.assign({}, nested, { + _indent: `${indent} `, + }); + result += `\n${serializeRichTextToMarkdown(nestedCopy)}`; + } + return result; + }) + .join("\n"); } - case 'ul': { - const indent = node._indent || ''; - return (node.children || []).map((li) => { - const licParts = []; - const nestedLists = []; - for (const child of (li.children || [])) { - if (child.type === 'ol' || child.type === 'ul') { - nestedLists.push(child); - } else { - licParts.push(child); + case "ul": { + const indent = node._indent || ""; + return (node.children || []) + .map((li) => { + const licParts = []; + const nestedLists = []; + for (const child of li.children || []) { + if (child.type === "ol" || child.type === "ul") { + nestedLists.push(child); + } else { + licParts.push(child); + } } - } - const content = licParts.map(serializeRichTextToMarkdown).join(''); - let result = `${indent}- ${content}`; - for (const nested of nestedLists) { - const nestedCopy = Object.assign({}, nested, { _indent: indent + ' ' }); - result += '\n' + serializeRichTextToMarkdown(nestedCopy); - } - return result; - }).join('\n'); + const content = licParts.map(serializeRichTextToMarkdown).join(""); + let result = `${indent}- ${content}`; + for (const nested of nestedLists) { + const nestedCopy = Object.assign({}, nested, { + _indent: `${indent} `, + }); + result += `\n${serializeRichTextToMarkdown(nestedCopy)}`; + } + return result; + }) + .join("\n"); } - case 'li': - case 'lic': - return (node.children || []).map(serializeRichTextToMarkdown).join(''); - case 'link': - case 'a': { - const text = (node.children || []).map(serializeRichTextToMarkdown).join('') || node.title || ''; - const href = node.url || node.href || ''; + case "li": + case "lic": + return (node.children || []).map(serializeRichTextToMarkdown).join(""); + case "link": + case "a": { + const text = + (node.children || []).map(serializeRichTextToMarkdown).join("") || + node.title || + ""; + const href = node.url || node.href || ""; return href ? `[${text}](${href})` : text; } - case 'img': - case 'image': { - const alt = node.alt || node.title || ''; - const src = node.url || node.src || ''; + case "img": + case "image": { + const alt = node.alt || node.title || ""; + const src = node.url || node.src || ""; return `![${alt}](${src})`; } - case 'jsx': - case 'mdxJsxFlowElement': - case 'mdxJsxTextElement': { - // Emit marker-form components (jsx:Name ...) so CAT tools see them - const propsToString = (pairs) => { - if (!pairs || !pairs.length) return ''; - return pairs.map(attr => { - const name = attr.name || attr.key || ''; - const value = attr.hasOwnProperty('value') ? attr.value : attr.val || attr.v; - if (!name) return ''; + case "jsx": + case "mdxJsxFlowElement": + case "mdxJsxTextElement": { + // Emit marker-form components (jsx:Name ...) so CAT tools see them + const propsToString = (pairs) => { + if (!pairs?.length) return ""; + return pairs + .map((attr) => { + const name = attr.name || attr.key || ""; + const value = Object.hasOwn(attr, "value") + ? attr.value + : attr.val || attr.v; + if (!name) return ""; if (value === true || value === undefined) return name; - if (typeof value === 'string') return `${name}=${JSON.stringify(value)}`; + if (typeof value === "string") + return `${name}=${JSON.stringify(value)}`; try { return `${name}={${JSON.stringify(value)}}`; - } catch (e) { + } catch { return `${name}=${JSON.stringify(String(value))}`; } - }).filter(Boolean).join(' '); - }; - - // Determine children content (prefer explicit children array). - // If not present, attempt a deep extraction from nested shapes - // (GraphQL/Tina may return varying AST shapes). - const deepSerialize = (obj) => { - if (obj === null || obj === undefined) return ''; - if (typeof obj === 'string') return obj; - if (Array.isArray(obj)) return obj.map(deepSerialize).join(''); - if (typeof obj === 'object') { - // If this looks like a node, let serializer handle it - if (obj.type) return serializeRichTextToMarkdown(obj); - // common text fields - if (obj.value || obj.text || obj.literal) return String(obj.value || obj.text || obj.literal); - // children-like containers - if (obj.children) return deepSerialize(obj.children); - if (obj._values) return deepSerialize(obj._values); - // otherwise inspect own properties - const parts = []; - for (const k of Object.keys(obj)) { - try { - parts.push(deepSerialize(obj[k])); - } catch (e) {} - } - return parts.join(''); - } - return String(obj); - }; - - let children = ''; - if (node.children && node.children.length) { - children = node.children.map(serializeRichTextToMarkdown).join(''); - } else if (node.attributes && node.attributes.length) { - const childAttr = node.attributes.find(a => a.name === 'children' && (a.value !== undefined && a.value !== null)); - if (childAttr) { - children = typeof childAttr.value === 'string' ? childAttr.value : deepSerialize(childAttr.value); - } - } else if (node.props && node.props.children) { - children = typeof node.props.children === 'string' ? node.props.children : deepSerialize(node.props.children); - } else if (node._values && node._values.children) { - children = typeof node._values.children === 'string' ? node._values.children : deepSerialize(node._values.children); - } else { - // final attempt: scan the whole node for nested text - children = deepSerialize(node); - } + }) + .filter(Boolean) + .join(" "); + }; - // If children derived from node.children was empty, prefer any - // explicit `props.children` or `_values.children` which may contain - // meaningful content (some AST shapes put the real child inside props). - if ((!children || String(children).trim() === '')) { - if (node.props && node.props.children) { - children = typeof node.props.children === 'string' ? node.props.children : deepSerialize(node.props.children); - } else if (node._values && node._values.children) { - children = typeof node._values.children === 'string' ? node._values.children : deepSerialize(node._values.children); + // Determine children content (prefer explicit children array). + // If not present, attempt a deep extraction from nested shapes + // (GraphQL/Tina may return varying AST shapes). + const deepSerialize = (obj) => { + if (obj === null || obj === undefined) return ""; + if (typeof obj === "string") return obj; + if (Array.isArray(obj)) return obj.map(deepSerialize).join(""); + if (typeof obj === "object") { + // If this looks like a node, let serializer handle it + if (obj.type) return serializeRichTextToMarkdown(obj); + // common text fields + if (obj.value || obj.text || obj.literal) + return String(obj.value || obj.text || obj.literal); + // children-like containers + if (obj.children) return deepSerialize(obj.children); + if (obj._values) return deepSerialize(obj._values); + // otherwise inspect own properties + const parts = []; + for (const k of Object.keys(obj)) { + try { + parts.push(deepSerialize(obj[k])); + } catch {} } + return parts.join(""); } + return String(obj); + }; - // collect attribute pairs from various node shapes - let attrPairs = []; - if (node.attributes && Array.isArray(node.attributes) && node.attributes.length) { - attrPairs = node.attributes - .filter(a => a && a.name && String(a.name).toLowerCase() !== 'children') - .map(a => ({ name: a.name, value: a.value })); - } else if (node.props && typeof node.props === 'object') { - attrPairs = Object.keys(node.props).filter(k => k !== 'children').map(k => ({ name: k, value: node.props[k] })); - } else if (node._values && typeof node._values === 'object') { - attrPairs = Object.keys(node._values).filter(k => k !== 'children').map(k => ({ name: k, value: node._values[k] })); + let children = ""; + if (node.children?.length) { + children = node.children.map(serializeRichTextToMarkdown).join(""); + } else if (node.attributes?.length) { + const childAttr = node.attributes.find( + (a) => + a.name === "children" && a.value !== undefined && a.value !== null + ); + if (childAttr) { + children = + typeof childAttr.value === "string" + ? childAttr.value + : deepSerialize(childAttr.value); } - const props = propsToString(attrPairs); - const p = props ? ' ' + props : ''; - if (children && children.length) { - return `(jsx:${node.name}${p})${children}(/jsx:${node.name})`; - } - // Prefer exposing a primary prop value (common keys like title, - // summary or caption) as the visible child text when no children - // are present. This gives translators the actual text they need - // rather than a machine-readable parenthetical list. - const preferred = ['title', 'summary', 'caption', 'alt', 'label', 'termKey', 'text']; - let primary = null; - for (const k of preferred) { - const found = (attrPairs || []).find(a => a && String(a.name) === k && typeof a.value === 'string' && String(a.value).trim()); - if (found) { primary = String(found.value); break; } - } - if (primary) { - return `(jsx:${node.name}${p})${primary}(/jsx:${node.name})`; + } else if (node.props?.children) { + children = + typeof node.props.children === "string" + ? node.props.children + : deepSerialize(node.props.children); + } else if (node._values?.children) { + children = + typeof node._values.children === "string" + ? node._values.children + : deepSerialize(node._values.children); + } else { + // final attempt: scan the whole node for nested text + children = deepSerialize(node); + } + + // If children derived from node.children was empty, prefer any + // explicit `props.children` or `_values.children` which may contain + // meaningful content (some AST shapes put the real child inside props). + if (!children || String(children).trim() === "") { + if (node.props?.children) { + children = + typeof node.props.children === "string" + ? node.props.children + : deepSerialize(node.props.children); + } else if (node._values?.children) { + children = + typeof node._values.children === "string" + ? node._values.children + : deepSerialize(node._values.children); } - // Fallback: expose a compact parenthetical annotation containing - // simple prop values so translators can still see translatable - // strings when no obvious primary prop exists. - const annParts = (attrPairs || []).map(a => { - const v = a && a.value; - if (v === undefined || v === null) return ''; - if (typeof v === 'string') return `${a.name}:${v}`; - try { return `${a.name}:${JSON.stringify(v)}`; } catch (e) { return `${a.name}:${String(v)}`; } - }).filter(Boolean); - if (annParts.length) { - const ann = `(${annParts.join(', ')})`; - return `(jsx:${node.name}${p})${ann}(/jsx:${node.name})`; + } + + // collect attribute pairs from various node shapes + let attrPairs = []; + if ( + node.attributes && + Array.isArray(node.attributes) && + node.attributes.length + ) { + attrPairs = node.attributes + .filter((a) => a?.name && String(a.name).toLowerCase() !== "children") + .map((a) => ({ name: a.name, value: a.value })); + } else if (node.props && typeof node.props === "object") { + attrPairs = Object.keys(node.props) + .filter((k) => k !== "children") + .map((k) => ({ name: k, value: node.props[k] })); + } else if (node._values && typeof node._values === "object") { + attrPairs = Object.keys(node._values) + .filter((k) => k !== "children") + .map((k) => ({ name: k, value: node._values[k] })); + } + const props = propsToString(attrPairs); + const p = props ? ` ${props}` : ""; + if (children?.length) { + return `(jsx:${node.name}${p})${children}(/jsx:${node.name})`; + } + // Prefer exposing a primary prop value (common keys like title, + // summary or caption) as the visible child text when no children + // are present. This gives translators the actual text they need + // rather than a machine-readable parenthetical list. + const preferred = [ + "title", + "summary", + "caption", + "alt", + "label", + "termKey", + "text", + ]; + let primary = null; + for (const k of preferred) { + const found = (attrPairs || []).find( + (a) => + a && + String(a.name) === k && + typeof a.value === "string" && + String(a.value).trim() + ); + if (found) { + primary = String(found.value); + break; } - return `(jsx:${node.name}${p}/)`; + } + if (primary) { + return `(jsx:${node.name}${p})${primary}(/jsx:${node.name})`; + } + // Fallback: expose a compact parenthetical annotation containing + // simple prop values so translators can still see translatable + // strings when no obvious primary prop exists. + const annParts = (attrPairs || []) + .map((a) => { + const v = a?.value; + if (v === undefined || v === null) return ""; + if (typeof v === "string") return `${a.name}:${v}`; + try { + return `${a.name}:${JSON.stringify(v)}`; + } catch { + return `${a.name}:${String(v)}`; + } + }) + .filter(Boolean); + if (annParts.length) { + const ann = `(${annParts.join(", ")})`; + return `(jsx:${node.name}${p})${ann}(/jsx:${node.name})`; + } + return `(jsx:${node.name}${p}/)`; } default: // Fallback: serialize children - return (node.children || []).map(serializeRichTextToMarkdown).join(''); + return (node.children || []).map(serializeRichTextToMarkdown).join(""); } } @@ -1034,25 +1120,28 @@ function serializeRichTextToMarkdown(node) { // links so hrefs are preserved in XLIFF text exports. This is a best-effort // conversion for stringy bodies that may contain raw HTML. function htmlAnchorsToMarkdown(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; try { // Unescape common < > entities so regex can match tags - let work = String(s).replace(/</g, '<').replace(/>/g, '>'); + let work = String(s).replace(/</g, "<").replace(/>/g, ">"); // Replace anchor tags with Markdown links; capture href in single/double/no-quotes - work = work.replace(/]*href=(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi, (m, g1, g2, g3, inner) => { - const href = g1 || g2 || g3 || ''; - // strip any nested tags inside link text - const innerStr = inner.replace(/<[^>]+>/g, '').trim(); - // If inner already contains a markdown-style link like [text](url), - // avoid producing nested markdown. Prefer an inline form: "text ". - const mdMatch = innerStr.match(/\[([^\]]+)\]\(([^)]+)\)/); - if (mdMatch) { - const display = mdMatch[1] || innerStr; - const u = href || (mdMatch[2] || '').trim(); - return u ? `${display} <${u}>` : display; - } - return href ? `[${innerStr}](${href})` : innerStr; - }); + work = work.replace( + /]*href=(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi, + (_m, g1, g2, g3, inner) => { + const href = g1 || g2 || g3 || ""; + // strip any nested tags inside link text + const innerStr = inner.replace(/<[^>]+>/g, "").trim(); + // If inner already contains a markdown-style link like [text](url), + // avoid producing nested markdown. Prefer an inline form: "text ". + const mdMatch = innerStr.match(/\[([^\]]+)\]\(([^)]+)\)/); + if (mdMatch) { + const display = mdMatch[1] || innerStr; + const u = href || (mdMatch[2] || "").trim(); + return u ? `${display} <${u}>` : display; + } + return href ? `[${innerStr}](${href})` : innerStr; + } + ); // Convert bare URLs into Markdown links: https://example.com -> [example.com](https://example.com) // Avoid autolinking URLs that are already part of a markdown link or // are inside angle brackets/parentheses/brackets to prevent nested links. @@ -1078,14 +1167,18 @@ function htmlAnchorsToMarkdown(s) { return s; }; work = _protect(work); - work = work.replace(/(?]+/gi, (m) => { + work = work.replace(/(?]+/gi, (m) => { try { const url = m; // use hostname or full url for link text let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } + try { + text = new URL(url).hostname; + } catch { + text = url; + } return `[${text}](${url})`; - } catch (e) { + } catch { return m; } }); @@ -1093,31 +1186,45 @@ function htmlAnchorsToMarkdown(s) { work = _protect(work); // Autolink www. and common TLDs without scheme (e.g. www.example.com or example.com) // Avoid cases already wrapped in markdown or angle brackets. - work = work.replace(/(?]+/gi, (m) => { - const url = m.startsWith('http') ? m : `https://${m}`; + work = work.replace(/(?]+/gi, (m) => { + const url = m.startsWith("http") ? m : `https://${m}`; let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } + try { + text = new URL(url).hostname; + } catch { + text = url; + } return `[${text}](${url})`; }); work = _protect(work); - work = work.replace(/(? { - // Avoid converting markdown-wrapped links or already-handled anchors - if (/^\[.*\]\(.*\)$/.test(m)) return m; - const url = m.startsWith('http') ? m : `https://${m}`; - let text; - try { text = (new URL(url)).hostname; } catch (e) { text = url; } - return `[${text}](${url})`; - }); + work = work.replace( + /(? { + // Avoid converting markdown-wrapped links or already-handled anchors + if (/^\[.*\]\(.*\)$/.test(m)) return m; + const url = m.startsWith("http") ? m : `https://${m}`; + let text; + try { + text = new URL(url).hostname; + } catch { + text = url; + } + return `[${text}](${url})`; + } + ); // Restore all protected markdown links - work = work.replace(/___MDLINK_(\d+)___/g, (m, idx) => _mdLinkSlots[parseInt(idx, 10)] || m); + work = work.replace( + /___MDLINK_(\d+)___/g, + (m, idx) => _mdLinkSlots[parseInt(idx, 10)] || m + ); return work; - } catch (e) { + } catch { return s; } } function escapeRegExpFor(text) { - return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return String(text).replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Walk an AST-like object (various shapes from Tina) and gather link @@ -1126,25 +1233,37 @@ function escapeRegExpFor(text) { function gatherLinkPairsFromAst(node, out) { out = out || []; if (!node) return out; - if (typeof node === 'string') return out; + if (typeof node === "string") return out; if (Array.isArray(node)) { for (const c of node) gatherLinkPairsFromAst(c, out); return out; } - if (typeof node === 'object') { + if (typeof node === "object") { const type = node.type || node._type || node.name || node.tagName; - if (type && String(type).toLowerCase() === 'link') { - const text = (node.children || []).map(n => (typeof n === 'string' ? n : (n.text || n.value || ''))).join('') || node.title || node.text || ''; - const href = node.url || node.href || node.destination || ''; - if (text && href) out.push({ text: String(text).trim(), href: String(href).trim() }); + if (type && String(type).toLowerCase() === "link") { + const text = + (node.children || []) + .map((n) => (typeof n === "string" ? n : n.text || n.value || "")) + .join("") || + node.title || + node.text || + ""; + const href = node.url || node.href || node.destination || ""; + if (text && href) + out.push({ text: String(text).trim(), href: String(href).trim() }); } // also inspect known prop shapes that may contain links if (node.url && (node.title || node.text)) { - out.push({ text: String(node.title || node.text).trim(), href: String(node.url).trim() }); + out.push({ + text: String(node.title || node.text).trim(), + href: String(node.url).trim(), + }); } // recursively inspect properties for (const k of Object.keys(node)) { - try { gatherLinkPairsFromAst(node[k], out); } catch (e) {} + try { + gatherLinkPairsFromAst(node[k], out); + } catch {} } } return out; @@ -1155,23 +1274,23 @@ function gatherLinkPairsFromAst(node, out) { // href is already present in the conv text. function repairLinksFromAst(conv, srcNode) { try { - if (!conv || typeof conv !== 'string') return conv; + if (!conv || typeof conv !== "string") return conv; if (!srcNode) return conv; // if conv already contains an explicit url, skip repair if (/https?:\/\//.test(conv) || /`); } } return out; - } catch (e) { + } catch { return conv; } } @@ -1182,30 +1301,29 @@ function findUrlsInObject(obj) { try { const txt = JSON.stringify(obj || {}, null, 0); const re = /https?:\/\/[^"'\\\s,<>]*/gi; - const out = []; - let m; - while ((m = re.exec(txt)) !== null) { - out.push(m[0]); - } - return out; - } catch (e) { + return txt.match(re) || []; + } catch { return []; } } // Append extracted URLs to plain list items when link pairs aren't available. function appendUrlsToListItems(conv, urls) { - if (!conv || !urls || !urls.length) return conv; + if (!conv || !urls?.length) return conv; const lines = String(conv).split(/\r?\n/); let i = 0; for (let li = 0; li < lines.length && i < urls.length; li++) { const line = lines[li]; - if (/^\s*-\s+/.test(line) && !/https?:\/\//.test(line) && !/'; + if ( + /^\s*-\s+/.test(line) && + !/https?:\/\//.test(line) && + !/`; i++; } } - return lines.join('\n'); + return lines.join("\n"); } // Preserve Markdown inline links [text](url) as-is. Previously this function @@ -1223,13 +1341,16 @@ function markdownLinksToInlineUrl(s) { // markdown link using the inner URL (url1). This avoids producing // malformed or duplicated links during subsequent conversions. function normalizeNestedMarkdownLinks(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; try { - return String(s).replace(/\[\[([^\]]+)\]\(([^)]+)\)\]\(([^)]+)\)/g, (m, innerText, innerUrl, outerUrl) => { - // prefer the inner URL as it is usually the intended target - return `[${innerText}](${innerUrl})`; - }); - } catch (e) { + return String(s).replace( + /\[\[([^\]]+)\]\(([^)]+)\)\]\(([^)]+)\)/g, + (_m, innerText, innerUrl, _outerUrl) => { + // prefer the inner URL as it is usually the intended target + return `[${innerText}](${innerUrl})`; + } + ); + } catch { return s; } } @@ -1238,54 +1359,90 @@ function normalizeNestedMarkdownLinks(s) { // into explicit Markdown links so hrefs survive export. Handles both // angle-bracket JSX and marker-form `(jsx:...)` forms. function convertJsxPropLinksToMarkdown(s) { - if (!s || typeof s !== 'string') return s; + if (!s || typeof s !== "string") return s; let out = String(s); try { // 1) Handle marker-form paired elements: (jsx:Name props...)children(/jsx:Name) - out = out.replace(/\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, (m, name, props, children) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const text = (children && String(children).trim()) ? String(children).trim() : (String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i) || [])[1] || href; - if (href) return `[${text}](${href})`; + out = out.replace( + /\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\)([\s\S]*?)\(\/jsx:\1\)/g, + (m, _name, props, children) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const text = + children && String(children).trim() + ? String(children).trim() + : (String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ) || [])[1] || href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); + ); // 2) Handle angle-bracket paired JSX: children - out = out.replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, (m, name, props, children) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const text = (children && String(children).trim()) ? String(children).trim() : (String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i) || [])[1] || href; - if (href) return `[${text}](${href})`; + out = out.replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + (m, _name, props, children) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const text = + children && String(children).trim() + ? String(children).trim() + : (String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ) || [])[1] || href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); + ); // 3) Handle self-closing marker or angle forms with href prop: (jsx:Name href="...") or - out = out.replace(/\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, (m, name, props) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const textMatch = String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i); - const text = (textMatch && (textMatch[1]||textMatch[2]||textMatch[3])) ? (textMatch[1]||textMatch[2]||textMatch[3]) : href; - if (href) return `[${text}](${href})`; + out = out.replace( + /\(jsx:([A-Z][\w-]*)((?:[^)"'{}]|"[^"]*"|'[^']*'|\{[^}]*\})*)\/\)/g, + (m, _name, props) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + if (hrefMatch) { + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const textMatch = String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s)]+))/i + ); + const text = + textMatch && (textMatch[1] || textMatch[2] || textMatch[3]) + ? textMatch[1] || textMatch[2] || textMatch[3] + : href; + if (href) return `[${text}](${href})`; + } + return m; } - return m; - }); - out = out.replace(/<([A-Z][\w-]*)\b([^>]*)\/\>/g, (m, name, props) => { - const hrefMatch = String(props).match(/(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); + ); + out = out.replace(/<([A-Z][\w-]*)\b([^>]*)\/>/g, (m, _name, props) => { + const hrefMatch = String(props).match( + /(?:href|url|to|link)=(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); if (hrefMatch) { - const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ''; - const textMatch = String(props).match(/(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i); - const text = (textMatch && (textMatch[1]||textMatch[2]||textMatch[3])) ? (textMatch[1]||textMatch[2]||textMatch[3]) : href; + const href = hrefMatch[1] || hrefMatch[2] || hrefMatch[3] || ""; + const textMatch = String(props).match( + /(?:title|caption|alt)=?(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i + ); + const text = + textMatch && (textMatch[1] || textMatch[2] || textMatch[3]) + ? textMatch[1] || textMatch[2] || textMatch[3] + : href; if (href) return `[${text}](${href})`; } return m; }); - - } catch (e) { + } catch { return s; } return out; @@ -1295,39 +1452,45 @@ export async function exportOutOfDateAsXliff(client, language) { // Fetch docs and i18n similar to scanTranslations and build units for outdated const canonicalize = (p) => { if (!p) return p; - let s = p.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); + let s = p.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); return s; }; // load all docs and translations - const docsResult = await client.queries.docConnection({ sort: 'title', first: 1000 }); + const docsResult = await client.queries.docConnection({ + sort: "title", + first: 1000, + }); const docsEdges = docsResult.data?.docConnection?.edges || []; const sourceMap = {}; for (const edge of docsEdges) { const node = edge.node; - const rel = node._sys?.relativePath || node._sys?.filename || ''; + const rel = node._sys?.relativePath || node._sys?.filename || ""; let clean = rel; - if (rel.startsWith('docs/')) clean = rel.replace(/^docs\//, ''); - if (clean.startsWith('api/')) continue; + if (rel.startsWith("docs/")) clean = rel.replace(/^docs\//, ""); + if (clean.startsWith("api/")) continue; sourceMap[canonicalize(clean)] = node; } - const i18nResult = await client.queries.i18nConnection({ sort: 'title', first: 1000 }); + const i18nResult = await client.queries.i18nConnection({ + sort: "title", + first: 1000, + }); const i18nEdges = i18nResult.data?.i18nConnection?.edges || []; const translationsMap = {}; for (const edge of i18nEdges) { const node = edge.node; - const relPath = node._sys?.relativePath || node._sys?.filename || ''; + const relPath = node._sys?.relativePath || node._sys?.filename || ""; const m = relPath.match(/^([a-zA-Z0-9_-]+)\/(.*)$/); if (!m) continue; const lang = m[1]; if (lang !== language) continue; const after = m[2]; - const prefix = 'docusaurus-plugin-content-docs/current/'; + const prefix = "docusaurus-plugin-content-docs/current/"; if (!after.startsWith(prefix)) continue; - const cleanAfter = after.replace(new RegExp(`^${prefix}`), ''); + const cleanAfter = after.replace(new RegExp(`^${prefix}`), ""); const canonical = canonicalize(cleanAfter); translationsMap[canonical] = node; } @@ -1339,110 +1502,111 @@ export async function exportOutOfDateAsXliff(client, language) { if (!translationsMap[key]) continue; const tr = translationsMap[key]; // Determine lastmod dates consistent with scanTranslations rules - const srcDate = src && src.lastmod ? new Date(src.lastmod) : null; - const trDate = tr && tr.lastmod ? new Date(tr.lastmod) : null; + const srcDate = src?.lastmod ? new Date(src.lastmod) : null; + const trDate = tr?.lastmod ? new Date(tr.lastmod) : null; // Include only when source has a date and translation is missing or older const isOutOfDate = srcDate && (!trDate || trDate < srcDate); if (!isOutOfDate) continue; // Prefer raw MDX if available so exported contains original headings // and full MDX/React component contents. Strip YAML frontmatter and capture // metadata separately so it can be emitted as elements. - let sourceBody = ''; + let sourceBody = ""; let sourceMeta = {}; // Try several common places where Tina may store raw or rich content if (src.raw) { const parsed = extractFrontmatter(src.raw); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; + sourceBody = parsed.body || ""; } else if (src._raw) { const parsed = extractFrontmatter(src._raw); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; - } else if (src._values && typeof src._values === 'string') { + sourceBody = parsed.body || ""; + } else if (src._values && typeof src._values === "string") { const parsed = extractFrontmatter(src._values); sourceMeta = parsed.metadata || {}; - sourceBody = parsed.body || ''; - } else if (src._values && typeof src._values === 'object') { - // Support several shapes: _values.body may be a string or an AST-like - // object. Prefer serializing AST shapes to Markdown when possible. - if (src._values.body && typeof src._values.body === 'object') { - try { sourceBody = serializeRichTextToMarkdown(src._values.body); } catch (e) { sourceBody = JSON.stringify(src._values.body); } - } else if (src._values.body && typeof src._values.body === 'string') { - sourceBody = src._values.body; - } else if (src._values.children) { - try { sourceBody = serializeRichTextToMarkdown(src._values); } catch (e) { sourceBody = JSON.stringify(src._values); } - } else { - try { sourceBody = JSON.stringify(src._values); } catch (e) { sourceBody = String(src._values); } + sourceBody = parsed.body || ""; + } else if (src._values && typeof src._values === "object") { + // Support several shapes: _values.body may be a string or an AST-like + // object. Prefer serializing AST shapes to Markdown when possible. + if (src._values.body && typeof src._values.body === "object") { + try { + sourceBody = serializeRichTextToMarkdown(src._values.body); + } catch { + sourceBody = JSON.stringify(src._values.body); } - } else if (src.body && typeof src.body === 'object') { + } else if (src._values.body && typeof src._values.body === "string") { + sourceBody = src._values.body; + } else if (src._values.children) { + try { + sourceBody = serializeRichTextToMarkdown(src._values); + } catch { + sourceBody = JSON.stringify(src._values); + } + } else { + try { + sourceBody = JSON.stringify(src._values); + } catch { + sourceBody = String(src._values); + } + } + } else if (src.body && typeof src.body === "object") { try { sourceBody = serializeRichTextToMarkdown(src.body); - } catch (e) { + } catch { sourceBody = JSON.stringify(src.body); } - } else if (typeof src.body === 'string') { + } else if (typeof src.body === "string") { const parsed = extractFrontmatter(src.body); sourceMeta = parsed.metadata || {}; sourceBody = parsed.body || src.body; } else { - sourceBody = src.body || ''; + sourceBody = src.body || ""; } - // optional debug helper - const DEBUG = (typeof process !== 'undefined' && process && process.env && process.env.XLIFF_DEBUG === '1') || (typeof globalThis !== 'undefined' && globalThis && globalThis.__XLIFF_DEBUG); - const debug = (...args) => { if (DEBUG) try { console.error('[xliff-debug]', ...args); } catch (e) {} }; - - // emit debug info about which path we used to populate sourceBody - try { - if (DEBUG) { - const srcTypes = []; - if (src.raw) srcTypes.push('raw'); - if (src._raw) srcTypes.push('_raw'); - if (src._values) srcTypes.push('_values'); - if (src.body && typeof src.body === 'object') srcTypes.push('body(AST)'); - if (typeof src.body === 'string') srcTypes.push('body(string)'); - if (src._sys && (src._sys.relativePath || src._sys.filename)) srcTypes.push('has _sys'); - debug('unit', key, 'srcTypes=' + srcTypes.join(',') + ' sourceBodyLen=' + String(sourceBody || '').length); - } - } catch (e) {} - // Cloud-only export: do NOT attempt filesystem fallbacks here. // The exporter should rely exclusively on data returned by GraphQL/Tina. // Any previous server-side filesystem fallbacks have been removed to // ensure exports generated in cloud environments do not access local disk. - // For target prefer raw translated MDX if present (tr.raw), otherwise // handle common shapes returned by GraphQL/Tina. When translation content // is provided as an AST-like object (for example in `tr._values.body` or // `tr.body`), serialize it to Markdown so the XLIFF target is human- // readable rather than a JSON blob. - let targetBody = ''; + let targetBody = ""; let targetMeta = {}; if (tr.raw) { const parsedT = extractFrontmatter(tr.raw); targetMeta = parsedT.metadata || {}; - targetBody = parsedT.body || ''; - } else if (tr._values && typeof tr._values === 'object') { + targetBody = parsedT.body || ""; + } else if (tr._values && typeof tr._values === "object") { // Prefer AST in tr._values.body when available - if (tr._values.body && typeof tr._values.body === 'object') { - try { targetBody = serializeRichTextToMarkdown(tr._values.body); } catch (e) { targetBody = JSON.stringify(tr._values.body); } - } else if (tr._values.body && typeof tr._values.body === 'string') { + if (tr._values.body && typeof tr._values.body === "object") { + try { + targetBody = serializeRichTextToMarkdown(tr._values.body); + } catch { + targetBody = JSON.stringify(tr._values.body); + } + } else if (tr._values.body && typeof tr._values.body === "string") { targetBody = tr._values.body; } else { - try { targetBody = JSON.stringify(tr._values); } catch (e) { targetBody = String(tr._values); } + try { + targetBody = JSON.stringify(tr._values); + } catch { + targetBody = String(tr._values); + } } - } else if (tr.body && typeof tr.body === 'object') { + } else if (tr.body && typeof tr.body === "object") { try { targetBody = serializeRichTextToMarkdown(tr.body); - } catch (e) { + } catch { targetBody = JSON.stringify(tr.body); } } else { - targetBody = tr.body || ''; + targetBody = tr.body || ""; } - const sourceTitle = src.title || ''; - const targetTitle = tr.title || ''; + const sourceTitle = src.title || ""; + const targetTitle = tr.title || ""; // Cloud-only export: do not attempt any additional filesystem fallback // here. If GraphQL/Tina returns an empty or incomplete shape for the @@ -1451,13 +1615,24 @@ export async function exportOutOfDateAsXliff(client, language) { // capture an explicit source path (if available) so we can store it as // a note for downstream tools (Swordfish may replace unit ids with // numeric placeholders; keeping the original path in notes preserves it). - const sourcePath = (src && src._sys && (src._sys.relativePath || src._sys.filename)) || (typeof key === 'string' ? `docs/${key}.mdx` : ''); - units.push({ id: key, sourceTitle, targetTitle, sourceBody, targetBody, sourceMeta, targetMeta, sourcePath }); + const sourcePath = + (src?._sys && (src._sys.relativePath || src._sys.filename)) || + (typeof key === "string" ? `docs/${key}.mdx` : ""); + units.push({ + id: key, + sourceTitle, + targetTitle, + sourceBody, + targetBody, + sourceMeta, + targetMeta, + sourcePath, + }); } // build XLIFF 2.1 document (Swordfish and most CAT tools prefer 2.0/2.1 over 2.2) const header = `\n\n`; - let body = ''; + let body = ""; // group by file attribute (we'll use language as file id) body += ` \n`; for (const u of units) { @@ -1465,19 +1640,19 @@ export async function exportOutOfDateAsXliff(client, language) { // Build notes for metadata. Include title and any frontmatter keys we captured. const notes = []; // store original source file path to aid tools that replace unit ids - notes.push(`path:${u.sourcePath || ''}`); - notes.push(`title:${u.sourceTitle || u.targetTitle || ''}`); + notes.push(`path:${u.sourcePath || ""}`); + notes.push(`title:${u.sourceTitle || u.targetTitle || ""}`); // source metadata if (u.sourceMeta) { for (const k of Object.keys(u.sourceMeta)) { - if (k === 'title') continue; + if (k === "title") continue; notes.push(`${k}:${u.sourceMeta[k]}`); } } // target metadata (prefix keys with 't.' to avoid collisions) if (u.targetMeta) { for (const k of Object.keys(u.targetMeta)) { - if (k === 'title') continue; + if (k === "title") continue; notes.push(`t.${k}:${u.targetMeta[k]}`); } } @@ -1488,7 +1663,9 @@ export async function exportOutOfDateAsXliff(client, language) { body += ` \n`; body += ` \n`; // Ensure source is never empty: insert a visible placeholder if needed - let safeSource = (u.sourceBody || '').toString().trim() ? u.sourceBody : '(no source content)'; + let safeSource = (u.sourceBody || "").toString().trim() + ? u.sourceBody + : "(no source content)"; // Cloud-only export: do not attempt to read local docs files by unit id. // If GraphQL did not provide content, leave the placeholder rather than // trying to access disk in cloud environments. @@ -1504,36 +1681,35 @@ export async function exportOutOfDateAsXliff(client, language) { // Normalize nested markdown links, convert to inline form so hrefs // survive CAT-tool round-trips, then convert HTML anchors and JSX prop // links. - let conv = outsideCodeFences(normalizeNestedMarkdownLinks)(String(safeSource)); + let conv = outsideCodeFences(normalizeNestedMarkdownLinks)( + String(safeSource) + ); conv = outsideCodeFences(markdownLinksToInlineUrl)(conv); conv = outsideCodeFences(htmlAnchorsToMarkdown)(conv); - // Extra debug output for specific problematic document - try { - if (DEBUG && u && String(u.id) === 'Getting-started---working-in-the-cloud') { - console.error('[xliff-debug-unit] id=' + u.id + ' serializedSourceLen=' + String((safeSource||'').length)); - console.error('[xliff-debug-unit] after normalizeNestedMarkdownLinks:\n' + normalizeNestedMarkdownLinks(String(safeSource)).slice(0,2000)); - console.error('[xliff-debug-unit] after markdownLinksToInlineUrl:\n' + markdownLinksToInlineUrl(normalizeNestedMarkdownLinks(String(safeSource))).slice(0,2000)); - console.error('[xliff-debug-unit] after htmlAnchorsToMarkdown:\n' + htmlAnchorsToMarkdown(markdownLinksToInlineUrl(normalizeNestedMarkdownLinks(String(safeSource)))).slice(0,2000)); - } - } catch (e) {} // If conversion appears to have lost hrefs, attempt AST-based repair try { - if ((!/https?:\/\//.test(conv) || /\[.*\]\(/.test(safeSource)) && src && src._values) { + if ( + (!/https?:\/\//.test(conv) || /\[.*\]\(/.test(safeSource)) && + src && + src._values + ) { conv = repairLinksFromAst(conv, src._values.body || src._values); // If repair didn't find pairs, try extracting raw URLs from the // source object and append them to list items in order. - if ((!/https?:\/\//.test(conv) || !/marker conversion so hrefs are visible to translators. conv = outsideCodeFences(convertJsxPropLinksToMarkdown)(conv); - conv = outsideCodeFences(s => s.replace(/</g, '<').replace(/>/g, '>'))(conv); + conv = outsideCodeFences((s) => + s.replace(/</g, "<").replace(/>/g, ">") + )(conv); // Convert angle-bracket JSX to marker form for CAT tools; do not // append parenthetical annotations here to avoid duplicate prop // annotations in the exported XLIFF. Translators will see props @@ -1547,10 +1723,10 @@ export async function exportOutOfDateAsXliff(client, language) { // the previous [^)]* approach which failed when JSX props contained ')'. conv = conv.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); safeSource = conv; - } catch (e) { + } catch { // ignore and fall back to raw source } // sanitize control chars before emitting @@ -1559,74 +1735,96 @@ export async function exportOutOfDateAsXliff(client, language) { // Ensure target text also preserves anchor hrefs and markdown links. // Convert markdown links to inline form and convert any HTML anchors // or JSX-prop links so hrefs are visible in the exported XLIFF target. - let safeTarget = outsideCodeFences(normalizeNestedMarkdownLinks)(String(u.targetBody || '')); + let safeTarget = outsideCodeFences(normalizeNestedMarkdownLinks)( + String(u.targetBody || "") + ); safeTarget = outsideCodeFences(markdownLinksToInlineUrl)(safeTarget); safeTarget = outsideCodeFences(htmlAnchorsToMarkdown)(safeTarget); safeTarget = outsideCodeFences(convertJsxPropLinksToMarkdown)(safeTarget); // Convert JSX to marker form and strip annotations (same pipeline as source) try { - safeTarget = outsideCodeFences(s => s.replace(/</g, '<').replace(/>/g, '>'))(safeTarget); + safeTarget = outsideCodeFences((s) => + s.replace(/</g, "<").replace(/>/g, ">") + )(safeTarget); safeTarget = outsideCodeFences(angleToMarker)(safeTarget); safeTarget = safeTarget.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); - } catch (e) { /* keep as-is on error */ } + } catch { + /* keep as-is on error */ + } const sanitizedTarget = stripControlChars(safeTarget); body += ` ${escapeXmlPreserveNewlines(sanitizedTarget)}\n`; body += ` \n`; body += ` \n`; } - body += ' \n'; - const footer = '\n'; + body += " \n"; + const footer = "\n"; return header + body + footer; } -export async function importXliffBundle(client, xliffText, language, onProgress) { +export async function importXliffBundle( + client, + xliffText, + language, + onProgress +) { // Surface an immediate progress signal so UI knows the import started - try { if (onProgress) onProgress({ id: null, status: 'started' }); } catch (e) {} + try { + if (onProgress) onProgress({ id: null, status: "started" }); + } catch {} // Parse XLIFF using DOMParser let doc; try { const parser = new DOMParser(); - doc = parser.parseFromString(xliffText, 'application/xml'); + doc = parser.parseFromString(xliffText, "application/xml"); } catch (parseErr) { - try { console.error && console.error('[xliff] parse error', parseErr); } catch (e) {} - if (onProgress) onProgress({ id: null, status: 'error', error: 'XLIFF parse error: ' + (parseErr && parseErr.message ? parseErr.message : String(parseErr)) }); - return [{ id: null, status: 'error', error: 'XLIFF parse error' }]; + if (onProgress) + onProgress({ + id: null, + status: "error", + error: + "XLIFF parse error: " + + (parseErr?.message ? parseErr.message : String(parseErr)), + }); + return [{ id: null, status: "error", error: "XLIFF parse error" }]; } // Be tolerant: XLIFF variants (or CAT tools like Swordfish) may wrap // units differently or add extra container tags. Try several fallbacks // to locate translation units: (XLIFF2), (XLIFF1.2) // or fall back to scanning for elements and their parent // or identifiers. Use a namespace-robust discovery. - const allEls = Array.from(doc.getElementsByTagName('*')); - let units = allEls.filter(el => { - const ln = (el.localName || el.tagName || '').toLowerCase(); - return ln === 'unit' || ln === 'trans-unit'; + const allEls = Array.from(doc.getElementsByTagName("*")); + let units = allEls.filter((el) => { + const ln = (el.localName || el.tagName || "").toLowerCase(); + return ln === "unit" || ln === "trans-unit"; }); if (!units || units.length === 0) { // find and use its ancestor as a unit-like container - const segs = allEls.filter(el => (el.localName || el.tagName || '').toLowerCase() === 'segment'); - units = segs.map(s => { + const segs = allEls.filter( + (el) => (el.localName || el.tagName || "").toLowerCase() === "segment" + ); + units = segs.map((s) => { // prefer parent unit/trans-unit, otherwise parent node if (!s) return s; const p = s.parentNode; if (!p) return s; - const pln = (p.localName || p.tagName || '').toLowerCase(); - if (pln === 'unit' || pln === 'trans-unit') return p; + const pln = (p.localName || p.tagName || "").toLowerCase(); + if (pln === "unit" || pln === "trans-unit") return p; return s; }); } // make unique (segments map could include duplicates) units = units.filter((v, i, a) => a.indexOf(v) === i); // diagnostic: report how many units were discovered - try { console.log && console.log('[xliff] discovered units:', units.length); } catch (e) {} // inform UI of discovered unit count - try { if (onProgress) onProgress({ id: null, status: 'discovered', count: units.length }); } catch (e) {} + try { + if (onProgress) + onProgress({ id: null, status: "discovered", count: units.length }); + } catch {} const results = []; for (const unit of units) { - try { console.debug && console.debug('[xliff] processing unit element', unit && (unit.getAttribute ? unit.getAttribute('id') : null)); } catch (e) {} // Try to determine an id for this unit. If unit lacks an explicit id, // attempt to find one on ancestor elements or derive one from a // `path:` note emitted by our exporter. @@ -1634,26 +1832,29 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (!p) return p; let s = String(p); // Strip a leading docs/ prefix if present - s = s.replace(/^docs\//, ''); + s = s.replace(/^docs\//, ""); // if path starts with a language code (2-3 letter code, optionally with // region e.g. "fr/", "nl/", "en-IE/") followed by the plugin prefix, // strip the language segment and plugin prefix together. const m = s.match(/^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(.*)$/i); if (m) s = m[1]; - s = s.replace(/^docusaurus-plugin-content-docs\/current\//, ''); - s = s.replace(/\.mdx?$|\.md$/i, ''); - s = s.replace(/\/(?:index|readme)$/i, ''); - if (s.startsWith('/')) s = s.slice(1); + s = s.replace(/^docusaurus-plugin-content-docs\/current\//, ""); + s = s.replace(/\.mdx?$|\.md$/i, ""); + s = s.replace(/\/(?:index|readme)$/i, ""); + if (s.startsWith("/")) s = s.slice(1); return s; }; let id = null; - if (unit.getAttribute && unit.getAttribute('id')) id = unit.getAttribute('id'); + if (unit.getAttribute?.("id")) id = unit.getAttribute("id"); // try ancestor nodes for id if (!id) { let p = unit.parentNode; while (p) { - if (p.getAttribute && p.getAttribute('id')) { id = p.getAttribute('id'); break; } + if (p.getAttribute?.("id")) { + id = p.getAttribute("id"); + break; + } p = p.parentNode; } } @@ -1667,11 +1868,11 @@ export async function importXliffBundle(client, xliffText, language, onProgress) let targetEl = null; if (unit.getElementsByTagName) { // Look for a element first - const segments = Array.from(unit.getElementsByTagName('segment')); + const segments = Array.from(unit.getElementsByTagName("segment")); const seg = segments.length ? segments[0] : null; if (seg) { - sourceEl = seg.getElementsByTagName('source')[0] || null; - targetEl = seg.getElementsByTagName('target')[0] || null; + sourceEl = seg.getElementsByTagName("source")[0] || null; + targetEl = seg.getElementsByTagName("target")[0] || null; } // If the segment target's text is identical to the segment source, // the translator may not have actually translated this segment (XLIFF @@ -1681,34 +1882,41 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // DeepL or TM). if (sourceEl && targetEl) { try { - const srcText = (sourceEl.textContent || '').trim(); - const tgtText = (targetEl.textContent || '').trim(); + const srcText = (sourceEl.textContent || "").trim(); + const tgtText = (targetEl.textContent || "").trim(); if (srcText && tgtText && srcText === tgtText) { // Target equals source — look for a different target in mtc:matches - const allTargets = Array.from(unit.getElementsByTagName('target')); + const allTargets = Array.from(unit.getElementsByTagName("target")); for (const t of allTargets) { if (t === targetEl) continue; - const altText = (t.textContent || '').trim(); + const altText = (t.textContent || "").trim(); if (altText && altText !== srcText) { targetEl = t; break; } } } - } catch (e) { /* keep segment target on error */ } + } catch { + /* keep segment target on error */ + } } // Fallback: pick the first source/target anywhere in the unit - if (!sourceEl) sourceEl = unit.getElementsByTagName('source')[0] || null; - if (!targetEl) targetEl = unit.getElementsByTagName('target')[0] || null; + if (!sourceEl) sourceEl = unit.getElementsByTagName("source")[0] || null; + if (!targetEl) targetEl = unit.getElementsByTagName("target")[0] || null; } - const notes = unit.getElementsByTagName ? Array.from(unit.getElementsByTagName('note')) : []; + const notes = unit.getElementsByTagName + ? Array.from(unit.getElementsByTagName("note")) + : []; // Find a note that starts with 'title:' (robust to ordering and whitespace) let titleNote = null; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^\s*title:\s*(.*)$/i); - if (m && m[1]) { titleNote = m[1].trim(); break; } + if (m?.[1]) { + titleNote = m[1].trim(); + break; + } } } // if no id yet, look for a note that begins with 'path:' which our exporter @@ -1716,11 +1924,11 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // original filename (including extension) for GraphQL relativePath so we // don't lose the .mdx extension required by the API. let rawPathFromNote = null; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^path:\s*(.*)$/i); - if (m && m[1]) { + if (m?.[1]) { rawPathFromNote = m[1].trim(); // use canonicalized id (without extensions) for unit id. // Always prefer the path-derived id over the existing id when the @@ -1736,21 +1944,26 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Extract visible text from the target while ignoring decorative XML tags const extractVisible = (el) => { - if (!el) return ''; - if (el.nodeType === 3) return el.nodeValue || ''; - let out = ''; + if (!el) return ""; + if (el.nodeType === 3) return el.nodeValue || ""; + let out = ""; const nodes = Array.from(el.childNodes || []); for (const n of nodes) { if (n.nodeType === 3) { - out += n.nodeValue || ''; + out += n.nodeValue || ""; } else if (n.nodeType === 1) { - const tag = (n.tagName || '').toLowerCase(); - if (tag === 'lb' || tag === 'br') { - out += '\n'; - } else if (tag === 'a') { + const tag = (n.tagName || "").toLowerCase(); + if (tag === "lb" || tag === "br") { + out += "\n"; + } else if (tag === "a") { // preserve links as Markdown [text](href) - const href = n.getAttribute && (n.getAttribute('href') || n.getAttribute('xlink:href') || n.getAttribute('data-href')) || ''; - const inner = extractVisible(n) || ''; + const href = + (n.getAttribute && + (n.getAttribute("href") || + n.getAttribute("xlink:href") || + n.getAttribute("data-href"))) || + ""; + const inner = extractVisible(n) || ""; if (href) out += `[${inner}](${href})`; else out += inner; } else { @@ -1761,7 +1974,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) return out; }; - let rawTarget = targetEl ? extractVisible(targetEl) : ''; + let rawTarget = targetEl ? extractVisible(targetEl) : ""; // If XML target contains JSON (export previously stored JSON), parse it; // otherwise treat as markdown/plain text and send through as-is. // Quick normalization: undo some remaining escape sequences that CAT @@ -1780,7 +1993,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // so props containing ')' in the preceding marker don't break matching. rawTarget = rawTarget.replace( /\)\s*\((?!jsx:|\/?jsx:)([a-zA-Z][\w-]*:[^()]*)\)/g, - ')' + ")" ); // Remove backslashes that CAT tools (e.g. Swordfish) insert before @@ -1790,22 +2003,35 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Note: \\n is left as-is (actual escaped newline) so we only strip // backslash when followed by a non-alphanumeric, non-space character // commonly used as a markdown control character. - rawTarget = rawTarget.replace(/\\([#\*\-\+\[\]\(\)>`_~!|:\.\\])/g, '$1'); + rawTarget = rawTarget.replace(/\\([#*\-+[\]()>`_~!|:.\\])/g, "$1"); // Undo escaped ordered-list dot: "1\. " -> "1. " (already covered by // the general pattern above, but keep for clarity) // Convert dash bullets to asterisk bullets for consistency with Tina // Preserve leading whitespace (indentation) for nested lists. // Only convert outside fenced code blocks so YAML/shell dashes are kept. - rawTarget = outsideCodeFences(s => s.replace(/(^|\n)(\s*)-\s+/g, '$1$2* '))(rawTarget); + rawTarget = outsideCodeFences((s) => + s.replace(/(^|\n)(\s*)-\s+/g, "$1$2* ") + )(rawTarget); // Trim accidental trailing whitespace per-line - rawTarget = rawTarget.split('\n').map(l => l.replace(/\s+$/,'')).join('\n'); - } catch (e) {} + rawTarget = rawTarget + .split("\n") + .map((l) => l.replace(/\s+$/, "")) + .join("\n"); + } catch {} // Targets exported by older flows may be JSON blobs; try to parse // JSON when it looks like a JSON object, otherwise keep string. let parsedBody = rawTarget; - if (rawTarget && typeof rawTarget === 'string' && rawTarget.trim().startsWith('{')) { - try { parsedBody = JSON.parse(rawTarget); } catch (e) { parsedBody = rawTarget; } + if ( + rawTarget && + typeof rawTarget === "string" && + rawTarget.trim().startsWith("{") + ) { + try { + parsedBody = JSON.parse(rawTarget); + } catch { + parsedBody = rawTarget; + } } // Convert angle-bracket JSX (e.g. ... // or ) to marker form so the parser handles them @@ -1819,13 +2045,19 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (fp % 2 === 0) { // Outside fenced code – convert angle-bracket JSX to marker form // Paired: content - fenceParts[fp] = fenceParts[fp].replace(/<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, '(jsx:$1$2)$3(/jsx:$1)'); + fenceParts[fp] = fenceParts[fp].replace( + /<([A-Z][\w-]*)\b([^>]*)>([\s\S]*?)<\/\1>/g, + "(jsx:$1$2)$3(/jsx:$1)" + ); // Self-closing: - fenceParts[fp] = fenceParts[fp].replace(/<([A-Z][\w-]*)\b([^>]*)\s*\/>/g, '(jsx:$1$2/)'); + fenceParts[fp] = fenceParts[fp].replace( + /<([A-Z][\w-]*)\b([^>]*)\s*\/>/g, + "(jsx:$1$2/)" + ); } } - rawTarget = fenceParts.join(''); - } catch (e) {} + rawTarget = fenceParts.join(""); + } catch {} // The parseMarkdownToTinaAst parser handles marker-form JSX directly // and creates proper mdxJsxFlowElement/mdxJsxTextElement nodes, // avoiding the problem where angle-bracket JSX in text nodes gets @@ -1837,7 +2069,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // available, fall back to `id` and append `.mdx` to satisfy the API. let rel = null; if (rawPathFromNote) { - let cleaned = rawPathFromNote.replace(/^docs\//, ''); + const cleaned = rawPathFromNote.replace(/^docs\//, ""); rel = `${language}/docusaurus-plugin-content-docs/current/${cleaned}`; } else if (id) { // ensure extension present @@ -1848,9 +2080,9 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } if (!rel) { const errMsg = `missing unit id`; - try { console.warn && console.warn('[xliff] skipping unit without id'); } catch (e) {} - results.push({ id: id || null, status: 'error', error: errMsg }); - if (onProgress) onProgress({ id: id || null, status: 'error', error: errMsg }); + results.push({ id: id || null, status: "error", error: errMsg }); + if (onProgress) + onProgress({ id: id || null, status: "error", error: errMsg }); continue; } @@ -1861,71 +2093,99 @@ export async function importXliffBundle(client, xliffText, language, onProgress) updateI18n(relativePath: $relativePath, params: $params) { id } } `; - // Build variables matching the UpdateI18n mutation: `params` must be - // an `I18nMutation` object (not wrapped under `i18n`). - // Ensure body is a JSON object as expected by the I18nMutation schema. - // If parsedBody is a plain string (markdown/plain text), preserve - // its newlines and common Markdown constructs rather than collapsing - // them to single-line paragraphs. Also attempt to undo some CAT-tool - // escapes and normalize empty paired JSX tags into self-closing form. - let bodyPayload = parsedBody; - if (typeof parsedBody === 'string') { - try { - // Collapse empty paired JSX tags like `` -> `` - parsedBody = parsedBody.replace(/<([A-Z][\\w-]*)([^>]*)>\s*<\/\1>/g, '<$1$2 />'); - } catch (e) { - /* ignore */ - } - try { - // Comprehensive backslash-unescape for markdown control characters - // that CAT tools may have inserted. The first rawTarget cleanup - // handles the bulk, but if parsedBody went through JSON-parse or - // markerToAngle it may have re-introduced some escapes. - parsedBody = parsedBody.replace(/\\([#\*\-\+\[\]\(\)>`_~!|:\.\\])/g, '$1'); - // Some CAT tools encode '#' as HTML entity; unescape common ones - parsedBody = parsedBody.replace(/#|#/g, '#'); - } catch (e) {} - - // Preserve full markdown text by parsing it into the structured - // Tina AST that TinaCMS expects for the `body` field. Previously - // the code split on double-newlines and wrapped each chunk in a - // bare { type: 'p', children: [{ type: 'text', text: ... }] } node - // which caused Tina's serializer to backslash-escape every Markdown - // control character (headings, list markers, backticks, etc.). - bodyPayload = parseMarkdownToTinaAst(String(parsedBody || '')); + // Build variables matching the UpdateI18n mutation: `params` must be + // an `I18nMutation` object (not wrapped under `i18n`). + // Ensure body is a JSON object as expected by the I18nMutation schema. + // If parsedBody is a plain string (markdown/plain text), preserve + // its newlines and common Markdown constructs rather than collapsing + // them to single-line paragraphs. Also attempt to undo some CAT-tool + // escapes and normalize empty paired JSX tags into self-closing form. + let bodyPayload = parsedBody; + if (typeof parsedBody === "string") { + try { + // Collapse empty paired JSX tags like `` -> `` + parsedBody = parsedBody.replace( + /<([A-Z][\\w-]*)([^>]*)>\s*<\/\1>/g, + "<$1$2 />" + ); + } catch { + /* ignore */ } + try { + // Comprehensive backslash-unescape for markdown control characters + // that CAT tools may have inserted. The first rawTarget cleanup + // handles the bulk, but if parsedBody went through JSON-parse or + // markerToAngle it may have re-introduced some escapes. + parsedBody = parsedBody.replace(/\\([#*\-+[\]()>`_~!|:.\\])/g, "$1"); + // Some CAT tools encode '#' as HTML entity; unescape common ones + parsedBody = parsedBody.replace(/#|#/g, "#"); + } catch {} + + // Preserve full markdown text by parsing it into the structured + // Tina AST that TinaCMS expects for the `body` field. Previously + // the code split on double-newlines and wrapped each chunk in a + // bare { type: 'p', children: [{ type: 'text', text: ... }] } node + // which caused Tina's serializer to backslash-escape every Markdown + // control character (headings, list markers, backticks, etc.). + bodyPayload = parseMarkdownToTinaAst(String(parsedBody || "")); + } // Seed metadata from entries as a fallback when the source // doc cannot be fetched (TinaCloud may reject doc queries). let sourceMetaParams = {}; try { const noteMeta = {}; - if (notes && notes.length) { + if (notes?.length) { for (const n of notes) { - const t = readElementTextPreservingLineBreaks(n) || ''; + const t = readElementTextPreservingLineBreaks(n) || ""; const m = t.match(/^\s*([^:]+):\s*([\s\S]*)$/); if (!m) continue; - const k = String(m[1] || '').trim(); - const vRaw = (m[2] || '').trim(); + const k = String(m[1] || "").trim(); + const vRaw = (m[2] || "").trim(); if (!k) continue; const lk = k.toLowerCase(); - if (lk === 'path') { continue; } // path is used for ID resolution, not a mutation field - if (lk === 'title') { noteMeta.title = vRaw; continue; } - if (lk === 'description') { noteMeta.description = vRaw; continue; } - if (lk === 'tags') { + if (lk === "path") { + continue; + } // path is used for ID resolution, not a mutation field + if (lk === "title") { + noteMeta.title = vRaw; + continue; + } + if (lk === "description") { + noteMeta.description = vRaw; + continue; + } + if (lk === "tags") { let vals = null; - try { if (/^[\[\{]/.test(vRaw)) vals = JSON.parse(vRaw); } catch (e) { vals = null; } + try { + if (/^[[{]/.test(vRaw)) vals = JSON.parse(vRaw); + } catch { + vals = null; + } if (!vals) vals = vRaw.split(/\s*,\s*/).filter(Boolean); noteMeta.tags = Array.isArray(vals) ? vals : [String(vals)]; continue; } - if (['draft','review','translate','approved','published','unlisted'].includes(lk)) { - noteMeta[lk] = (/^(true|1|yes)$/i).test(vRaw); + if ( + [ + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", + ].includes(lk) + ) { + noteMeta[lk] = /^(true|1|yes)$/i.test(vRaw); continue; } - if (lk === 'conditions') { + if (lk === "conditions") { let vals = null; - try { if (/^[\[]/.test(vRaw)) vals = JSON.parse(vRaw); } catch (e) { vals = null; } + try { + if (/^[[]/.test(vRaw)) vals = JSON.parse(vRaw); + } catch { + vals = null; + } if (!vals) vals = vRaw.split(/\s*,\s*/).filter(Boolean); noteMeta.conditions = Array.isArray(vals) ? vals : [String(vals)]; continue; @@ -1934,7 +2194,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } } sourceMetaParams = Object.assign({}, noteMeta); - } catch (e) { + } catch { /* ignore note parsing errors */ } @@ -1942,59 +2202,70 @@ export async function importXliffBundle(client, xliffText, language, onProgress) try { let sourceDocRel = null; if (rawPathFromNote) { - let rp = String(rawPathFromNote || '').replace(/^\/?/, ''); + let rp = String(rawPathFromNote || "").replace(/^\/?/, ""); // The `doc` collection resolves relative to its configured content // directory (typically `docs/`). Strip any prefix that doesn't // belong: `docs/`, `docusaurus-plugin-content-docs/current/`, or // language prefixes like `fr/...`. - rp = rp.replace(/^docs\//, ''); - rp = rp.replace(/^docusaurus-plugin-content-docs\/current\//, ''); - rp = rp.replace(/^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(?:docusaurus-plugin-content-docs\/current\/)?/, ''); + rp = rp.replace(/^docs\//, ""); + rp = rp.replace(/^docusaurus-plugin-content-docs\/current\//, ""); + rp = rp.replace( + /^[a-z]{2,3}(?:-[a-zA-Z]{2,4})?\/(?:docusaurus-plugin-content-docs\/current\/)?/, + "" + ); sourceDocRel = rp; } else if (id) { - const cleaned = String(id).replace(/^\//, '').replace(/\.mdx?$|\.md$/i, ''); + const cleaned = String(id) + .replace(/^\//, "") + .replace(/\.mdx?$|\.md$/i, ""); sourceDocRel = `${cleaned}.mdx`; } if (sourceDocRel) { // Strip leading slashes. try { - sourceDocRel = String(sourceDocRel || '').replace(/^\//, ''); - } catch (e) {} - try { console.debug && console.debug('[xliff] sourceDocRel normalized to', sourceDocRel); } catch (e) {} + sourceDocRel = String(sourceDocRel || "").replace(/^\//, ""); + } catch {} try { - const docQuery = await client.queries.doc({ relativePath: sourceDocRel }); - const sdoc = docQuery && docQuery.data && docQuery.data.doc ? docQuery.data.doc : null; + const docQuery = await client.queries.doc({ + relativePath: sourceDocRel, + }); + const sdoc = docQuery?.data?.doc ? docQuery.data.doc : null; if (sdoc) { // Dynamically copy all non-null fields from the source doc, // skipping internal/GraphQL fields and body/lastmod. - const skipKeys = new Set(['__typename', '_sys', '_values', 'id', 'body', 'lastmod']); + const skipKeys = new Set([ + "__typename", + "_sys", + "_values", + "id", + "body", + "lastmod", + ]); for (const k of Object.keys(sdoc)) { if (skipKeys.has(k)) continue; if (sdoc[k] != null) { - sourceMetaParams[k] = Array.isArray(sdoc[k]) ? sdoc[k].slice() : sdoc[k]; + sourceMetaParams[k] = Array.isArray(sdoc[k]) + ? sdoc[k].slice() + : sdoc[k]; } } } - } catch (dqErr) { - try { console.warn && console.warn('[xliff] source doc query failed for', sourceDocRel, dqErr && dqErr.message); } catch (e) {} - } + } catch (_dqErr) {} } - } catch (metaErr) { - try { console.warn && console.warn('[xliff] metadata clone failed', metaErr && metaErr.message); } catch (e) {} - } + } catch (_metaErr) {} // Build final params. // Prefer preserving an existing translation's frontmatter (except lastmod). // If a translation doc exists at `rel`, clone its metadata and replace // the `body` with the imported content. If no translation exists, // fall back to source-cloned metadata (or notes) and the title note. - let paramsObj = {}; + const paramsObj = {}; try { let existingTranslation = null; try { const trQuery = await client.queries.i18n({ relativePath: rel }); - existingTranslation = trQuery && trQuery.data && trQuery.data.i18n ? trQuery.data.i18n : null; - } catch (e) { + existingTranslation = trQuery?.data?.i18n ? trQuery.data.i18n : null; + } catch { // If fetching the existing translation fails (cloud permissions), // we'll fall back to source metadata parsed from notes or cloned source. existingTranslation = null; @@ -2003,11 +2274,20 @@ export async function importXliffBundle(client, xliffText, language, onProgress) if (existingTranslation) { // Retain whatever metadata is present in the existing translation. // Skip internal/GraphQL fields and lastmod/body (we set those below). - const skipKeys = new Set(['__typename', '_sys', '_values', 'id', 'body', 'lastmod']); + const skipKeys = new Set([ + "__typename", + "_sys", + "_values", + "id", + "body", + "lastmod", + ]); for (const k of Object.keys(existingTranslation)) { if (skipKeys.has(k)) continue; if (existingTranslation[k] != null) { - paramsObj[k] = Array.isArray(existingTranslation[k]) ? existingTranslation[k].slice() : existingTranslation[k]; + paramsObj[k] = Array.isArray(existingTranslation[k]) + ? existingTranslation[k].slice() + : existingTranslation[k]; } } } else { @@ -2018,7 +2298,7 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } if (titleNote) paramsObj.title = titleNote; } - } catch (buildErr) { + } catch { // Fallback to source-cloned metadata if anything unexpected fails. // Only include keys with meaningful values. for (const k of Object.keys(sourceMetaParams || {})) { @@ -2029,14 +2309,26 @@ export async function importXliffBundle(client, xliffText, language, onProgress) // Always replace the body with the imported payload and set new lastmod paramsObj.body = bodyPayload; - paramsObj.lastmod = (new Date()).toISOString(); + paramsObj.lastmod = new Date().toISOString(); // Sanitize params: only include fields defined by I18nMutation and strip // null/undefined values. This prevents unexpected fields (e.g. 'path' from // XLIFF notes, or 'priority' from source docs) from causing GraphQL errors. const validI18nFields = new Set([ - 'help', 'lastmod', 'modifiedBy', 'title', 'body', 'conditions', - 'description', 'slug', 'tags', 'draft', 'review', 'translate', - 'approved', 'published', 'unlisted' + "help", + "lastmod", + "modifiedBy", + "title", + "body", + "conditions", + "description", + "slug", + "tags", + "draft", + "review", + "translate", + "approved", + "published", + "unlisted", ]); const sanitized = {}; for (const k of Object.keys(paramsObj)) { @@ -2045,7 +2337,6 @@ export async function importXliffBundle(client, xliffText, language, onProgress) } const variables = { relativePath: rel, params: sanitized }; // client.request in the dashboard expects an object with query/variables - try { console.debug && console.debug('[xliff] sending update for', rel); } catch (e) {} // Send request and inspect response for GraphQL errors. Some client // implementations return a response object rather than throwing on // GraphQL errors, so we must explicitly check `errors` to avoid @@ -2054,43 +2345,51 @@ export async function importXliffBundle(client, xliffText, language, onProgress) try { resp = await client.request({ query: mutation, variables }); } catch (requestErr) { - const emsg = requestErr && requestErr.message ? requestErr.message : String(requestErr); - try { console.warn && console.warn('[xliff] request threw for', rel, emsg); } catch (e) {} - results.push({ id, status: 'error', error: emsg }); - if (onProgress) onProgress({ id, status: 'error', error: emsg }); + const emsg = requestErr?.message + ? requestErr.message + : String(requestErr); + results.push({ id, status: "error", error: emsg }); + if (onProgress) onProgress({ id, status: "error", error: emsg }); continue; } // The generated Tina requester may return { data, errors } or the raw // GraphQL data. Inspect both shapes and ensure updateI18n succeeded. - const respErrors = resp && (resp.errors || (resp.data && resp.data.errors)) || null; - if (respErrors && respErrors.length) { - const msg = (respErrors.map && respErrors.map(e => (e && e.message) ? e.message : String(e)).join('; ')) || 'GraphQL errors'; - try { console.warn && console.warn('[xliff] update failed for', rel, msg, resp); } catch (e) {} - results.push({ id, status: 'error', error: msg, response: resp }); - if (onProgress) onProgress({ id, status: 'error', error: msg, response: resp }); + const respErrors = (resp && (resp.errors || resp.data?.errors)) || null; + if (respErrors?.length) { + const msg = Array.isArray(respErrors) + ? respErrors + .map((e) => (e?.message ? e.message : String(e))) + .join("; ") + : "GraphQL errors"; + results.push({ id, status: "error", error: msg, response: resp }); + if (onProgress) + onProgress({ id, status: "error", error: msg, response: resp }); continue; } // If no explicit errors, ensure the mutation returned a valid payload. const data = resp && (resp.data || resp); - const updated = data && (data.updateI18n || (data.updateI18n === null ? null : (Object.values(data).find(v => v && v.id)))); + const updated = + data && + (data.updateI18n || + (data.updateI18n === null + ? null + : Object.values(data).find((v) => v?.id))); if (!updated) { // If updateI18n is absent or null, surface the whole response for diagnosis - const msg = 'No update returned from server'; - try { console.warn && console.warn('[xliff] no update for', rel, resp); } catch (e) {} - results.push({ id, status: 'error', error: msg, response: resp }); - if (onProgress) onProgress({ id, status: 'error', error: msg, response: resp }); + const msg = "No update returned from server"; + results.push({ id, status: "error", error: msg, response: resp }); + if (onProgress) + onProgress({ id, status: "error", error: msg, response: resp }); } else { - try { console.debug && console.debug('[xliff] update successful for', rel, updated); } catch (e) {} - results.push({ id, status: 'updated' }); - if (onProgress) onProgress({ id, status: 'updated' }); + results.push({ id, status: "updated" }); + if (onProgress) onProgress({ id, status: "updated" }); } } catch (err) { - const errMsg = err && err.message ? err.message : String(err); - try { console.warn && console.warn('[xliff] import error for', id, errMsg); } catch (e) {} - results.push({ id, status: 'error', error: errMsg }); - if (onProgress) onProgress({ id, status: 'error', error: errMsg }); + const errMsg = err?.message ? err.message : String(err); + results.push({ id, status: "error", error: errMsg }); + if (onProgress) onProgress({ id, status: "error", error: errMsg }); } } return results; diff --git a/template/tina/config.jsx b/template/tina/config.jsx index 3d77f3a5..98ed011b 100644 --- a/template/tina/config.jsx +++ b/template/tina/config.jsx @@ -1,22 +1,19 @@ import React from "react"; import { defineConfig, ReferenceField, TextField } from "tinacms"; -import { getEditorIdentity } from "../src/utils/editorIdentity"; // docusaurus config for language settings import docusaurusData from "../config/docusaurus/index.json"; // conditions from the conditions JSON file import conditionsData from "../reuse/conditions/index.json"; // doc tags from the taxonomy JSON file import data from "../reuse/taxonomy/index.json"; +import { docusaurusDate, titleFromSlug } from "../scripts/util"; // collapsible field component import CollapsibleField from "../src/components/CollapsibleField"; // conditions tree UI component import ConditionsTreeField from "../src/components/ConditionsField"; +import { DashboardsCollection } from "../src/components/Dashboard/template"; import { FeaturesBlockTemplate } from "../src/components/Features/template"; -import { - GlossaryTermCollection, - GlossaryTermTemplate, - GlossaryTermTranslationTemplate, -} from "../src/components/GlossaryTerm/template"; +import { GlossaryTermCollection } from "../src/components/GlossaryTerm/template"; // context help import HelpButton from "../src/components/HelpButton"; import { HeroBlockTemplate } from "../src/components/Hero/template"; @@ -27,9 +24,8 @@ import StatusField from "../src/components/StatusField"; import TagsField from "../src/components/TagsField"; import { ThemeCollection } from "../src/components/Theme/template"; import { YouTubeEmbedBlockTemplate } from "../src/components/YouTubeEmbed/template"; -import { DashboardsCollection } from "../src/components/Dashboard/template"; import { MDXTemplates } from "../src/theme/template"; -import { docusaurusDate, titleFromSlug } from "../scripts/util"; +import { getEditorIdentity } from "../src/utils/editorIdentity"; // Function to extract available locales from Docusaurus config @@ -52,7 +48,7 @@ function createLanguageOptions(configData = docusaurusData) { } // Get available locales from Docusaurus config -const availableLocales = getDocusaurusLocales(); +const _availableLocales = getDocusaurusLocales(); // Create language options with descriptive labels const languageOptions = createLanguageOptions(); @@ -227,8 +223,8 @@ const PostCollection = { format: (val) => { if (!val) return new Date(); // If we already have a YYYY-MM-DD string, create a Date object for the picker - if (typeof val === 'string' && val.match(/^\d{4}-\d{2}-\d{2}$/)) { - return new Date(val + 'T12:00:00.000Z'); // Use noon to avoid timezone issues + if (typeof val === "string" && val.match(/^\d{4}-\d{2}-\d{2}$/)) { + return new Date(`${val}T12:00:00.000Z`); // Use noon to avoid timezone issues } return new Date(val); }, @@ -922,7 +918,11 @@ const AutogeneratedTemplate = { ], }; -const LeafTemplates = [DocLinkTemplate, ExternalLinkTemplate, AutogeneratedTemplate]; +const LeafTemplates = [ + DocLinkTemplate, + ExternalLinkTemplate, + AutogeneratedTemplate, +]; const CategoryTemplate = { ...CategoryTemplateProps, @@ -997,10 +997,7 @@ const CategoryTemplate = { const SidebarItemsField = { ...ItemsField, - templates: [ - CategoryTemplate, - ...LeafTemplates, - ], + templates: [CategoryTemplate, ...LeafTemplates], }; const SidebarCollection = { @@ -1470,14 +1467,23 @@ const MediaCollection = { { type: "string", name: "filename", label: "Filename", required: true }, { type: "string", name: "path", label: "Path", required: true }, { type: "number", name: "size", label: "Size (bytes)", required: true }, - { type: "string", name: "dimensions", label: "Dimensions (WxH)", required: false }, - { type: "string", name: "lastModified", label: "Last Modified", required: false }, + { + type: "string", + name: "dimensions", + label: "Dimensions (WxH)", + required: false, + }, + { + type: "string", + name: "lastModified", + label: "Last Modified", + required: false, + }, ], }, ], }; - export default defineConfig({ branch, clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID, // Get this from tina.io diff --git a/tina/config.jsx b/tina/config.jsx index 3d77f3a5..98ed011b 100644 --- a/tina/config.jsx +++ b/tina/config.jsx @@ -1,22 +1,19 @@ import React from "react"; import { defineConfig, ReferenceField, TextField } from "tinacms"; -import { getEditorIdentity } from "../src/utils/editorIdentity"; // docusaurus config for language settings import docusaurusData from "../config/docusaurus/index.json"; // conditions from the conditions JSON file import conditionsData from "../reuse/conditions/index.json"; // doc tags from the taxonomy JSON file import data from "../reuse/taxonomy/index.json"; +import { docusaurusDate, titleFromSlug } from "../scripts/util"; // collapsible field component import CollapsibleField from "../src/components/CollapsibleField"; // conditions tree UI component import ConditionsTreeField from "../src/components/ConditionsField"; +import { DashboardsCollection } from "../src/components/Dashboard/template"; import { FeaturesBlockTemplate } from "../src/components/Features/template"; -import { - GlossaryTermCollection, - GlossaryTermTemplate, - GlossaryTermTranslationTemplate, -} from "../src/components/GlossaryTerm/template"; +import { GlossaryTermCollection } from "../src/components/GlossaryTerm/template"; // context help import HelpButton from "../src/components/HelpButton"; import { HeroBlockTemplate } from "../src/components/Hero/template"; @@ -27,9 +24,8 @@ import StatusField from "../src/components/StatusField"; import TagsField from "../src/components/TagsField"; import { ThemeCollection } from "../src/components/Theme/template"; import { YouTubeEmbedBlockTemplate } from "../src/components/YouTubeEmbed/template"; -import { DashboardsCollection } from "../src/components/Dashboard/template"; import { MDXTemplates } from "../src/theme/template"; -import { docusaurusDate, titleFromSlug } from "../scripts/util"; +import { getEditorIdentity } from "../src/utils/editorIdentity"; // Function to extract available locales from Docusaurus config @@ -52,7 +48,7 @@ function createLanguageOptions(configData = docusaurusData) { } // Get available locales from Docusaurus config -const availableLocales = getDocusaurusLocales(); +const _availableLocales = getDocusaurusLocales(); // Create language options with descriptive labels const languageOptions = createLanguageOptions(); @@ -227,8 +223,8 @@ const PostCollection = { format: (val) => { if (!val) return new Date(); // If we already have a YYYY-MM-DD string, create a Date object for the picker - if (typeof val === 'string' && val.match(/^\d{4}-\d{2}-\d{2}$/)) { - return new Date(val + 'T12:00:00.000Z'); // Use noon to avoid timezone issues + if (typeof val === "string" && val.match(/^\d{4}-\d{2}-\d{2}$/)) { + return new Date(`${val}T12:00:00.000Z`); // Use noon to avoid timezone issues } return new Date(val); }, @@ -922,7 +918,11 @@ const AutogeneratedTemplate = { ], }; -const LeafTemplates = [DocLinkTemplate, ExternalLinkTemplate, AutogeneratedTemplate]; +const LeafTemplates = [ + DocLinkTemplate, + ExternalLinkTemplate, + AutogeneratedTemplate, +]; const CategoryTemplate = { ...CategoryTemplateProps, @@ -997,10 +997,7 @@ const CategoryTemplate = { const SidebarItemsField = { ...ItemsField, - templates: [ - CategoryTemplate, - ...LeafTemplates, - ], + templates: [CategoryTemplate, ...LeafTemplates], }; const SidebarCollection = { @@ -1470,14 +1467,23 @@ const MediaCollection = { { type: "string", name: "filename", label: "Filename", required: true }, { type: "string", name: "path", label: "Path", required: true }, { type: "number", name: "size", label: "Size (bytes)", required: true }, - { type: "string", name: "dimensions", label: "Dimensions (WxH)", required: false }, - { type: "string", name: "lastModified", label: "Last Modified", required: false }, + { + type: "string", + name: "dimensions", + label: "Dimensions (WxH)", + required: false, + }, + { + type: "string", + name: "lastModified", + label: "Last Modified", + required: false, + }, ], }, ], }; - export default defineConfig({ branch, clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID, // Get this from tina.io diff --git a/tina/tina-lock.json b/tina/tina-lock.json new file mode 100644 index 00000000..70bef00c --- /dev/null +++ b/tina/tina-lock.json @@ -0,0 +1 @@ +{"schema":{"version":{"fullVersion":"2.4.9","major":"2","minor":"4","patch":"9"},"meta":{"flags":["experimentalData"]},"collections":[{"name":"post","label":"Blog Articles","path":"blog","format":"mdx","ui":{"defaultItem":{"date":"2026-08-10"}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["post","help"],"searchable":true,"uid":false},{"label":"Last Modified","type":"string","name":"lastmod","ui":{"component":"hidden"},"namespace":["post","lastmod"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["post","title"],"searchable":true,"uid":false},{"name":"authors","label":"Authors","type":"object","list":true,"ui":{},"fields":[{"name":"name","label":"Name","type":"string","isTitle":true,"required":true,"namespace":["post","authors","name"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","namespace":["post","authors","title"],"searchable":true,"uid":false},{"name":"url","label":"URL","type":"string","namespace":["post","authors","url"],"searchable":true,"uid":false},{"name":"image_url","label":"Image URL","type":"string","namespace":["post","authors","image_url"],"searchable":true,"uid":false}],"namespace":["post","authors"],"searchable":true,"uid":false},{"name":"date","label":"Date","type":"string","required":true,"ui":{"component":"date","dateFormat":"YYYY-MM-DD"},"namespace":["post","date"],"searchable":true,"uid":false},{"label":"Tags","name":"tags","type":"string","list":true,"ui":{},"options":["apis","apis_graphql","apis_openapi","computer-languages","computer-languages_css","computer-languages_html","computer-languages_javascript","computer-languages_javascript_jsx","computer-languages_javascript_mermaid","computer-languages_javascript_react","computer-languages_latex","computer-languages_latex_katex","computer-languages_markdown","computer-languages_markdown_mdx","computer-languages_xml","computer-languages_yaml","configuration","configuration_docusaurus","configuration_docusaurus_homepage","configuration_docusaurus_sidebar","configuration_github-pages","configuration_tinacms","content","content_blog-articles","content_diagrams","content_equations","content_images","content_topics","content_wikis","development","development_ai-tools","development_apis","development_apis_graphql","development_deployment","development_getting-started","development_installation","development_local-development","development_cloud-development","elements","elements_admonitions","elements_code-blocks","elements_comments","elements_context-sensitive-help","elements_doc-card-lists","elements_figures","elements_footnotes","elements_horizontal-rules","elements_links","elements_passthroughs","elements_quotes","elements_tables","elements_tabs","formatting","formatting_bold","formatting_code-font","formatting_headings","formatting_italic","formatting_strikethrough","internationalization","internationalization_localization","internationalization_translation","metadata","metadata_conditions","metadata_descriptions","metadata_slugs","metadata_taxonomies","metadata_titles","metadata_workflows","reuse","reuse_code-files","reuse_conditional-text","reuse_glossary-terms","reuse_images","reuse_snippets","reuse_variable-sets","software","software_ai-integration","software_artificial-intelligence","software_automation","software_automation_github-actions","software_browsers","software_browsers_chrome","software_browsers_edge","software_browsers_firefox","software_browsers_safari","software_command-line-interface","software_content-management-systems","software_content-management-systems_tinacms","software_content-management-systems_media-management","software_grammar-spelling-style","software_grammar-spelling-style_languagetool","software_integrated-development-environments","software_integrated-development-environments_eclipse","software_integrated-development-environments_vscodium","software_integrations","software_mcp","software_notifications","software_notifications_email","software_notifications_slack","software_notifications_teams","software_package-managers","software_package-managers_yarn","software_plugins","software_search","software_search_algolia","software_search_lunr","software_search_search-engine-optimisation","software_static-site-generators","software_static-site-generators_docusaurus","software_source-control","software_source-control_git","software_source-control_github","software_upgrading"],"namespace":["post","tags"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["post","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["post","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["post","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["post","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["post","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["post","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["post","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["post","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["post","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["post","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["post","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["post","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["post","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["post","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["post","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["post","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["post","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["post","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["post","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["post","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["post","body","a","id"],"searchable":true,"uid":false}],"namespace":["post","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["post","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["post","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["post","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["post","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["post","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["post","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["post","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["post","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["post","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["post","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["post","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["post","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["post","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["post","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["post","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["post","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["post","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["post","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["post","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["post","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["post","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["post","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["post","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["post","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["post","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["post","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["post","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["post","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["post","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["post","body","Tabs","children","TabItem","children"]}],"namespace":["post","body","Tabs","children","TabItem"]}],"namespace":["post","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["post","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["post","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["post","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["post","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["post","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["post","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["post","body","VariableSet"]}],"namespace":["post","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["post"]},{"label":"Conditions","name":"conditions","path":"reuse/conditions","format":"json","fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["conditions","help"],"searchable":true,"uid":false},{"type":"object","label":"Categories","name":"categories","list":true,"ui":{},"fields":[{"type":"string","label":"Category Name","name":"name","isTitle":true,"required":true,"namespace":["conditions","categories","name"],"searchable":true,"uid":false},{"type":"string","label":"Description","name":"description","namespace":["conditions","categories","description"],"searchable":true,"uid":false},{"type":"object","label":"Conditions","name":"conditions","list":true,"ui":{},"fields":[{"type":"string","label":"Condition","name":"condition","isTitle":true,"required":true,"namespace":["conditions","categories","conditions","condition"],"searchable":true,"uid":false},{"type":"string","label":"Description","name":"description","namespace":["conditions","categories","conditions","description"],"searchable":true,"uid":false},{"type":"boolean","label":"Active","name":"active","description":"Whether this condition is currently active/available","namespace":["conditions","categories","conditions","active"],"searchable":true,"uid":false}],"namespace":["conditions","categories","conditions"],"searchable":true,"uid":false}],"namespace":["conditions","categories"],"searchable":true,"uid":false}],"ui":{"allowedActions":{"create":false,"delete":false}},"namespace":["conditions"]},{"name":"dashboards","label":"Dashboards","path":"static/dashboards","format":"json","ui":{"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"boolean","name":"statusBar","label":"","required":false,"ui":{},"namespace":["dashboards","statusBar"],"searchable":true,"uid":false},{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["dashboards","help"],"searchable":true,"uid":false},{"type":"boolean","name":"dashboard1","label":"Content Overview","required":false,"ui":{},"namespace":["dashboards","dashboard1"],"searchable":true,"uid":false},{"type":"boolean","name":"contentReuseDashboard","label":"Content Reuse Overview","required":false,"ui":{},"namespace":["dashboards","contentReuseDashboard"],"searchable":true,"uid":false},{"type":"boolean","name":"mediaDashboard","label":"Media Library","required":false,"ui":{},"namespace":["dashboards","mediaDashboard"],"searchable":true,"uid":false},{"type":"boolean","name":"translationDashboard","label":"Translation Status","required":false,"ui":{},"namespace":["dashboards","translationDashboard"],"searchable":true,"uid":false},{"type":"boolean","name":"brokenLinksDashboard","label":"Broken Links","required":false,"ui":{},"namespace":["dashboards","brokenLinksDashboard"],"searchable":true,"uid":false}],"namespace":["dashboards"]},{"label":"Glossary Terms","name":"glossaryTerms","path":"reuse/glossaryTerms","format":"json","fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["glossaryTerms","help"],"searchable":true,"uid":false},{"type":"object","name":"glossaryTerms","label":"Glossary Terms","list":true,"templates":[{"name":"glossaryTerm","label":"Glossary Term","ui":{},"fields":[{"type":"string","name":"key","label":"Key","isTitle":true,"required":true,"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","key"],"searchable":true,"uid":false},{"type":"object","name":"translations","label":"Translations","list":true,"templates":[{"name":"translation","label":"Translation","ui":{},"fields":[{"type":"string","name":"lang","label":"Language Code","required":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","translations","translation","lang"]},{"type":"string","name":"term","label":"Term","required":true,"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","translations","translation","term"]},{"type":"string","name":"definition","label":"Definition","required":true,"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","translations","translation","definition"]}],"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","translations","translation"]}],"namespace":["glossaryTerms","glossaryTerms","glossaryTerm","translations"],"searchable":true,"uid":false}],"namespace":["glossaryTerms","glossaryTerms","glossaryTerm"]}],"namespace":["glossaryTerms","glossaryTerms"],"searchable":true,"uid":false}],"ui":{"allowedActions":{"create":false,"delete":false}},"namespace":["glossaryTerms"]},{"name":"homepage","label":"Home Page","description":"To see settings changes reflected on your site, you must restart the Tina CLI after saving changes (local development only).","path":"config/homepage","format":"json","ui":{"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["homepage","help"],"searchable":true,"uid":false},{"type":"string","name":"_warning","ui":{},"namespace":["homepage","_warning"],"searchable":true,"uid":false},{"type":"string","label":"Label","name":"label","required":true,"isTitle":true,"ui":{"component":"hidden"},"namespace":["homepage","label"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","namespace":["homepage","title"],"searchable":true,"uid":false},{"type":"string","name":"description","label":"Description","namespace":["homepage","description"],"searchable":true,"uid":false},{"type":"object","list":true,"name":"blocks","label":"Blocks","templates":[{"name":"hero","label":"Hero","fields":[{"name":"title","label":"Title","description":"By default this is the site title","type":"string","namespace":["homepage","blocks","hero","title"],"searchable":true,"uid":false},{"name":"subtitle","label":"Subtitle","description":"By default this is the site tagline","type":"string","namespace":["homepage","blocks","hero","subtitle"],"searchable":true,"uid":false},{"name":"description","label":"Description","description":"Additional text displayed below the subtitle","type":"string","namespace":["homepage","blocks","hero","description"],"searchable":true,"uid":false},{"label":"Document Link","name":"document","type":"reference","collections":["doc"],"namespace":["homepage","blocks","hero","document"],"searchable":true,"uid":false},{"name":"documentLabel","label":"Primary Button Text","type":"string","namespace":["homepage","blocks","hero","documentLabel"],"searchable":true,"uid":false},{"name":"secondaryButtonText","label":"Secondary Button Text","type":"string","namespace":["homepage","blocks","hero","secondaryButtonText"],"searchable":true,"uid":false},{"name":"secondaryButtonLink","label":"Secondary Button Link","type":"string","namespace":["homepage","blocks","hero","secondaryButtonLink"],"searchable":true,"uid":false},{"name":"showHeroCard","label":"Show Hero Card","description":"Display the visual hero card with features","type":"boolean","namespace":["homepage","blocks","hero","showHeroCard"],"searchable":true,"uid":false},{"name":"heroCardTitle","label":"Hero Card Title","type":"string","namespace":["homepage","blocks","hero","heroCardTitle"],"searchable":true,"uid":false},{"name":"heroCardFeatures","label":"Hero Card Features","type":"object","list":true,"fields":[{"name":"feature","label":"Feature","type":"string","namespace":["homepage","blocks","hero","heroCardFeatures","feature"]}],"namespace":["homepage","blocks","hero","heroCardFeatures"],"searchable":true,"uid":false}],"namespace":["homepage","blocks","hero"]},{"name":"features","label":"Features","fields":[{"name":"items","label":"Features","type":"object","list":true,"ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["homepage","blocks","features","items","title"]},{"name":"description","label":"Description","type":"rich-text","namespace":["homepage","blocks","features","items","description"]},{"name":"image","label":"Image","type":"image","namespace":["homepage","blocks","features","items","image"]}],"namespace":["homepage","blocks","features","items"],"searchable":true,"uid":false}],"namespace":["homepage","blocks","features"]},{"name":"youTubeEmbed","label":"YouTube Embed","fields":[{"name":"title","label":"Title","type":"string","namespace":["homepage","blocks","youTubeEmbed","title"],"searchable":true,"uid":false},{"name":"url","label":"YouTube URL","type":"string","namespace":["homepage","blocks","youTubeEmbed","url"],"searchable":true,"uid":false},{"name":"caption","label":"Caption","type":"string","namespace":["homepage","blocks","youTubeEmbed","caption"],"searchable":true,"uid":false}],"namespace":["homepage","blocks","youTubeEmbed"]}],"namespace":["homepage","blocks"],"searchable":true,"uid":false}],"namespace":["homepage"]},{"name":"pages","label":"Pages","path":"src/pages","format":"mdx","fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["pages","help"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["pages","title"],"searchable":true,"uid":false},{"type":"string","name":"description","label":"Description","namespace":["pages","description"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["pages","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["pages","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["pages","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["pages","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["pages","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["pages","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["pages","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["pages","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["pages","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["pages","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["pages","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["pages","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["pages","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["pages","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["pages","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["pages","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["pages","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["pages","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["pages","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["pages","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["pages","body","a","id"],"searchable":true,"uid":false}],"namespace":["pages","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["pages","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["pages","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["pages","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["pages","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["pages","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["pages","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["pages","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["pages","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["pages","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["pages","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["pages","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["pages","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["pages","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["pages","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["pages","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["pages","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["pages","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["pages","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["pages","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["pages","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["pages","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["pages","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["pages","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["pages","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["pages","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["pages","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["pages","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["pages","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["pages","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["pages","body","Tabs","children","TabItem","children"]}],"namespace":["pages","body","Tabs","children","TabItem"]}],"namespace":["pages","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["pages","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["pages","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["pages","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["pages","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["pages","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["pages","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["pages","body","VariableSet"]}],"namespace":["pages","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"ui":{"allowedActions":{"create":true,"delete":true}},"namespace":["pages"]},{"label":"Settings","name":"settings","path":"config/docusaurus","format":"json","ui":{"global":true,"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["settings","help"],"searchable":true,"uid":false},{"type":"string","name":"_warning","ui":{},"namespace":["settings","_warning"],"searchable":true,"uid":false},{"type":"string","label":"Label","name":"label","required":true,"isTitle":true,"ui":{"component":"hidden"},"namespace":["settings","label"],"searchable":true,"uid":false},{"type":"string","label":"Title","name":"title","required":true,"ui":{},"namespace":["settings","title"],"searchable":true,"uid":false},{"type":"string","label":"Tagline","name":"tagline","ui":{},"namespace":["settings","tagline"],"searchable":true,"uid":false},{"type":"image","label":"Favicon","name":"favicon","ui":{},"namespace":["settings","favicon"],"searchable":false,"uid":false},{"type":"string","label":"GraphQL Schema URL","name":"graphql","ui":{},"namespace":["settings","graphql"],"searchable":true,"uid":false},{"type":"object","label":"Color Mode","name":"colorMode","fields":[{"type":"string","label":"Default Mode","name":"defaultMode","description":"The color mode that is applied by default","options":[{"label":"Light","value":"light"},{"label":"Dark","value":"dark"},{"label":"System","value":"system"}],"ui":{"component":"button-toggle"},"namespace":["settings","colorMode","defaultMode"],"searchable":true,"uid":false},{"type":"boolean","label":"Hide Switch","name":"disableSwitch","description":"Hide the switch in the navbar","namespace":["settings","colorMode","disableSwitch"],"searchable":true,"uid":false},{"type":"boolean","label":"Respect Prefers Color Scheme","name":"respectPrefersColorScheme","description":"Use prefers-color-scheme CSS media feature","namespace":["settings","colorMode","respectPrefersColorScheme"],"searchable":true,"uid":false}],"namespace":["settings","colorMode"],"searchable":true,"uid":false},{"type":"object","label":"Footer","name":"footer","fields":[{"name":"style","label":"Style","type":"string","options":[{"label":"Dark","value":"dark"},{"label":"Light","value":"light"}],"ui":{"component":"button-toggle"},"namespace":["settings","footer","style"],"searchable":true,"uid":false},{"type":"object","label":"Categories","name":"links","list":true,"ui":{},"fields":[{"type":"string","label":"Title","name":"title","namespace":["settings","footer","links","title"],"searchable":true,"uid":false},{"type":"object","label":"Links","name":"items","list":true,"templates":[{"name":"internal","label":"Internal","ui":{},"fields":[{"type":"string","label":"Label","name":"label","namespace":["settings","footer","links","items","internal","label"],"searchable":true,"uid":false},{"type":"reference","label":"Page","name":"to","collections":["doc","pages","post"],"namespace":["settings","footer","links","items","internal","to"],"searchable":true,"uid":false}],"namespace":["settings","footer","links","items","internal"]},{"name":"blog","label":"Blog","ui":{"defaultItem":{"label":"Blog"}},"fields":[{"type":"string","label":"Label","name":"label","namespace":["settings","footer","links","items","blog","label"],"searchable":true,"uid":false}],"namespace":["settings","footer","links","items","blog"]},{"name":"external","label":"External","ui":{},"fields":[{"type":"string","label":"Label","name":"label","namespace":["settings","footer","links","items","external","label"],"searchable":true,"uid":false},{"type":"string","label":"URL","name":"href","namespace":["settings","footer","links","items","external","href"],"searchable":true,"uid":false}],"namespace":["settings","footer","links","items","external"]}],"namespace":["settings","footer","links","items"],"searchable":true,"uid":false}],"namespace":["settings","footer","links"],"searchable":true,"uid":false},{"type":"string","label":"Copyright","name":"copyright","namespace":["settings","footer","copyright"],"searchable":true,"uid":false}],"namespace":["settings","footer"],"searchable":true,"uid":false},{"type":"object","label":"GitHub Deployment","name":"github","fields":[{"type":"string","label":"Project Name","name":"projectName","description":"GitHub repository name for GitHub Pages deployment","namespace":["settings","github","projectName"],"searchable":true,"uid":false},{"type":"string","label":"Organization Name","name":"organizationName","description":"GitHub username or organization name","namespace":["settings","github","organizationName"],"searchable":true,"uid":false}],"namespace":["settings","github"],"searchable":true,"uid":false},{"type":"object","label":"Languages","name":"languages","fields":[{"type":"object","label":"Supported Languages","name":"supported","list":true,"ui":{},"fields":[{"type":"string","label":"Language Code","name":"code","required":true,"namespace":["settings","languages","supported","code"],"searchable":true,"uid":false},{"type":"string","label":"Display Label","name":"label","required":true,"namespace":["settings","languages","supported","label"],"searchable":true,"uid":false}],"namespace":["settings","languages","supported"],"searchable":true,"uid":false},{"type":"string","label":"Default Language","name":"default","required":true,"ui":{},"namespace":["settings","languages","default"],"searchable":true,"uid":false}],"namespace":["settings","languages"],"searchable":true,"uid":false},{"type":"object","label":"Logo","name":"logo","fields":[{"type":"string","label":"Alt Text","name":"alt","namespace":["settings","logo","alt"],"searchable":true,"uid":false},{"type":"image","label":"Source","name":"src","namespace":["settings","logo","src"],"searchable":false,"uid":false}],"namespace":["settings","logo"],"searchable":true,"uid":false},{"type":"object","label":"OpenAPI","name":"openapi","fields":[{"type":"object","label":"APIs","name":"apis","list":true,"ui":{"defaultItem":{"groupPathsBy":"tag","categoryLinkSource":"tag"}},"fields":[{"type":"string","label":"API Name","name":"name","required":true,"description":"Unique name for this API (e.g., petstore, userapi, etc.)","namespace":["settings","openapi","apis","name"],"searchable":true,"uid":false},{"type":"string","label":"Spec Path","name":"specPath","required":true,"description":"Path to the OpenAPI specification file (e.g., apis/petstore.yaml)","namespace":["settings","openapi","apis","specPath"],"searchable":true,"uid":false},{"type":"string","label":"Output Directory","name":"outputDir","required":true,"description":"Directory where generated API docs will be placed (e.g., docs/api/petstore)","namespace":["settings","openapi","apis","outputDir"],"searchable":true,"uid":false},{"type":"string","label":"Download URL","name":"downloadUrl","description":"Optional URL to download the OpenAPI spec file","namespace":["settings","openapi","apis","downloadUrl"],"searchable":true,"uid":false},{"type":"string","label":"Group Paths By","name":"groupPathsBy","description":"How to group API endpoints in sidebar","options":[{"label":"Tag","value":"tag"},{"label":"Operation","value":"operation"}],"ui":{"component":"select"},"namespace":["settings","openapi","apis","groupPathsBy"],"searchable":true,"uid":false},{"type":"string","label":"Category Link Source","name":"categoryLinkSource","description":"Source for category links","options":[{"label":"Tag","value":"tag"},{"label":"Info","value":"info"}],"ui":{"component":"select"},"namespace":["settings","openapi","apis","categoryLinkSource"],"searchable":true,"uid":false}],"namespace":["settings","openapi","apis"],"searchable":true,"uid":false},{"type":"string","label":"Language Tabs","name":"languageTabs","list":true,"description":"Select which programming languages to show as tabs in OpenAPI code examples across all APIs","options":[{"label":"C","value":"c"},{"label":"C#","value":"csharp"},{"label":"cURL/Bash","value":"curl"},{"label":"Dart","value":"dart"},{"label":"Go","value":"go"},{"label":"Java","value":"java"},{"label":"JavaScript","value":"javascript"},{"label":"Kotlin","value":"kotlin"},{"label":"Node.js","value":"nodejs"},{"label":"Objective-C","value":"objective-c"},{"label":"OCaml","value":"ocaml"},{"label":"PHP","value":"php"},{"label":"PowerShell","value":"powershell"},{"label":"Python","value":"python"},{"label":"R","value":"r"},{"label":"Ruby","value":"ruby"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"TypeScript","value":"typescript"}],"namespace":["settings","openapi","languageTabs"],"searchable":true,"uid":false}],"namespace":["settings","openapi"],"searchable":true,"uid":false},{"type":"object","label":"Syntax Highlighting","name":"prism","fields":[{"type":"string","label":"Additional Languages","name":"additionalLanguages","list":true,"description":"Programming languages supported for syntax highlighting","namespace":["settings","prism","additionalLanguages"],"searchable":true,"uid":false},{"type":"object","label":"Magic Comments","name":"magicComments","list":true,"description":"Comments that trigger special highlighting behaviors","ui":{},"fields":[{"type":"string","label":"CSS Class Name","name":"className","required":true,"namespace":["settings","prism","magicComments","className"],"searchable":true,"uid":false},{"type":"string","label":"Line Comment","name":"line","description":"Comment text that triggers highlighting on the next line","namespace":["settings","prism","magicComments","line"],"searchable":true,"uid":false},{"type":"object","label":"Block Comment","name":"block","description":"Comments that define a block of highlighted lines","fields":[{"type":"string","label":"Start Comment","name":"start","namespace":["settings","prism","magicComments","block","start"],"searchable":true,"uid":false},{"type":"string","label":"End Comment","name":"end","namespace":["settings","prism","magicComments","block","end"],"searchable":true,"uid":false}],"namespace":["settings","prism","magicComments","block"],"searchable":true,"uid":false}],"namespace":["settings","prism","magicComments"],"searchable":true,"uid":false},{"type":"string","label":"Light Theme","name":"theme","description":"Syntax highlighting theme for light mode","options":[{"label":"docStatic Light","value":"prismLight"},{"label":"Duotone Light","value":"duotoneLight"},{"label":"GitHub","value":"github"},{"label":"Gruvbox Material Light","value":"gruvboxMaterialLight"},{"label":"Jettwave Light","value":"jettwaveLight"},{"label":"Night Owl Light","value":"nightOwlLight"},{"label":"One Light","value":"oneLight"},{"label":"Ultramin","value":"ultramin"},{"label":"VS Code Light","value":"vsLight"}],"ui":{"component":"select"},"namespace":["settings","prism","theme"],"searchable":true,"uid":false},{"type":"string","label":"Dark Theme","name":"darkTheme","description":"Syntax highlighting theme for dark mode","options":[{"label":"docStatic Dark","value":"prismDark"},{"label":"Dracula","value":"dracula"},{"label":"Duotone Dark","value":"duotoneDark"},{"label":"Gruvbox Material Dark","value":"gruvboxMaterialDark"},{"label":"Jettwave Dark","value":"jettwaveDark"},{"label":"Night Owl","value":"nightOwl"},{"label":"Oceanic Next","value":"oceanicNext"},{"label":"Okaidia","value":"okaidia"},{"label":"One Dark","value":"oneDark"},{"label":"Palenight","value":"palenight"},{"label":"Shades of Purple","value":"shadesOfPurple"},{"label":"Synthwave 84","value":"synthwave84"},{"label":"VS Dark","value":"vsDark"}],"ui":{"component":"select"},"namespace":["settings","prism","darkTheme"],"searchable":true,"uid":false}],"namespace":["settings","prism"],"searchable":true,"uid":false},{"type":"object","label":"URL","name":"url","fields":[{"type":"string","label":"Site URL","name":"siteUrl","required":true,"description":"The URL where your site will be hosted","namespace":["settings","url","siteUrl"],"searchable":true,"uid":false},{"type":"string","label":"Base URL","name":"baseUrl","description":"Base URL for your site (e.g., /my-project/). Leave empty for root domain.","namespace":["settings","url","baseUrl"],"searchable":true,"uid":false},{"type":"boolean","label":"Trailing Slash","name":"trailingSlash","description":"Whether to add trailing slashes to URLs","namespace":["settings","url","trailingSlash"],"searchable":true,"uid":false}],"namespace":["settings","url"],"searchable":true,"uid":false},{"type":"object","label":"Navbar","name":"navbar","list":true,"ui":{"defaultItem":{"position":"left"}},"fields":[{"name":"label","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["settings","navbar","label"],"searchable":true,"uid":false},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Page","value":"page"},{"label":"Blog","value":"blog"},{"label":"External","value":"external"},{"label":"Manual Path","value":"manualPath"},{"label":"Locale Dropdown","value":"localeDropdown"},{"label":"Docs Version Dropdown","value":"docsVersionDropdown"},{"label":"Dropdown","value":"dropdown"},{"label":"Search","value":"search"}],"namespace":["settings","navbar","link"],"searchable":true,"uid":false},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["settings","navbar","docLink"],"searchable":true,"uid":false},{"name":"pageLink","label":"Page","type":"reference","collections":["pages"],"ui":{},"namespace":["settings","navbar","pageLink"],"searchable":true,"uid":false},{"name":"externalLink","label":"URL","type":"string","ui":{},"namespace":["settings","navbar","externalLink"],"searchable":true,"uid":false},{"name":"manualPath","label":"Manual Path","type":"string","ui":{},"namespace":["settings","navbar","manualPath"],"searchable":true,"uid":false},{"name":"docId","label":"Document ID","type":"string","ui":{},"namespace":["settings","navbar","docId"],"searchable":true,"uid":false},{"name":"position","label":"Position","type":"string","required":true,"options":[{"label":"Left","value":"left"},{"label":"Right","value":"right"}],"ui":{"component":"button-toggle"},"namespace":["settings","navbar","position"],"searchable":true,"uid":false},{"name":"items","label":"Items","type":"object","list":true,"ui":{},"fields":[{"name":"label","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["settings","navbar","items","label"],"searchable":true,"uid":false},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Page","value":"page"},{"label":"Blog","value":"blog"},{"label":"External","value":"external"},{"label":"Manual Path","value":"manualPath"},{"label":"Locale Dropdown","value":"localeDropdown"},{"label":"Docs Version Dropdown","value":"docsVersionDropdown"},{"label":"Dropdown","value":"dropdown"},{"label":"Search","value":"search"}],"namespace":["settings","navbar","items","link"],"searchable":true,"uid":false},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["settings","navbar","items","docLink"],"searchable":true,"uid":false},{"name":"pageLink","label":"Page","type":"reference","collections":["pages"],"ui":{},"namespace":["settings","navbar","items","pageLink"],"searchable":true,"uid":false},{"name":"externalLink","label":"URL","type":"string","ui":{},"namespace":["settings","navbar","items","externalLink"],"searchable":true,"uid":false},{"name":"manualPath","label":"Manual Path","type":"string","ui":{},"namespace":["settings","navbar","items","manualPath"],"searchable":true,"uid":false},{"name":"docId","label":"Document ID","type":"string","ui":{},"namespace":["settings","navbar","items","docId"],"searchable":true,"uid":false},{"name":"position","label":"Position","type":"string","required":true,"options":[{"label":"Left","value":"left"},{"label":"Right","value":"right"}],"ui":{"component":"button-toggle"},"namespace":["settings","navbar","items","position"],"searchable":true,"uid":false},{"name":"items","label":"Items","type":"object","list":true,"ui":{},"fields":[{"name":"label","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["settings","navbar","items","items","label"],"searchable":true,"uid":false},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Page","value":"page"},{"label":"Blog","value":"blog"},{"label":"External","value":"external"},{"label":"Manual Path","value":"manualPath"},{"label":"Locale Dropdown","value":"localeDropdown"},{"label":"Docs Version Dropdown","value":"docsVersionDropdown"},{"label":"Dropdown","value":"dropdown"},{"label":"Search","value":"search"}],"namespace":["settings","navbar","items","items","link"],"searchable":true,"uid":false},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["settings","navbar","items","items","docLink"],"searchable":true,"uid":false},{"name":"pageLink","label":"Page","type":"reference","collections":["pages"],"ui":{},"namespace":["settings","navbar","items","items","pageLink"],"searchable":true,"uid":false},{"name":"externalLink","label":"URL","type":"string","ui":{},"namespace":["settings","navbar","items","items","externalLink"],"searchable":true,"uid":false},{"name":"manualPath","label":"Manual Path","type":"string","ui":{},"namespace":["settings","navbar","items","items","manualPath"],"searchable":true,"uid":false},{"name":"docId","label":"Document ID","type":"string","ui":{},"namespace":["settings","navbar","items","items","docId"],"searchable":true,"uid":false},{"name":"position","label":"Position","type":"string","required":true,"options":[{"label":"Left","value":"left"},{"label":"Right","value":"right"}],"ui":{"component":"button-toggle"},"namespace":["settings","navbar","items","items","position"],"searchable":true,"uid":false}],"namespace":["settings","navbar","items","items"],"searchable":true,"uid":false}],"namespace":["settings","navbar","items"],"searchable":true,"uid":false}],"namespace":["settings","navbar"],"searchable":true,"uid":false},{"type":"boolean","label":"Sidebar can be hidden","name":"sidebarHideable","namespace":["settings","sidebarHideable"],"searchable":true,"uid":false},{"type":"boolean","label":"Show blog reading time","name":"showReadingTime","namespace":["settings","showReadingTime"],"searchable":true,"uid":false}],"namespace":["settings"]},{"name":"snippets","label":"Snippets","path":"reuse/snippets","format":"mdx","ui":{"defaultItem":{"lastmod":"2026-08-10T22:16:43.706Z"}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["snippets","help"],"searchable":true,"uid":false},{"label":"Last Modified","type":"string","name":"lastmod","ui":{"component":"hidden"},"namespace":["snippets","lastmod"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["snippets","title"],"searchable":true,"uid":false},{"type":"string","name":"description","label":"Description","namespace":["snippets","description"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["snippets","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["snippets","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["snippets","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["snippets","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["snippets","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["snippets","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["snippets","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["snippets","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["snippets","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["snippets","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["snippets","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["snippets","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["snippets","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["snippets","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["snippets","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["snippets","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["snippets","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["snippets","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","a","id"],"searchable":true,"uid":false}],"namespace":["snippets","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["snippets","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["snippets","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["snippets","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["snippets","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["snippets","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["snippets","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["snippets","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["snippets","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["snippets","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["snippets","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["snippets","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["snippets","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["snippets","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["snippets","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["snippets","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["snippets","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["snippets","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["snippets","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["snippets","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["snippets","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["snippets","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["snippets","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["snippets","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["snippets","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["snippets","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["snippets","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["snippets","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["snippets","body","Tabs","children","TabItem","children"]}],"namespace":["snippets","body","Tabs","children","TabItem"]}],"namespace":["snippets","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["snippets","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["snippets","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["snippets","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["snippets","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["snippets","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["snippets","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["snippets","body","VariableSet"]}],"namespace":["snippets","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["snippets"]},{"name":"sidebar","label":"Table of Contents","path":"config/sidebar","format":"json","ui":{"global":true,"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["sidebar","help"],"searchable":true,"uid":false},{"type":"string","name":"_warning","ui":{},"namespace":["sidebar","_warning"],"searchable":true,"uid":false},{"type":"string","label":"Label","name":"label","required":true,"isTitle":true,"ui":{"component":"hidden"},"namespace":["sidebar","label"],"searchable":true,"uid":false},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","title"],"searchable":true,"uid":false},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","link"],"searchable":true,"uid":false},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","docLink"],"searchable":true,"uid":false},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","title"]},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","items","category","link"]},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","items","category","docLink"]},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","title"]},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","items","category","items","category","link"]},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","items","category","items","category","docLink"]},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","title"]},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","items","category","items","category","items","category","link"]},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","items","category","items","category","items","category","docLink"]},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","title"]},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","link"]},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","docLink"]},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"category","label":"Category","ui":{"defaultItem":{"link":"none"}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","title"]},{"name":"link","label":"Link","type":"string","options":[{"label":"None","value":"none"},{"label":"Document","value":"doc"},{"label":"Generated Index","value":"generated"}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","link"]},{"name":"docLink","label":"Document","type":"reference","collections":["doc"],"ui":{},"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","docLink"]},{"name":"items","label":"Items","type":"object","list":true,"templates":[{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category","items"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category","items"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","category","items","category","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category","items"]}],"namespace":["sidebar","items","category","items","category","items","category","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","category","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","category","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","category","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","category","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items","category","items","category","items"]}],"namespace":["sidebar","items","category","items","category","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items","category","items"]}],"namespace":["sidebar","items","category","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","category","items","doc","document"]},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","category","items","doc","label"]}],"namespace":["sidebar","items","category","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","link","title"]},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","category","items","link","href"]}],"namespace":["sidebar","items","category","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","category","items","autogenerated","title"]},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","category","items","autogenerated","dirName"]}],"namespace":["sidebar","items","category","items","autogenerated"]}],"namespace":["sidebar","items","category","items"],"searchable":true,"uid":false}],"namespace":["sidebar","items","category"]},{"name":"doc","label":"Doc Link","ui":{},"fields":[{"label":"Document","name":"document","type":"reference","collections":["doc"],"isTitle":true,"required":true,"namespace":["sidebar","items","doc","document"],"searchable":true,"uid":false},{"name":"label","label":"Label","description":"By default this is the document title","type":"string","namespace":["sidebar","items","doc","label"],"searchable":true,"uid":false}],"namespace":["sidebar","items","doc"]},{"name":"link","label":"External Link","ui":{},"fields":[{"name":"title","label":"Label","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","link","title"],"searchable":true,"uid":false},{"name":"href","label":"URL","type":"string","required":true,"namespace":["sidebar","items","link","href"],"searchable":true,"uid":false}],"namespace":["sidebar","items","link"]},{"name":"autogenerated","label":"Auto-populated from Folder","ui":{"defaultItem":{"title":"New Auto-populated Section","dirName":""}},"fields":[{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["sidebar","items","autogenerated","title"],"searchable":true,"uid":false},{"name":"dirName","label":"Folder Name","description":"The folder path inside docs/ to auto-populate from (for example 'teams' or 'architecture/diagrams')","type":"string","required":true,"namespace":["sidebar","items","autogenerated","dirName"],"searchable":true,"uid":false}],"namespace":["sidebar","items","autogenerated"]}],"namespace":["sidebar","items"],"searchable":true,"uid":false}],"namespace":["sidebar"]},{"name":"taxonomy","label":"Taxonomies","path":"reuse/taxonomy","format":"json","fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["taxonomy","help"],"searchable":true,"uid":false},{"type":"object","list":true,"name":"taxonomy","label":"Taxonomy","ui":{},"fields":[{"type":"string","name":"tag","label":"Tag","isTitle":true,"required":true,"namespace":["taxonomy","taxonomy","tag"],"searchable":true,"uid":false},{"type":"object","list":true,"name":"children","label":"Children","ui":{},"fields":[{"type":"string","name":"tag","label":"Tag","isTitle":true,"required":true,"namespace":["taxonomy","taxonomy","children","tag"],"searchable":true,"uid":false},{"type":"object","list":true,"name":"children","label":"Children","ui":{},"fields":[{"type":"string","name":"tag","label":"Tag","isTitle":true,"required":true,"namespace":["taxonomy","taxonomy","children","children","tag"],"searchable":true,"uid":false}],"namespace":["taxonomy","taxonomy","children","children"],"searchable":true,"uid":false}],"namespace":["taxonomy","taxonomy","children"],"searchable":true,"uid":false}],"namespace":["taxonomy","taxonomy"],"searchable":true,"uid":false}],"ui":{"allowedActions":{"create":false,"delete":false}},"namespace":["taxonomy"]},{"name":"theme","label":"Theme","path":"config/theme","format":"json","ui":{"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"string","name":"_warning","ui":{},"namespace":["theme","_warning"],"searchable":true,"uid":false},{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["theme","help"],"searchable":true,"uid":false},{"type":"object","name":"colors","label":"Light Mode","fields":[{"type":"string","name":"primary","label":"Primary","ui":{"component":"color"},"namespace":["theme","colors","primary"],"searchable":true,"uid":false},{"type":"string","name":"primaryDark","label":"Primary Dark","ui":{"component":"color"},"namespace":["theme","colors","primaryDark"],"searchable":true,"uid":false},{"type":"string","name":"primaryDarker","label":"Primary Darker","ui":{"component":"color"},"namespace":["theme","colors","primaryDarker"],"searchable":true,"uid":false},{"type":"string","name":"primaryDarkest","label":"Primary Darkest","ui":{"component":"color"},"namespace":["theme","colors","primaryDarkest"],"searchable":true,"uid":false},{"type":"string","name":"primaryLight","label":"Primary Light","ui":{"component":"color"},"namespace":["theme","colors","primaryLight"],"searchable":true,"uid":false},{"type":"string","name":"primaryLighter","label":"Primary Lighter","ui":{"component":"color"},"namespace":["theme","colors","primaryLighter"],"searchable":true,"uid":false},{"type":"string","name":"primaryLightest","label":"Primary Lightest","ui":{"component":"color"},"namespace":["theme","colors","primaryLightest"],"searchable":true,"uid":false},{"type":"string","name":"footerBackground","label":"Footer Background","ui":{"component":"color"},"namespace":["theme","colors","footerBackground"],"searchable":true,"uid":false},{"type":"string","name":"highlightedCodeLineBackground","label":"Highlighted Code Line Background","description":"Background color for highlighted lines in code blocks","ui":{"component":"color"},"namespace":["theme","colors","highlightedCodeLineBackground"],"searchable":true,"uid":false}],"namespace":["theme","colors"],"searchable":true,"uid":false},{"type":"object","name":"darkColors","label":"Dark Mode","fields":[{"type":"string","name":"primary","label":"Primary","ui":{"component":"color"},"namespace":["theme","darkColors","primary"],"searchable":true,"uid":false},{"type":"string","name":"primaryDark","label":"Primary Dark","ui":{"component":"color"},"namespace":["theme","darkColors","primaryDark"],"searchable":true,"uid":false},{"type":"string","name":"primaryDarker","label":"Primary Darker","ui":{"component":"color"},"namespace":["theme","darkColors","primaryDarker"],"searchable":true,"uid":false},{"type":"string","name":"primaryDarkest","label":"Primary Darkest","ui":{"component":"color"},"namespace":["theme","darkColors","primaryDarkest"],"searchable":true,"uid":false},{"type":"string","name":"primaryLight","label":"Primary Light","ui":{"component":"color"},"namespace":["theme","darkColors","primaryLight"],"searchable":true,"uid":false},{"type":"string","name":"primaryLighter","label":"Primary Lighter","ui":{"component":"color"},"namespace":["theme","darkColors","primaryLighter"],"searchable":true,"uid":false},{"type":"string","name":"primaryLightest","label":"Primary Lightest","ui":{"component":"color"},"namespace":["theme","darkColors","primaryLightest"],"searchable":true,"uid":false},{"type":"string","name":"footerBackground","label":"Footer Background","ui":{"component":"color"},"namespace":["theme","darkColors","footerBackground"],"searchable":true,"uid":false},{"type":"string","name":"highlightedCodeLineBackground","label":"Highlighted Code Line Background","description":"Background color for highlighted lines in code blocks","ui":{"component":"color"},"namespace":["theme","darkColors","highlightedCodeLineBackground"],"searchable":true,"uid":false}],"namespace":["theme","darkColors"],"searchable":true,"uid":false},{"type":"object","name":"typography","label":"Typography","fields":[{"type":"string","name":"baseFontFamily","label":"Base Font Family","description":"CSS font-family value (example: '\"Inter\", \"Arial\", sans-serif')","namespace":["theme","typography","baseFontFamily"],"searchable":true,"uid":false},{"type":"string","name":"monospaceFontFamily","label":"Monospace Font Family","description":"CSS font-family value for code blocks (example: '\"Fira Code\", monospace')","namespace":["theme","typography","monospaceFontFamily"],"searchable":true,"uid":false},{"type":"string","name":"codeFontSize","label":"Code Font Size","ui":{"component":"select"},"options":[{"value":"90%","label":"Small (90%)"},{"value":"95%","label":"Default (95%)"},{"value":"100%","label":"Medium (100%)"},{"value":"110%","label":"Large (110%)"}],"namespace":["theme","typography","codeFontSize"],"searchable":true,"uid":false}],"namespace":["theme","typography"],"searchable":true,"uid":false},{"type":"object","name":"layout","label":"Layout","fields":[{"type":"number","name":"globalRadius","label":"Global Border Radius (px)","ui":{},"namespace":["theme","layout","globalRadius"],"searchable":true,"uid":false},{"type":"number","name":"buttonRadius","label":"Button Border Radius (px)","ui":{},"namespace":["theme","layout","buttonRadius"],"searchable":true,"uid":false},{"type":"number","name":"cardRadius","label":"Card Border Radius (px)","ui":{},"namespace":["theme","layout","cardRadius"],"searchable":true,"uid":false},{"type":"string","name":"navbarHeight","label":"Navbar Height","ui":{"component":"select"},"options":[{"value":"3rem","label":"Small (3rem)"},{"value":"3.5rem","label":"Medium (3.5rem)"},{"value":"4rem","label":"Default (4rem)"},{"value":"4.5rem","label":"Large (4.5rem)"}],"namespace":["theme","layout","navbarHeight"],"searchable":true,"uid":false}],"namespace":["theme","layout"],"searchable":true,"uid":false},{"type":"string","name":"customCSS","label":"Custom CSS","ui":{"component":"textarea"},"description":"Add custom CSS rules that will be injected into the site","namespace":["theme","customCSS"],"searchable":true,"uid":false}],"namespace":["theme"]},{"name":"doc","label":"Topics","path":"docs","match":{"exclude":"{api/**/**,wiki/**/**}"},"format":"mdx","ui":{"defaultItem":{"draft":true,"review":false,"translate":false,"approved":false,"published":false,"unlisted":false}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["doc","help"],"searchable":true,"uid":false},{"label":"Last Modified","type":"string","name":"lastmod","ui":{"component":"hidden"},"namespace":["doc","lastmod"],"searchable":true,"uid":false},{"label":"Modified By","type":"string","name":"modifiedBy","ui":{"component":"hidden"},"namespace":["doc","modifiedBy"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["doc","title"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["doc","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["doc","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["doc","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["doc","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["doc","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["doc","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["doc","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["doc","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["doc","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["doc","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["doc","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["doc","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["doc","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["doc","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["doc","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["doc","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["doc","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["doc","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["doc","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["doc","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["doc","body","a","id"],"searchable":true,"uid":false}],"namespace":["doc","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["doc","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["doc","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["doc","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["doc","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["doc","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["doc","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["doc","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["doc","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["doc","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["doc","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["doc","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["doc","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["doc","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["doc","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["doc","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["doc","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["doc","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["doc","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["doc","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["doc","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["doc","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["doc","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["doc","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["doc","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["doc","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["doc","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["doc","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["doc","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["doc","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["doc","body","Tabs","children","TabItem","children"]}],"namespace":["doc","body","Tabs","children","TabItem"]}],"namespace":["doc","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["doc","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["doc","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["doc","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["doc","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["doc","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["doc","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["doc","body","VariableSet"]}],"namespace":["doc","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"label":"Conditions","name":"conditions","type":"string","list":true,"ui":{},"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"namespace":["doc","conditions"],"searchable":true,"uid":false},{"type":"string","name":"description","label":"Description","ui":{},"namespace":["doc","description"],"searchable":true,"uid":false},{"type":"string","name":"slug","label":"Slug","ui":{},"namespace":["doc","slug"],"searchable":true,"uid":false},{"label":"Tags","name":"tags","type":"string","list":true,"ui":{},"options":["apis","apis_graphql","apis_openapi","computer-languages","computer-languages_css","computer-languages_html","computer-languages_javascript","computer-languages_javascript_jsx","computer-languages_javascript_mermaid","computer-languages_javascript_react","computer-languages_latex","computer-languages_latex_katex","computer-languages_markdown","computer-languages_markdown_mdx","computer-languages_xml","computer-languages_yaml","configuration","configuration_docusaurus","configuration_docusaurus_homepage","configuration_docusaurus_sidebar","configuration_github-pages","configuration_tinacms","content","content_blog-articles","content_diagrams","content_equations","content_images","content_topics","content_wikis","development","development_ai-tools","development_apis","development_apis_graphql","development_deployment","development_getting-started","development_installation","development_local-development","development_cloud-development","elements","elements_admonitions","elements_code-blocks","elements_comments","elements_context-sensitive-help","elements_doc-card-lists","elements_figures","elements_footnotes","elements_horizontal-rules","elements_links","elements_passthroughs","elements_quotes","elements_tables","elements_tabs","formatting","formatting_bold","formatting_code-font","formatting_headings","formatting_italic","formatting_strikethrough","internationalization","internationalization_localization","internationalization_translation","metadata","metadata_conditions","metadata_descriptions","metadata_slugs","metadata_taxonomies","metadata_titles","metadata_workflows","reuse","reuse_code-files","reuse_conditional-text","reuse_glossary-terms","reuse_images","reuse_snippets","reuse_variable-sets","software","software_ai-integration","software_artificial-intelligence","software_automation","software_automation_github-actions","software_browsers","software_browsers_chrome","software_browsers_edge","software_browsers_firefox","software_browsers_safari","software_command-line-interface","software_content-management-systems","software_content-management-systems_tinacms","software_content-management-systems_media-management","software_grammar-spelling-style","software_grammar-spelling-style_languagetool","software_integrated-development-environments","software_integrated-development-environments_eclipse","software_integrated-development-environments_vscodium","software_integrations","software_mcp","software_notifications","software_notifications_email","software_notifications_slack","software_notifications_teams","software_package-managers","software_package-managers_yarn","software_plugins","software_search","software_search_algolia","software_search_lunr","software_search_search-engine-optimisation","software_static-site-generators","software_static-site-generators_docusaurus","software_source-control","software_source-control_git","software_source-control_github","software_upgrading"],"namespace":["doc","tags"],"searchable":true,"uid":false},{"type":"boolean","name":"draft","label":"Workflow","ui":{},"namespace":["doc","draft"],"searchable":true,"uid":false},{"type":"boolean","name":"review","label":"In Review","ui":{"component":"hidden"},"namespace":["doc","review"],"searchable":true,"uid":false},{"type":"boolean","name":"translate","label":"In Translation","ui":{"component":"hidden"},"namespace":["doc","translate"],"searchable":true,"uid":false},{"type":"boolean","name":"approved","label":"Translation Approved","ui":{"component":"hidden"},"namespace":["doc","approved"],"searchable":true,"uid":false},{"type":"boolean","name":"published","label":"Published","ui":{"component":"hidden"},"namespace":["doc","published"],"searchable":true,"uid":false},{"type":"boolean","name":"unlisted","label":"Unlisted","ui":{"component":"hidden"},"namespace":["doc","unlisted"],"searchable":true,"uid":false}],"namespace":["doc"]},{"name":"i18n","label":"Translations","path":"i18n","format":"mdx","ui":{"defaultItem":{"draft":true,"review":false,"translate":false,"approved":false,"published":false,"unlisted":false}},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["i18n","help"],"searchable":true,"uid":false},{"label":"Last Modified","type":"string","name":"lastmod","ui":{"component":"hidden"},"namespace":["i18n","lastmod"],"searchable":true,"uid":false},{"label":"Modified By","type":"string","name":"modifiedBy","ui":{"component":"hidden"},"namespace":["i18n","modifiedBy"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["i18n","title"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["i18n","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["i18n","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["i18n","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["i18n","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["i18n","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["i18n","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["i18n","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["i18n","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["i18n","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["i18n","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["i18n","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["i18n","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["i18n","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["i18n","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["i18n","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["i18n","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["i18n","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["i18n","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","a","id"],"searchable":true,"uid":false}],"namespace":["i18n","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["i18n","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["i18n","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["i18n","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["i18n","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["i18n","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["i18n","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["i18n","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["i18n","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["i18n","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["i18n","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["i18n","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["i18n","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["i18n","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["i18n","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["i18n","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["i18n","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["i18n","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["i18n","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["i18n","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["i18n","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["i18n","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["i18n","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["i18n","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["i18n","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["i18n","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["i18n","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["i18n","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["i18n","body","Tabs","children","TabItem","children"]}],"namespace":["i18n","body","Tabs","children","TabItem"]}],"namespace":["i18n","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["i18n","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["i18n","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["i18n","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["i18n","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["i18n","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["i18n","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["i18n","body","VariableSet"]}],"namespace":["i18n","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"label":"Conditions","name":"conditions","type":"string","list":true,"ui":{},"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"namespace":["i18n","conditions"],"searchable":true,"uid":false},{"type":"string","name":"description","label":"Description","ui":{},"namespace":["i18n","description"],"searchable":true,"uid":false},{"type":"string","name":"slug","label":"Slug","ui":{},"namespace":["i18n","slug"],"searchable":true,"uid":false},{"label":"Tags","name":"tags","type":"string","list":true,"ui":{},"options":["apis","apis_graphql","apis_openapi","computer-languages","computer-languages_css","computer-languages_html","computer-languages_javascript","computer-languages_javascript_jsx","computer-languages_javascript_mermaid","computer-languages_javascript_react","computer-languages_latex","computer-languages_latex_katex","computer-languages_markdown","computer-languages_markdown_mdx","computer-languages_xml","computer-languages_yaml","configuration","configuration_docusaurus","configuration_docusaurus_homepage","configuration_docusaurus_sidebar","configuration_github-pages","configuration_tinacms","content","content_blog-articles","content_diagrams","content_equations","content_images","content_topics","content_wikis","development","development_ai-tools","development_apis","development_apis_graphql","development_deployment","development_getting-started","development_installation","development_local-development","development_cloud-development","elements","elements_admonitions","elements_code-blocks","elements_comments","elements_context-sensitive-help","elements_doc-card-lists","elements_figures","elements_footnotes","elements_horizontal-rules","elements_links","elements_passthroughs","elements_quotes","elements_tables","elements_tabs","formatting","formatting_bold","formatting_code-font","formatting_headings","formatting_italic","formatting_strikethrough","internationalization","internationalization_localization","internationalization_translation","metadata","metadata_conditions","metadata_descriptions","metadata_slugs","metadata_taxonomies","metadata_titles","metadata_workflows","reuse","reuse_code-files","reuse_conditional-text","reuse_glossary-terms","reuse_images","reuse_snippets","reuse_variable-sets","software","software_ai-integration","software_artificial-intelligence","software_automation","software_automation_github-actions","software_browsers","software_browsers_chrome","software_browsers_edge","software_browsers_firefox","software_browsers_safari","software_command-line-interface","software_content-management-systems","software_content-management-systems_tinacms","software_content-management-systems_media-management","software_grammar-spelling-style","software_grammar-spelling-style_languagetool","software_integrated-development-environments","software_integrated-development-environments_eclipse","software_integrated-development-environments_vscodium","software_integrations","software_mcp","software_notifications","software_notifications_email","software_notifications_slack","software_notifications_teams","software_package-managers","software_package-managers_yarn","software_plugins","software_search","software_search_algolia","software_search_lunr","software_search_search-engine-optimisation","software_static-site-generators","software_static-site-generators_docusaurus","software_source-control","software_source-control_git","software_source-control_github","software_upgrading"],"namespace":["i18n","tags"],"searchable":true,"uid":false},{"type":"boolean","name":"draft","label":"Workflow","ui":{},"namespace":["i18n","draft"],"searchable":true,"uid":false},{"type":"boolean","name":"review","label":"In Review","ui":{"component":"hidden"},"namespace":["i18n","review"],"searchable":true,"uid":false},{"type":"boolean","name":"translate","label":"In Translation","ui":{"component":"hidden"},"namespace":["i18n","translate"],"searchable":true,"uid":false},{"type":"boolean","name":"approved","label":"Translation Approved","ui":{"component":"hidden"},"namespace":["i18n","approved"],"searchable":true,"uid":false},{"type":"boolean","name":"published","label":"Published","ui":{"component":"hidden"},"namespace":["i18n","published"],"searchable":true,"uid":false},{"type":"boolean","name":"unlisted","label":"Unlisted","ui":{"component":"hidden"},"namespace":["i18n","unlisted"],"searchable":true,"uid":false}],"namespace":["i18n"]},{"label":"Variable Sets","name":"variableSets","path":"reuse/variableSets","format":"json","fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["variableSets","help"],"searchable":true,"uid":false},{"type":"object","label":"Variable Sets","name":"variableSets","list":true,"ui":{},"fields":[{"type":"string","label":"Variable Set Name","name":"name","isTitle":true,"required":true,"namespace":["variableSets","variableSets","name"],"searchable":true,"uid":false},{"type":"object","label":"Variables","name":"variables","list":true,"ui":{},"fields":[{"type":"string","label":"Key","name":"key","isTitle":true,"required":true,"namespace":["variableSets","variableSets","variables","key"],"searchable":true,"uid":false},{"type":"object","label":"Translations","name":"translations","list":true,"ui":{},"fields":[{"type":"string","label":"Language","name":"lang","required":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"namespace":["variableSets","variableSets","variables","translations","lang"],"searchable":true,"uid":false},{"type":"string","label":"Value","name":"value","required":true,"namespace":["variableSets","variableSets","variables","translations","value"],"searchable":true,"uid":false}],"namespace":["variableSets","variableSets","variables","translations"],"searchable":true,"uid":false}],"namespace":["variableSets","variableSets","variables"],"searchable":true,"uid":false}],"namespace":["variableSets","variableSets"],"searchable":true,"uid":false}],"ui":{"allowedActions":{"create":false,"delete":false}},"namespace":["variableSets"]},{"name":"wiki","label":"Wiki Pages","path":"docs/wiki","format":"mdx","ui":{},"fields":[{"type":"boolean","name":"help","label":"Help","required":false,"ui":{},"namespace":["wiki","help"],"searchable":true,"uid":false},{"label":"Last Modified","type":"string","name":"lastmod","ui":{"component":"hidden"},"namespace":["wiki","lastmod"],"searchable":true,"uid":false},{"type":"string","name":"title","label":"Title","isTitle":true,"required":true,"namespace":["wiki","title"],"searchable":true,"uid":false},{"type":"rich-text","name":"body","label":"Body","isBody":true,"templates":[{"name":"Admonition","ui":{"defaultItem":{"type":"note","title":"Note"}},"fields":[{"name":"type","label":"Type","type":"string","options":[{"label":"Note","value":"note"},{"label":"Tip","value":"tip"},{"label":"Info","value":"info"},{"label":"Caution","value":"caution"},{"label":"Warning","value":"danger"}],"namespace":["wiki","body","Admonition","type"],"searchable":true,"uid":false},{"name":"title","label":"Title","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","Admonition","title"],"searchable":true,"uid":false},{"name":"children","label":"Content","type":"rich-text","namespace":["wiki","body","Admonition","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["wiki","body","Admonition"]},{"name":"CodeSnippet","label":"Code Snippet","ui":{},"fields":[{"name":"title","label":"Title","type":"string","namespace":["wiki","body","CodeSnippet","title"],"searchable":true,"uid":false},{"name":"language","label":"Language","type":"string","options":[{"label":"TypeScript","value":"typescript"},{"label":"JavaScript","value":"javascript"},{"label":"JSX","value":"jsx"},{"label":"TSX","value":"tsx"},{"label":"HTML","value":"html"},{"label":"CSS","value":"css"},{"label":"SCSS/Sass","value":"scss"},{"label":"Less","value":"less"},{"label":"Stylus","value":"stylus"},{"label":"JSON","value":"json"},{"label":"JSON5","value":"json5"},{"label":"JSONC","value":"jsonc"},{"label":"XML","value":"xml"},{"label":"YAML","value":"yaml"},{"label":"TOML","value":"toml"},{"label":"CSV","value":"csv"},{"label":"INI","value":"ini"},{"label":"Python","value":"python"},{"label":"Java","value":"java"},{"label":"C#","value":"csharp"},{"label":"C++","value":"cpp"},{"label":"C","value":"c"},{"label":"PHP","value":"php"},{"label":"Ruby","value":"ruby"},{"label":"Go","value":"go"},{"label":"Rust","value":"rust"},{"label":"Swift","value":"swift"},{"label":"Kotlin","value":"kotlin"},{"label":"Scala","value":"scala"},{"label":"R","value":"r"},{"label":"MATLAB","value":"matlab"},{"label":"Objective-C","value":"objectivec"},{"label":"Dart","value":"dart"},{"label":"Elixir","value":"elixir"},{"label":"Erlang","value":"erlang"},{"label":"F#","value":"fsharp"},{"label":"Haskell","value":"haskell"},{"label":"Lua","value":"lua"},{"label":"Perl","value":"perl"},{"label":"Clojure","value":"clojure"},{"label":"Bash","value":"bash"},{"label":"Shell","value":"shell"},{"label":"PowerShell","value":"powershell"},{"label":"Batch","value":"batch"},{"label":"Fish","value":"fish"},{"label":"Zsh","value":"zsh"},{"label":"SQL","value":"sql"},{"label":"PostgreSQL","value":"postgresql"},{"label":"MySQL","value":"mysql"},{"label":"SQLite","value":"sqlite"},{"label":"MongoDB","value":"mongodb"},{"label":"GraphQL","value":"graphql"},{"label":"SPARQL","value":"sparql"},{"label":"Dockerfile","value":"dockerfile"},{"label":"Docker Compose","value":"docker-compose"},{"label":"Kubernetes","value":"kubernetes"},{"label":"Terraform","value":"terraform"},{"label":"HCL","value":"hcl"},{"label":"Ansible","value":"ansible"},{"label":"Vagrant","value":"vagrant"},{"label":"Jenkins","value":"jenkins"},{"label":"Markdown","value":"markdown"},{"label":"MDX","value":"mdx"},{"label":"LaTeX","value":"latex"},{"label":"AsciiDoc","value":"asciidoc"},{"label":"reStructuredText","value":"rst"},{"label":"Apache Config","value":"apache"},{"label":"Nginx","value":"nginx"},{"label":"Makefile","value":"makefile"},{"label":"CMake","value":"cmake"},{"label":"Properties","value":"properties"},{"label":"EditorConfig","value":"editorconfig"},{"label":"Git Config","value":"gitignore"},{"label":"Assembly x86","value":"asm6502"},{"label":"WebAssembly","value":"wasm"},{"label":"Lisp","value":"lisp"},{"label":"Scheme","value":"scheme"},{"label":"ML","value":"ml"},{"label":"OCaml","value":"ocaml"},{"label":"Handlebars","value":"handlebars"},{"label":"Mustache","value":"mustache"},{"label":"Twig","value":"twig"},{"label":"Smarty","value":"smarty"},{"label":"Jinja2","value":"jinja2"},{"label":"EJS","value":"ejs"},{"label":"Pug","value":"pug"},{"label":"Haml","value":"haml"},{"label":"Regular Expression","value":"regex"},{"label":"CSS-in-JS","value":"css-in-js"},{"label":"Protocol Buffers","value":"protobuf"},{"label":"Thrift","value":"thrift"},{"label":"ANTLR","value":"antlr4"},{"label":"BNF","value":"bnf"},{"label":"ABNF","value":"abnf"},{"label":"GLSL","value":"glsl"},{"label":"HLSL","value":"hlsl"},{"label":"Godot Script","value":"gdscript"},{"label":"Mathematica","value":"mathematica"},{"label":"Wolfram","value":"wolfram"},{"label":"R Markdown","value":"rmd"},{"label":"Jupyter","value":"jupyter"},{"label":"Git Diff","value":"diff"},{"label":"Git Patch","value":"patch"},{"label":"HTTP","value":"http"},{"label":"DNS Zone","value":"dns-zone"},{"label":"Log Files","value":"log"},{"label":"Apache Log","value":"apachelog"},{"label":"Nginx Log","value":"nginxlog"},{"label":"Plain Text","value":"text"},{"label":"ABNF","value":"abnf"},{"label":"ActionScript","value":"actionscript"},{"label":"Ada","value":"ada"},{"label":"ApacheConf","value":"apacheconf"},{"label":"APL","value":"apl"},{"label":"AppleScript","value":"applescript"},{"label":"Arduino","value":"arduino"},{"label":"AutoHotkey","value":"autohotkey"},{"label":"AutoIt","value":"autoit"},{"label":"Awk","value":"awk"},{"label":"BASIC","value":"basic"},{"label":"Brainfuck","value":"brainfuck"},{"label":"Bro","value":"bro"},{"label":"CoffeeScript","value":"coffeescript"},{"label":"Crystal","value":"crystal"},{"label":"D","value":"d"},{"label":"Django","value":"django"},{"label":"Elm","value":"elm"},{"label":"Factor","value":"factor"},{"label":"Forth","value":"forth"},{"label":"Fortran","value":"fortran"},{"label":"GDScript","value":"gdscript"},{"label":"Gherkin","value":"gherkin"},{"label":"GLSL","value":"glsl"},{"label":"GraphQL","value":"graphql"},{"label":"Groovy","value":"groovy"},{"label":"Hack","value":"hack"},{"label":"Haxe","value":"haxe"},{"label":"Hy","value":"hy"},{"label":"Icon","value":"icon"},{"label":"Inform7","value":"inform7"},{"label":"J","value":"j"},{"label":"Julia","value":"julia"},{"label":"Keyman","value":"keyman"},{"label":"LiveScript","value":"livescript"},{"label":"LOLCODE","value":"lolcode"},{"label":"Nim","value":"nim"},{"label":"Nix","value":"nix"},{"label":"OCaml","value":"ocaml"},{"label":"Oz","value":"oz"},{"label":"Pascal","value":"pascal"},{"label":"PureScript","value":"purescript"},{"label":"Q","value":"q"},{"label":"Racket","value":"racket"},{"label":"Reason","value":"reason"},{"label":"Rescript","value":"rescript"},{"label":"SAS","value":"sas"},{"label":"Solidity","value":"solidity"},{"label":"Stata","value":"stata"},{"label":"Tcl","value":"tcl"},{"label":"Vala","value":"vala"},{"label":"VB.NET","value":"vbnet"},{"label":"Verilog","value":"verilog"},{"label":"VHDL","value":"vhdl"},{"label":"Vim Script","value":"vim"},{"label":"Visual Basic","value":"vb"},{"label":"WebIDL","value":"webidl"},{"label":"Zig","value":"zig"}],"ui":{"component":"select","description":"Select the programming language for syntax highlighting"},"namespace":["wiki","body","CodeSnippet","language"],"searchable":true,"uid":false},{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.xml","value":"example.xml"}],"ui":{"component":"select","description":"Select a file from /reuse/code/ (includes subdirectories)"},"namespace":["wiki","body","CodeSnippet","filepath"],"searchable":true,"uid":false}],"namespace":["wiki","body","CodeSnippet"]},{"name":"Comment","label":"Comment","inline":true,"ui":{},"fields":[{"name":"reviewer","label":"Reviewer","type":"string","required":true,"namespace":["wiki","body","Comment","reviewer"],"searchable":true,"uid":false},{"name":"comment","label":"Comment","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","Comment","comment"],"searchable":true,"uid":false}],"namespace":["wiki","body","Comment"]},{"name":"ConditionalText","label":"Conditional Text","inline":true,"ui":{"previewSrc":"/blocks/ConditionalText.png","defaultItem":{"action":"show","conditions":[],"languages":[],"logic":"any","languageLogic":"any","requireBothConditions":false,"fallback":""}},"fields":[{"type":"rich-text","name":"children","label":"Content","namespace":["wiki","body","ConditionalText","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false},{"type":"string","name":"action","label":"Action","options":[{"value":"show","label":"Show when conditions are met"},{"value":"hide","label":"Hide when conditions are met"}],"ui":{"component":"select","description":"Choose whether to show or hide content when conditions match"},"namespace":["wiki","body","ConditionalText","action"],"searchable":true,"uid":false},{"type":"string","name":"conditions","label":"Required Conditions","list":true,"options":[{"value":"admin","label":"admin (User Roles)"},{"value":"user","label":"user (User Roles)"},{"value":"moderator","label":"moderator (User Roles)"},{"value":"guest","label":"guest (User Roles)"},{"value":"editor","label":"editor (User Roles)"},{"value":"author","label":"author (User Roles)"},{"value":"subscriber","label":"subscriber (User Roles)"},{"value":"advanced-tools","label":"advanced-tools (Feature Flags)"},{"value":"development","label":"development (Environment)"},{"value":"staging","label":"staging (Environment)"},{"value":"production","label":"production (Environment)"},{"value":"macOS","label":"macOS (Operating system)"},{"value":"Windows","label":"Windows (Operating system)"},{"value":"Linux","label":"Linux (Operating system)"},{"value":"Android","label":"Android (Operating system)"},{"value":"iOS","label":"iOS (Operating system)"}],"ui":{"description":"Content action will be triggered when these conditions are met (defined in page metadata)"},"namespace":["wiki","body","ConditionalText","conditions"],"searchable":true,"uid":false},{"type":"string","name":"languages","label":"Required Languages","list":true,"options":[{"value":"de","label":"Deutsch (de)"},{"value":"en","label":"English (en)"},{"value":"es","label":"EspaƱol (es)"},{"value":"fr","label":"FranƧais (fr)"},{"value":"ja","label":"ę—„ęœ¬čŖž (ja)"}],"ui":{"component":"checkbox-group","description":"Content action will be triggered for these languages"},"namespace":["wiki","body","ConditionalText","languages"],"searchable":true,"uid":false},{"type":"string","name":"logic","label":"Condition Logic","options":[{"value":"any","label":"Any condition matches (OR)"},{"value":"all","label":"All conditions must match (AND)"}],"ui":{"component":"select"},"namespace":["wiki","body","ConditionalText","logic"],"searchable":true,"uid":false},{"type":"string","name":"languageLogic","label":"Language Logic","options":[{"value":"any","label":"Any language matches (OR)"},{"value":"all","label":"All languages must match (AND)"}],"ui":{"component":"select"},"namespace":["wiki","body","ConditionalText","languageLogic"],"searchable":true,"uid":false},{"type":"boolean","name":"requireBothConditions","label":"Require Both Condition AND Language Conditions","ui":{"description":"When true, both condition and language conditions must be satisfied"},"namespace":["wiki","body","ConditionalText","requireBothConditions"],"searchable":true,"uid":false},{"type":"string","name":"fallback","label":"Fallback Text","ui":{"component":"textarea","description":"Optional text to show when conditions are not met"},"namespace":["wiki","body","ConditionalText","fallback"],"searchable":true,"uid":false}],"namespace":["wiki","body","ConditionalText"]},{"name":"a","label":"Context Help","ui":{},"fields":[{"name":"id","label":"Context Help ID (/docs/#)","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","a","id"],"searchable":true,"uid":false}],"namespace":["wiki","body","a"]},{"name":"Details","fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","Details","summary"],"searchable":true,"uid":false},{"name":"children","label":"Details","type":"rich-text","namespace":["wiki","body","Details","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["wiki","body","Details"]},{"name":"DocCardList","label":"Doc Card List","fields":[{"name":"title","label":"Title","type":"string","namespace":["wiki","body","DocCardList","title"],"searchable":true,"uid":false}],"namespace":["wiki","body","DocCardList"]},{"name":"Figure","label":"Figure","inline":true,"ui":{},"fields":[{"name":"img","label":"Image","type":"image","required":true,"namespace":["wiki","body","Figure","img"],"searchable":false,"uid":false},{"name":"caption","label":"Caption","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","Figure","caption"],"searchable":true,"uid":false},{"name":"size","label":"Size (%)","type":"number","description":"Width as a percentage of the container (e.g., 25 for quarter width, 50 for half width)","namespace":["wiki","body","Figure","size"],"searchable":true,"uid":false},{"name":"align","label":"Alignment","type":"string","description":"Align the image left or right (only applies when size is less than 100)","options":[{"value":"left","label":"Left"},{"value":"center","label":"Center"},{"value":"right","label":"Right"}],"namespace":["wiki","body","Figure","align"],"searchable":true,"uid":false},{"name":"hideCaption","label":"Hide Caption","type":"boolean","namespace":["wiki","body","Figure","hideCaption"],"searchable":true,"uid":false}],"namespace":["wiki","body","Figure"]},{"name":"Footnote","inline":true,"fields":[{"name":"summary","label":"Summary","type":"string","isTitle":true,"required":true,"namespace":["wiki","body","Footnote","summary"],"searchable":true,"uid":false},{"name":"children","label":"Footnote","type":"rich-text","namespace":["wiki","body","Footnote","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["wiki","body","Footnote"]},{"name":"GlossaryTerm","label":"Glossary Term","inline":true,"ui":{},"fields":[{"name":"termKey","label":"Term Key","type":"string","isTitle":true,"required":true,"options":[{"label":"single-sourcing","value":"single-sourcing"}],"ui":{"component":"select","description":"Select a glossary term key from the Glossary Terms collection"},"namespace":["wiki","body","GlossaryTerm","termKey"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["wiki","body","GlossaryTerm","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["wiki","body","GlossaryTerm","bold"],"searchable":true,"uid":false}],"namespace":["wiki","body","GlossaryTerm"]},{"name":"Passthrough","label":"Passthrough","ui":{},"fields":[{"type":"string","name":"summary","label":"Summary","isTitle":true,"required":true,"namespace":["wiki","body","Passthrough","summary"],"searchable":true,"uid":false},{"type":"string","name":"string","label":"Content","ui":{"component":"textarea"},"namespace":["wiki","body","Passthrough","string"],"searchable":true,"uid":false},{"type":"string","name":"type","label":"Content Type","options":[{"value":"markdown","label":"Markdown"},{"value":"html","label":"HTML"},{"value":"jsx","label":"JSX"}],"ui":{"component":"select"},"namespace":["wiki","body","Passthrough","type"],"searchable":true,"uid":false}],"namespace":["wiki","body","Passthrough"]},{"name":"RelatedTopics","label":"Related Topics","inline":false,"ui":{},"fields":[{"name":"maxResults","label":"Maximum Results","type":"number","description":"Maximum number of related topics to display","ui":{},"namespace":["wiki","body","RelatedTopics","maxResults"],"searchable":true,"uid":false}],"namespace":["wiki","body","RelatedTopics"]},{"name":"Snippet","label":"Snippet","inline":true,"ui":{},"fields":[{"name":"filepath","label":"File Path","type":"string","isTitle":true,"required":true,"options":[{"label":"example.mdx","value":"example.mdx"}],"ui":{"component":"select","description":"Select a file from /reuse/snippets/ (includes subdirectories)"},"namespace":["wiki","body","Snippet","filepath"],"searchable":true,"uid":false}],"namespace":["wiki","body","Snippet"]},{"name":"Tabs","label":"Tabs","ui":{},"fields":[{"name":"children","label":"Tab Items","type":"rich-text","templates":[{"name":"TabItem","label":"Tab Item","ui":{"defaultItem":{"label":"New Tab","value":"new-tab"}},"fields":[{"name":"value","label":"Tab Value","type":"string","required":true,"description":"Unique identifier for this tab","namespace":["wiki","body","Tabs","children","TabItem","value"]},{"name":"label","label":"Tab Label","type":"string","required":true,"isTitle":true,"description":"Display text for the tab button","namespace":["wiki","body","Tabs","children","TabItem","label"]},{"name":"default","label":"Default Tab","type":"boolean","description":"Set this tab as the default selected tab","namespace":["wiki","body","Tabs","children","TabItem","default"]},{"name":"children","label":"Tab Content","type":"rich-text","templates":[],"namespace":["wiki","body","Tabs","children","TabItem","children"]}],"namespace":["wiki","body","Tabs","children","TabItem"]}],"namespace":["wiki","body","Tabs","children"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["wiki","body","Tabs"]},{"name":"Truncate","label":"Truncate","fields":[{"name":"deactivate","label":"Do not modify this string or you will not be able to edit this topic in the rich text editor.","type":"string","defaultValue":"","namespace":["wiki","body","Truncate","deactivate"],"searchable":true,"uid":false}],"namespace":["wiki","body","Truncate"]},{"name":"VariableSet","label":"Variable","inline":true,"ui":{},"fields":[{"name":"variableSelection","label":"Variable","type":"string","isTitle":true,"required":true,"options":[{"value":"writing-terms_single-sourcing","label":"single-sourcing (writing-terms)"},{"value":"languages_English","label":"English (languages)"},{"value":"languages_French","label":"French (languages)"},{"value":"languages_German","label":"German (languages)"},{"value":"languages_Spanish","label":"Spanish (languages)"},{"value":"languages_Japanese","label":"Japanese (languages)"}],"ui":{"component":"select"},"namespace":["wiki","body","VariableSet","variableSelection"],"searchable":true,"uid":false},{"name":"initcap","label":"Capitalize first letter","type":"boolean","namespace":["wiki","body","VariableSet","initcap"],"searchable":true,"uid":false},{"name":"bold","label":"Bold text","type":"boolean","namespace":["wiki","body","VariableSet","bold"],"searchable":true,"uid":false}],"namespace":["wiki","body","VariableSet"]}],"namespace":["wiki","body"],"searchable":true,"parser":{"type":"mdx"},"uid":false}],"namespace":["wiki"]},{"name":"generated","label":"API (generated)","path":"docs/api","format":"mdx","ui":{"global":false,"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"boolean","name":"help","label":"Help","ui":{"component":"hidden"},"required":false,"namespace":["generated","help"],"searchable":true,"uid":false}],"namespace":["generated"]},{"name":"media","label":"Media (generated)","path":"reuse/media","format":"json","ui":{"allowedActions":{"create":false,"delete":false}},"fields":[{"type":"object","name":"media","label":"Media","list":true,"fields":[{"type":"string","name":"filename","label":"Filename","required":true,"namespace":["media","media","filename"],"searchable":true,"uid":false},{"type":"string","name":"path","label":"Path","required":true,"namespace":["media","media","path"],"searchable":true,"uid":false},{"type":"number","name":"size","label":"Size (bytes)","required":true,"namespace":["media","media","size"],"searchable":true,"uid":false},{"type":"string","name":"dimensions","label":"Dimensions (WxH)","required":false,"namespace":["media","media","dimensions"],"searchable":true,"uid":false},{"type":"string","name":"lastModified","label":"Last Modified","required":false,"namespace":["media","media","lastModified"],"searchable":true,"uid":false}],"namespace":["media","media"],"searchable":true,"uid":false}],"namespace":["media"]}],"config":{"media":{"tina":{"publicFolder":"static","mediaRoot":"img"}},"search":{"tina":{"stopwordLanguages":["eng"]}}}},"lookup":{"DocumentConnection":{"type":"DocumentConnection","resolveType":"multiCollectionDocumentList","collections":["post","conditions","dashboards","glossaryTerms","homepage","pages","settings","snippets","sidebar","taxonomy","theme","doc","i18n","variableSets","wiki","generated","media"]},"Node":{"type":"Node","resolveType":"nodeDocument"},"DocumentNode":{"type":"DocumentNode","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"Post":{"type":"Post","resolveType":"collectionDocument","collection":"post","createPost":"create","updatePost":"update"},"PostConnection":{"type":"PostConnection","resolveType":"collectionDocumentList","collection":"post"},"Conditions":{"type":"Conditions","resolveType":"collectionDocument","collection":"conditions","createConditions":"create","updateConditions":"update"},"ConditionsConnection":{"type":"ConditionsConnection","resolveType":"collectionDocumentList","collection":"conditions"},"Dashboards":{"type":"Dashboards","resolveType":"collectionDocument","collection":"dashboards","createDashboards":"create","updateDashboards":"update"},"DashboardsConnection":{"type":"DashboardsConnection","resolveType":"collectionDocumentList","collection":"dashboards"},"GlossaryTermsGlossaryTermsGlossaryTermTranslations":{"type":"GlossaryTermsGlossaryTermsGlossaryTermTranslations","resolveType":"unionData","typeMap":{"translation":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslation"}},"GlossaryTermsGlossaryTerms":{"type":"GlossaryTermsGlossaryTerms","resolveType":"unionData","typeMap":{"glossaryTerm":"GlossaryTermsGlossaryTermsGlossaryTerm"}},"GlossaryTerms":{"type":"GlossaryTerms","resolveType":"collectionDocument","collection":"glossaryTerms","createGlossaryTerms":"create","updateGlossaryTerms":"update"},"GlossaryTermsConnection":{"type":"GlossaryTermsConnection","resolveType":"collectionDocumentList","collection":"glossaryTerms"},"HomepageBlocksHeroDocument":{"type":"HomepageBlocksHeroDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"HomepageBlocks":{"type":"HomepageBlocks","resolveType":"unionData","typeMap":{"hero":"HomepageBlocksHero","features":"HomepageBlocksFeatures","youTubeEmbed":"HomepageBlocksYouTubeEmbed"}},"Homepage":{"type":"Homepage","resolveType":"collectionDocument","collection":"homepage","createHomepage":"create","updateHomepage":"update"},"HomepageConnection":{"type":"HomepageConnection","resolveType":"collectionDocumentList","collection":"homepage"},"Pages":{"type":"Pages","resolveType":"collectionDocument","collection":"pages","createPages":"create","updatePages":"update"},"PagesConnection":{"type":"PagesConnection","resolveType":"collectionDocumentList","collection":"pages"},"SettingsFooterLinksItemsInternalTo":{"type":"SettingsFooterLinksItemsInternalTo","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsFooterLinksItems":{"type":"SettingsFooterLinksItems","resolveType":"unionData","typeMap":{"internal":"SettingsFooterLinksItemsInternal","blog":"SettingsFooterLinksItemsBlog","external":"SettingsFooterLinksItemsExternal"}},"SettingsNavbarDocLink":{"type":"SettingsNavbarDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsNavbarPageLink":{"type":"SettingsNavbarPageLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsNavbarItemsDocLink":{"type":"SettingsNavbarItemsDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsNavbarItemsPageLink":{"type":"SettingsNavbarItemsPageLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsNavbarItemsItemsDocLink":{"type":"SettingsNavbarItemsItemsDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SettingsNavbarItemsItemsPageLink":{"type":"SettingsNavbarItemsItemsPageLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"Settings":{"type":"Settings","resolveType":"collectionDocument","collection":"settings","createSettings":"create","updateSettings":"update"},"SettingsConnection":{"type":"SettingsConnection","resolveType":"collectionDocumentList","collection":"settings"},"Snippets":{"type":"Snippets","resolveType":"collectionDocument","collection":"snippets","createSnippets":"create","updateSnippets":"update"},"SnippetsConnection":{"type":"SnippetsConnection","resolveType":"collectionDocumentList","collection":"snippets"},"SidebarItemsCategoryDocLink":{"type":"SidebarItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryDocLink":{"type":"SidebarItemsCategoryItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryDocLink":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems","resolveType":"unionData","typeMap":{"doc":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory","doc":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory","doc":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}},"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItemsCategoryItems":{"type":"SidebarItemsCategoryItemsCategoryItemsCategoryItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategory","doc":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}},"SidebarItemsCategoryItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItemsCategoryItems":{"type":"SidebarItemsCategoryItemsCategoryItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategoryItemsCategoryItemsCategory","doc":"SidebarItemsCategoryItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsCategoryItemsAutogenerated"}},"SidebarItemsCategoryItemsDocDocument":{"type":"SidebarItemsCategoryItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItemsCategoryItems":{"type":"SidebarItemsCategoryItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategoryItemsCategory","doc":"SidebarItemsCategoryItemsDoc","link":"SidebarItemsCategoryItemsLink","autogenerated":"SidebarItemsCategoryItemsAutogenerated"}},"SidebarItemsDocDocument":{"type":"SidebarItemsDocDocument","resolveType":"multiCollectionDocument","createDocument":"create","updateDocument":"update"},"SidebarItems":{"type":"SidebarItems","resolveType":"unionData","typeMap":{"category":"SidebarItemsCategory","doc":"SidebarItemsDoc","link":"SidebarItemsLink","autogenerated":"SidebarItemsAutogenerated"}},"Sidebar":{"type":"Sidebar","resolveType":"collectionDocument","collection":"sidebar","createSidebar":"create","updateSidebar":"update"},"SidebarConnection":{"type":"SidebarConnection","resolveType":"collectionDocumentList","collection":"sidebar"},"Taxonomy":{"type":"Taxonomy","resolveType":"collectionDocument","collection":"taxonomy","createTaxonomy":"create","updateTaxonomy":"update"},"TaxonomyConnection":{"type":"TaxonomyConnection","resolveType":"collectionDocumentList","collection":"taxonomy"},"Theme":{"type":"Theme","resolveType":"collectionDocument","collection":"theme","createTheme":"create","updateTheme":"update"},"ThemeConnection":{"type":"ThemeConnection","resolveType":"collectionDocumentList","collection":"theme"},"Doc":{"type":"Doc","resolveType":"collectionDocument","collection":"doc","createDoc":"create","updateDoc":"update"},"DocConnection":{"type":"DocConnection","resolveType":"collectionDocumentList","collection":"doc"},"I18n":{"type":"I18n","resolveType":"collectionDocument","collection":"i18n","createI18n":"create","updateI18n":"update"},"I18nConnection":{"type":"I18nConnection","resolveType":"collectionDocumentList","collection":"i18n"},"VariableSets":{"type":"VariableSets","resolveType":"collectionDocument","collection":"variableSets","createVariableSets":"create","updateVariableSets":"update"},"VariableSetsConnection":{"type":"VariableSetsConnection","resolveType":"collectionDocumentList","collection":"variableSets"},"Wiki":{"type":"Wiki","resolveType":"collectionDocument","collection":"wiki","createWiki":"create","updateWiki":"update"},"WikiConnection":{"type":"WikiConnection","resolveType":"collectionDocumentList","collection":"wiki"},"Generated":{"type":"Generated","resolveType":"collectionDocument","collection":"generated","createGenerated":"create","updateGenerated":"update"},"GeneratedConnection":{"type":"GeneratedConnection","resolveType":"collectionDocumentList","collection":"generated"},"Media":{"type":"Media","resolveType":"collectionDocument","collection":"media","createMedia":"create","updateMedia":"update"},"MediaConnection":{"type":"MediaConnection","resolveType":"collectionDocumentList","collection":"media"}},"graphql":{"kind":"Document","definitions":[{"kind":"ScalarTypeDefinition","name":{"kind":"Name","value":"Reference"},"description":{"kind":"StringValue","value":"References another document, used as a foreign key"},"directives":[]},{"kind":"ScalarTypeDefinition","name":{"kind":"Name","value":"JSON"},"description":{"kind":"StringValue","value":""},"directives":[]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SystemInfo"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"filename"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"basename"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"hasReferences"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"breadcrumbs"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"excludeExtension"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"path"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"relativePath"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"extension"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"template"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"collection"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"Folder"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"path"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"PageInfo"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"hasPreviousPage"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"hasNextPage"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"startCursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"endCursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"InterfaceTypeDefinition","description":{"kind":"StringValue","value":""},"name":{"kind":"Name","value":"Node"},"interfaces":[],"directives":[],"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}]},{"kind":"InterfaceTypeDefinition","description":{"kind":"StringValue","value":""},"name":{"kind":"Name","value":"Document"},"interfaces":[],"directives":[],"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InterfaceTypeDefinition","description":{"kind":"StringValue","value":"A relay-compliant pagination connection"},"name":{"kind":"Name","value":"Connection"},"interfaces":[],"directives":[],"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"Query"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"getOptimizedQuery"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"queryString"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"collection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"collections"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Collection"}}}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Node"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"post"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"postConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"conditions"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Conditions"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"conditionsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dashboards"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Dashboards"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dashboardsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"glossaryTerms"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTerms"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"glossaryTermsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"homepage"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Homepage"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"homepageConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pages"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pagesConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"settings"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Settings"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"settingsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"snippets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Snippets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"snippetsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"sidebar"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Sidebar"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"sidebarConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"taxonomy"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Taxonomy"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"taxonomyConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"theme"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Theme"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"themeConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"doc"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"i18n"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18n"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"i18nConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"variableSets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"variableSetsConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"wiki"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Wiki"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"wikiConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"generated"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Generated"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"generatedConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedConnection"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"media"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Media"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"mediaConnection"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaFilter"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaConnection"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"post"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dashboards"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerms"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"homepage"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"settings"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"snippets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sidebar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"taxonomy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"theme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"i18n"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"wiki"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"generated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"media"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"DocumentConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"DocumentConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"Collection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"slug"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"path"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"format"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"matches"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"templates"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"fields"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"documents"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"before"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"after"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"first"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"last"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sort"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"folder"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentConnection"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"DocumentNode"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},{"kind":"NamedType","name":{"kind":"Name","value":"Conditions"}},{"kind":"NamedType","name":{"kind":"Name","value":"Dashboards"}},{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTerms"}},{"kind":"NamedType","name":{"kind":"Name","value":"Homepage"}},{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}},{"kind":"NamedType","name":{"kind":"Name","value":"Settings"}},{"kind":"NamedType","name":{"kind":"Name","value":"Snippets"}},{"kind":"NamedType","name":{"kind":"Name","value":"Sidebar"}},{"kind":"NamedType","name":{"kind":"Name","value":"Taxonomy"}},{"kind":"NamedType","name":{"kind":"Name","value":"Theme"}},{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}},{"kind":"NamedType","name":{"kind":"Name","value":"I18n"}},{"kind":"NamedType","name":{"kind":"Name","value":"VariableSets"}},{"kind":"NamedType","name":{"kind":"Name","value":"Wiki"}},{"kind":"NamedType","name":{"kind":"Name","value":"Generated"}},{"kind":"NamedType","name":{"kind":"Name","value":"Media"}},{"kind":"NamedType","name":{"kind":"Name","value":"Folder"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"PostAuthors"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"url"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"image_url"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Post"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastmod"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"authors"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostAuthors"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"date"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"tags"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"BooleanFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"eq"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"exists"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"StringFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"startsWith"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"eq"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"exists"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"in"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostAuthorsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"image_url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"RichTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"startsWith"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"eq"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"exists"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ImageFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"startsWith"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"eq"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"exists"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"in"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"NumberFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lt"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lte"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"gte"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"gt"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"eq"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"exists"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"in"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"authors"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostAuthorsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"date"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostBodyFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"PostConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"PostConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ConditionsCategoriesConditions"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"condition"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"active"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ConditionsCategories"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"conditions"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategoriesConditions"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Conditions"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"categories"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategories"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsCategoriesConditionsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"condition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"active"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsCategoriesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategoriesConditionsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"categories"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategoriesFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ConditionsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Conditions"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"ConditionsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Dashboards"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"statusBar"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dashboard1"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"contentReuseDashboard"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"mediaDashboard"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"translationDashboard"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"brokenLinksDashboard"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DashboardsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"statusBar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dashboard1"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"contentReuseDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"mediaDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translationDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"brokenLinksDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"DashboardsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Dashboards"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"DashboardsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslation"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"lang"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"term"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"definition"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslations"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslation"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTerm"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"key"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"translations"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslations"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTerms"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTerm"}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"GlossaryTerms"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"glossaryTerms"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTerms"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslationFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lang"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"term"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"definition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translation"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslationFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"key"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translations"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerms"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"GlossaryTermsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTerms"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"GlossaryTermsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsConnectionEdges"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeatures"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"feature"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageBlocksHero"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"subtitle"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroDocument"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"documentLabel"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"secondaryButtonText"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"secondaryButtonLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"showHeroCard"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"heroCardTitle"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"heroCardFeatures"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeatures"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageBlocksFeaturesItems"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"image"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageBlocksFeatures"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeaturesItems"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbed"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"url"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"caption"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"HomepageBlocks"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHero"}},{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeatures"}},{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbed"}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Homepage"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_warning"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"blocks"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocks"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeaturesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"feature"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"subtitle"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"documentLabel"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"secondaryButtonText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"secondaryButtonLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"showHeroCard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"heroCardTitle"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"heroCardFeatures"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeaturesFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksFeaturesItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"image"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksFeaturesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeaturesItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hero"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"features"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeaturesFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"youTubeEmbed"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"blocks"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"HomepageConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Homepage"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"HomepageConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Pages"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesBodyFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"PagesConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"PagesConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsColorMode"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"defaultMode"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"disableSwitch"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"respectPrefersColorScheme"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalTo"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}},{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsFooterLinksItemsInternal"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"to"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalTo"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsFooterLinksItemsBlog"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsFooterLinksItemsExternal"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternal"}},{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsBlog"}},{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsExternal"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsFooterLinks"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItems"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsFooter"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"style"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"links"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinks"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"copyright"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsGithub"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"projectName"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"organizationName"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsLanguagesSupported"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"code"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsLanguages"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"supported"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguagesSupported"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"default"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsLogo"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"alt"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"src"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsOpenapiApis"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"specPath"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"outputDir"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"downloadUrl"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"groupPathsBy"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"categoryLinkSource"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsOpenapi"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"apis"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapiApis"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"languageTabs"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlock"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"start"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"end"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsPrismMagicComments"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"className"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"line"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"block"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlock"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsPrism"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"additionalLanguages"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"magicComments"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicComments"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"theme"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"darkTheme"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsUrl"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"siteUrl"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"baseUrl"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"trailingSlash"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarPageLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsPageLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsPageLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsNavbarItemsItems"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsPageLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"externalLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"manualPath"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docId"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"position"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsNavbarItems"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsPageLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"externalLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"manualPath"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docId"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"position"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItems"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsNavbar"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarPageLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"externalLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"manualPath"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docId"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"position"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItems"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Settings"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_warning"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"tagline"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"favicon"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"graphql"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"colorMode"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsColorMode"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"footer"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooter"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"github"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsGithub"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"languages"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguages"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"logo"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLogo"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"openapi"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapi"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"prism"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrism"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"url"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsUrl"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"navbar"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbar"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"sidebarHideable"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"showReadingTime"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsColorModeFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"defaultMode"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"disableSwitch"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"respectPrefersColorScheme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalToFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"post"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"to"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalToFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsBlogFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsExternalFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"internal"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"blog"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsBlogFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"external"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsExternalFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"style"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"links"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"copyright"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsGithubFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"projectName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"organizationName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLanguagesSupportedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"code"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLanguagesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"supported"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguagesSupportedFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLogoFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"alt"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"src"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsOpenapiApisFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"specPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"outputDir"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"downloadUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"groupPathsBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"categoryLinkSource"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsOpenapiFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"apis"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapiApisFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageTabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlockFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"start"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"end"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismMagicCommentsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"className"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"line"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"block"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlockFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"additionalLanguages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"magicComments"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicCommentsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"theme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"darkTheme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsUrlFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"siteUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"baseUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"trailingSlash"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarPageLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsPageLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsPageLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsPageLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsPageLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarPageLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tagline"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"favicon"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"graphql"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"colorMode"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsColorModeFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"github"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsGithubFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguagesFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logo"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLogoFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"openapi"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapiFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"prism"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsUrlFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"navbar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sidebarHideable"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"showReadingTime"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SettingsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Settings"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"SettingsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Snippets"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastmod"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsBodyFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SnippetsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Snippets"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"SnippetsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsConnectionEdges"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsCategory"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"link"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"docLink"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryDocLink"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItems"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItemsDocDocument"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsDoc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"document"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsDocDocument"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsLink"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"href"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarItemsAutogenerated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dirName"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"UnionTypeDefinition","name":{"kind":"Name","value":"SidebarItems"},"directives":[],"types":[{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategory"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsDoc"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsLink"}},{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsAutogenerated"}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Sidebar"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_warning"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"label"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"items"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItems"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryDocLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsDocDocumentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsDocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsDocDocumentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsLinkFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsAutogeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsDocFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsLinkFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsAutogeneratedFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"SidebarConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Sidebar"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"SidebarConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildren"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"tag"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"TaxonomyTaxonomyChildren"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"tag"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"children"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildren"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"TaxonomyTaxonomy"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"tag"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"children"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildren"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Taxonomy"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"taxonomy"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomy"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"taxonomy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"TaxonomyConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Taxonomy"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"TaxonomyConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ThemeColors"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"primary"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDark"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDarker"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDarkest"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLight"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLighter"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLightest"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"footerBackground"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ThemeDarkColors"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"primary"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDark"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDarker"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryDarkest"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLight"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLighter"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"primaryLightest"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"footerBackground"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ThemeTypography"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"baseFontFamily"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"monospaceFontFamily"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"codeFontSize"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ThemeLayout"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"globalRadius"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"buttonRadius"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"cardRadius"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"navbarHeight"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Theme"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"_warning"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"colors"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeColors"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"darkColors"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeDarkColors"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"typography"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeTypography"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"layout"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeLayout"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"customCSS"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeColorsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDark"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarker"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarkest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLighter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLightest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footerBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeDarkColorsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDark"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarker"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarkest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLighter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLightest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footerBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeTypographyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"baseFontFamily"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"monospaceFontFamily"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"codeFontSize"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeLayoutFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"globalRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"buttonRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"cardRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"navbarHeight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"colors"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeColorsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"darkColors"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeDarkColorsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"typography"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeTypographyFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"layout"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeLayoutFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"customCSS"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"ThemeConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Theme"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"ThemeConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Doc"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastmod"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"modifiedBy"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"conditions"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"slug"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"tags"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"draft"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"review"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"translate"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"approved"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"published"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"unlisted"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"modifiedBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocBodyFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"slug"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"draft"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"review"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"approved"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"published"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"unlisted"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"DocConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"DocConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"I18n"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastmod"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"modifiedBy"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"conditions"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"description"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"slug"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"tags"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"draft"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"review"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"translate"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"approved"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"published"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"unlisted"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"modifiedBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nBodyFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"slug"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"draft"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"review"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"approved"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"published"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"unlisted"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"I18nConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18n"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"I18nConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslations"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"lang"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"value"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"VariableSetsVariableSetsVariables"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"key"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"translations"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslations"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"VariableSetsVariableSets"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"name"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"variables"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariables"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"VariableSets"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"variableSets"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslationsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lang"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"key"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translations"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslationsFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variables"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"VariableSetsConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSets"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"VariableSetsConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Wiki"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastmod"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"title"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"body"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyAdmonitionFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyCodeSnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"language"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyCommentFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"reviewer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyConditionalTextFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"action"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageLogic"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"requireBothConditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"fallback"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyAFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"id"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyDetailsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyDocCardListFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyFigureFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"img"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"align"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hideCaption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyFootnoteFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyGlossaryTermFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"termKey"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyPassthroughFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"summary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"string"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"type"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyRelatedTopicsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"maxResults"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodySnippetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filepath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyTabsChildrenTabItemFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"RichTextFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyTabsChildrenFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"TabItem"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyTabsChildrenTabItemFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyTabsFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyTabsChildrenFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyTruncateFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"deactivate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyVariableSetFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSelection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"initcap"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"bold"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiBodyFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Admonition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyAdmonitionFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"CodeSnippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyCodeSnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Comment"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyCommentFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"ConditionalText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyConditionalTextFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"a"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyAFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Details"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyDetailsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"DocCardList"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyDocCardListFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Figure"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyFigureFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Footnote"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyFootnoteFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"GlossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyGlossaryTermFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Passthrough"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyPassthroughFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"RelatedTopics"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyRelatedTopicsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Snippet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodySnippetFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Tabs"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyTabsFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"Truncate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyTruncateFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"VariableSet"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyVariableSetFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiBodyFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"WikiConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Wiki"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"WikiConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Generated"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"help"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GeneratedFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"BooleanFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"GeneratedConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Generated"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"GeneratedConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"MediaMedia"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"filename"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"path"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"size"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"dimensions"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"lastModified"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},{"kind":"NamedType","name":{"kind":"Name","value":"Document"}}],"directives":[],"name":{"kind":"Name","value":"Media"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"media"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMedia"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"id"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_sys"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SystemInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"_values"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"MediaMediaFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filename"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"path"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NumberFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dimensions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastModified"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"StringFilter"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"MediaFilter"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"media"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMediaFilter"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"MediaConnectionEdges"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"cursor"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"node"},"arguments":[],"type":{"kind":"NamedType","name":{"kind":"Name","value":"Media"}}}]},{"kind":"ObjectTypeDefinition","interfaces":[{"kind":"NamedType","name":{"kind":"Name","value":"Connection"}}],"directives":[],"name":{"kind":"Name","value":"MediaConnection"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"pageInfo"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PageInfo"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"totalCount"},"arguments":[],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"edges"},"arguments":[],"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaConnectionEdges"}}}}]},{"kind":"ObjectTypeDefinition","interfaces":[],"directives":[],"name":{"kind":"Name","value":"Mutation"},"fields":[{"kind":"FieldDefinition","name":{"kind":"Name","value":"addPendingDocument"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"template"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateDocument"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentUpdateMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"deleteDocument"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createDocument"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createFolder"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"collection"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocumentNode"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updatePost"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createPost"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateConditions"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Conditions"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createConditions"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Conditions"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateDashboards"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Dashboards"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createDashboards"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Dashboards"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateGlossaryTerms"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTerms"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createGlossaryTerms"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTerms"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateHomepage"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Homepage"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createHomepage"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Homepage"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updatePages"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createPages"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Pages"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateSettings"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Settings"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createSettings"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Settings"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateSnippets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Snippets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createSnippets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Snippets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateSidebar"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Sidebar"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createSidebar"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Sidebar"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateTaxonomy"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Taxonomy"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createTaxonomy"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Taxonomy"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateTheme"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Theme"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createTheme"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Theme"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateDoc"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createDoc"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DocMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Doc"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateI18n"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18n"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createI18n"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"I18n"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateVariableSets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createVariableSets"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSets"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateWiki"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Wiki"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createWiki"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Wiki"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateGenerated"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Generated"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createGenerated"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Generated"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"updateMedia"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Media"}}}},{"kind":"FieldDefinition","name":{"kind":"Name","value":"createMedia"},"arguments":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"params"},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMutation"}}}}],"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Media"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocumentUpdateMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"post"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dashboards"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerms"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"homepage"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"settings"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"snippets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sidebar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"taxonomy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"theme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"i18n"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"wiki"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"generated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"media"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"relativePath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocumentMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"post"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PostMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dashboards"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DashboardsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerms"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"homepage"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PagesMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"settings"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"snippets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SnippetsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sidebar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"taxonomy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"theme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"i18n"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"I18nMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSets"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"wiki"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WikiMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"generated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GeneratedMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"media"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostAuthorsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"image_url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PostMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"authors"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostAuthorsMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"date"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsCategoriesConditionsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"condition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"active"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsCategoriesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategoriesConditionsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ConditionsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"categories"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConditionsCategoriesMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DashboardsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"statusBar"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dashboard1"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"contentReuseDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"mediaDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translationDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"brokenLinksDashboard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslationMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lang"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"term"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"definition"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translation"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsTranslationMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"key"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translations"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermTranslationsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerm"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsGlossaryTermMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GlossaryTermsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"glossaryTerms"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlossaryTermsGlossaryTermsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeaturesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"feature"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksHeroMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"subtitle"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"documentLabel"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"secondaryButtonText"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"secondaryButtonLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"showHeroCard"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"heroCardTitle"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"heroCardFeatures"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroHeroCardFeaturesMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksFeaturesItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"image"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksFeaturesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeaturesItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"caption"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageBlocksMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"hero"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksHeroMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"features"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksFeaturesMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"youTubeEmbed"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksYouTubeEmbedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"HomepageMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"blocks"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HomepageBlocksMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"PagesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsColorModeMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"defaultMode"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"disableSwitch"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"respectPrefersColorScheme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"to"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsBlogMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsExternalMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"internal"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsInternalMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"blog"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsBlogMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"external"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsExternalMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterLinksMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsFooterMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"style"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"links"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterLinksMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"copyright"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsGithubMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"projectName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"organizationName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLanguagesSupportedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"code"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLanguagesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"supported"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguagesSupportedMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"default"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsLogoMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"alt"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"src"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsOpenapiApisMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"specPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"outputDir"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"downloadUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"groupPathsBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"categoryLinkSource"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsOpenapiMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"apis"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapiApisMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languageTabs"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlockMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"start"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"end"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismMagicCommentsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"className"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"line"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"block"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicCommentsBlockMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsPrismMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"additionalLanguages"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"magicComments"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMagicCommentsMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"theme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"darkTheme"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsUrlMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"siteUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"baseUrl"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"trailingSlash"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsNavbarMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"pageLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"externalLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"manualPath"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docId"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"position"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SettingsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tagline"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"favicon"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"graphql"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"colorMode"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsColorModeMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footer"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsFooterMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"github"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsGithubMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"languages"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLanguagesMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"logo"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsLogoMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"openapi"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsOpenapiMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"prism"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsPrismMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"url"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsUrlMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"navbar"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SettingsNavbarMutation"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"sidebarHideable"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"showReadingTime"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SnippetsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsCategoryMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"docLink"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsDocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"document"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsLinkMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"href"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsAutogeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dirName"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarItemsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"category"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsCategoryMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"doc"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsDocMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"link"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsLinkMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"autogenerated"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsAutogeneratedMutation"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"SidebarMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"label"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"items"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SidebarItemsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildrenMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenChildrenMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyTaxonomyMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tag"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"children"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyChildrenMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"TaxonomyMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"taxonomy"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TaxonomyTaxonomyMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeColorsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDark"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarker"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarkest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLighter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLightest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footerBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeDarkColorsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primary"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDark"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarker"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryDarkest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLighter"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"primaryLightest"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"footerBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"highlightedCodeLineBackground"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeTypographyMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"baseFontFamily"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"monospaceFontFamily"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"codeFontSize"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeLayoutMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"globalRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"buttonRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"cardRadius"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"navbarHeight"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"ThemeMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"_warning"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"colors"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeColorsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"darkColors"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeDarkColorsMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"typography"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeTypographyMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"layout"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ThemeLayoutMutation"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"customCSS"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"DocMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"modifiedBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"slug"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"draft"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"review"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"approved"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"published"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"unlisted"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"I18nMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"modifiedBy"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"conditions"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"description"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"slug"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"tags"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"draft"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"review"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translate"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"approved"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"published"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"unlisted"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslationsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lang"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"value"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"key"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"translations"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesTranslationsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsVariableSetsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"name"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variables"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsVariablesMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"VariableSetsMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"variableSets"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"VariableSetsVariableSetsMutation"}}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"WikiMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastmod"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"title"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"body"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"GeneratedMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"help"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"MediaMediaMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"filename"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"path"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"size"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"dimensions"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"InputValueDefinition","name":{"kind":"Name","value":"lastModified"},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}]},{"kind":"InputObjectTypeDefinition","name":{"kind":"Name","value":"MediaMutation"},"fields":[{"kind":"InputValueDefinition","name":{"kind":"Name","value":"media"},"type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MediaMediaMutation"}}}}]}]}} \ No newline at end of file diff --git a/update-manifest.json b/update-manifest.json index a2ee25d9..d1114120 100644 --- a/update-manifest.json +++ b/update-manifest.json @@ -1,5 +1,6 @@ { "manifestVersion": 1, + "minCreateVersion": "0.2.1", "mirrorDirs": [ "src/clientModules", "src/components", @@ -11,15 +12,18 @@ "files": [ "docusaurus.config.ts", "sidebars.ts", - "biome.json", "frontmatter.json", "tina/config.jsx", "config/docusaurus/openapi-tag-template.md", "src/css/custom.css", "src/pages/404.js", "src/pages/index.jsx", - "src/pages/index.module.css" + "src/pages/index.module.css", + "biome.template.json" ], + "renameFiles": { + "biome.template.json": "biome.json" + }, "removeFiles": [ "util.js", "babel.config.js" diff --git a/yarn.lock b/yarn.lock index bc4addcf..43a045fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,16 @@ # yarn lockfile v1 +"@11ty/gray-matter@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@11ty/gray-matter/-/gray-matter-1.0.0.tgz#35ee04d76b870893c053f64f659c923a7a9db2d7" + integrity sha512-7mJJl+wf1AByoT0PknQiQfOPnVNT4fevGrUBVWO4HXsnYn1aQPyRyrELYrNUFleUBM++KzMKN6QaxHPk0t/6/g== + dependencies: + js-yaml "^4.1.0" + kind-of "^6.0.3" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + "@algolia/abtesting@1.16.1": version "1.16.1" resolved "https://registry.yarnpkg.com/@algolia/abtesting/-/abtesting-1.16.1.tgz#036ddd7ca49a4f5ba20ced09b9e0e5b913ccf6e8" @@ -77,10 +87,10 @@ resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.50.1.tgz#c29b1b1f3e9098f36ee867413b2366893234b5bb" integrity sha512-Hw52Fwapyk/7hMSV/fI4+s3H9MGZEUcRh4VphyXLAk2oLYdndVUkc6KBi0zwHSzwPAr+ZBwFPe2x6naUt9mZGw== -"@algolia/client-common@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.53.0.tgz#c8b0d8afc0d202ba71de9c3ac2c7331b92020f75" - integrity sha512-YPN45TXD9Wrse185t/Ta7nktZsqpv97oOjCzp2sblHnCL6rBc9TDeJAg1IGl2UpdwnSD05Zu/5wLB4watOUMyg== +"@algolia/client-common@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.56.0.tgz#6190221a7091dfa1a0e0a3b5964e92b1b59968ba" + integrity sha512-v2TPStUhY//ripPjIVclZ8AWc7DEGooXULZGFlFu37zNatgHjw34oZZ+OSbbc/YHO+xZwPl62I1k8xH1m4S2eg== "@algolia/client-insights@5.50.1": version "5.50.1" @@ -122,15 +132,15 @@ "@algolia/requester-fetch" "5.50.1" "@algolia/requester-node-http" "5.50.1" -"@algolia/client-search@^5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.53.0.tgz#a1b412880462c85a1ac72c830498e0312dde1e0e" - integrity sha512-Ds16IyPm/dNJPCU8OzApo2gwGrgWT5BYHhE3NFwZbpCveqyvPDB9sZDDkJ5DsdOGT2aC+R3i0/M1OVXF2qdgPg== +"@algolia/client-search@^5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.56.0.tgz#66b19d5382bf47a16105817b78e372f5e9039508" + integrity sha512-+mKUdYvqOi0BcvpAEyCEw49vSBptufIcfibtHz2bdr1pI789M46Yt0uQEk/sxtK3teh71OQvVFHaTDzShUWewQ== dependencies: - "@algolia/client-common" "5.53.0" - "@algolia/requester-browser-xhr" "5.53.0" - "@algolia/requester-fetch" "5.53.0" - "@algolia/requester-node-http" "5.53.0" + "@algolia/client-common" "5.56.0" + "@algolia/requester-browser-xhr" "5.56.0" + "@algolia/requester-fetch" "5.56.0" + "@algolia/requester-node-http" "5.56.0" "@algolia/events@^4.0.1": version "4.0.1" @@ -174,12 +184,12 @@ dependencies: "@algolia/client-common" "5.50.1" -"@algolia/requester-browser-xhr@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.53.0.tgz#bd742734337378090d5c95f80de2b7a933089924" - integrity sha512-ke27DqgzCOlt+RbeEdCxtXxMQOnAOi8ujr2wid0DmDKzR95Kw/f9sBsuhBxtjevCqJRJszfRTLY0B1pbO6IhkA== +"@algolia/requester-browser-xhr@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.56.0.tgz#b1f4705c53f1602ec14339999bfbf0e3e9a7bbc8" + integrity sha512-7t24cBxaInS3mZb7ddEaZT/tp6q+/aR4YttsQVyP1/i+LmwPR34atO35KjaLFCcRVrlP7sYOAqkCfg6lIRB+ew== dependencies: - "@algolia/client-common" "5.53.0" + "@algolia/client-common" "5.56.0" "@algolia/requester-fetch@5.50.1": version "5.50.1" @@ -188,12 +198,12 @@ dependencies: "@algolia/client-common" "5.50.1" -"@algolia/requester-fetch@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-fetch/-/requester-fetch-5.53.0.tgz#1f4b3d933c50d0022de4ce18d235b65325b7024e" - integrity sha512-GngiOqt2Gq4oLno6yXQVj9om+qSO9SWAoduoTOEg79dKZ62brB8OOIvSJG/vDNoanYi6a7Al9uDZwXvi+bcVTg== +"@algolia/requester-fetch@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-fetch/-/requester-fetch-5.56.0.tgz#03f0aeea08efc991ab9f0663f1ea63df720fd9ba" + integrity sha512-R7ePHgVYmDFjZpvrsVAfbDz/d4RxKAYZ5/vgLfIsCVRZRryjWl/3INOxpOICzitehQ5FjNtNjcLQTrmHPTcHBQ== dependencies: - "@algolia/client-common" "5.53.0" + "@algolia/client-common" "5.56.0" "@algolia/requester-node-http@5.50.1": version "5.50.1" @@ -202,12 +212,12 @@ dependencies: "@algolia/client-common" "5.50.1" -"@algolia/requester-node-http@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.53.0.tgz#8c25669aaf6fc11a2970d2f62fbda3c603ec11ce" - integrity sha512-6mF9LZMUk0QqWvrnxkxBqhswwz6Xfiwy6/gmTzL5HrlhdVG3ITAqGV2k3XmVThP1h0Ulc3VQwiNCD7/Nr4JNlQ== +"@algolia/requester-node-http@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.56.0.tgz#238bfa98ed145e261c1db7e133bee6390ba58c94" + integrity sha512-PIOUXlSnrqM0S+WOgDRb4RzotydJH7ZoT6tOyL7tAO7qJOfvX5wsEW8Pe+PMKMwvuI4/gIyK9cg2H7lJXqnc4Q== dependencies: - "@algolia/client-common" "5.53.0" + "@algolia/client-common" "5.56.0" "@alloc/quick-lru@^5.2.0": version "5.2.0" @@ -1139,7 +1149,7 @@ "@babel/plugin-transform-modules-commonjs" "^7.27.1" "@babel/plugin-transform-typescript" "^7.28.5" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.25.9", "@babel/runtime@^7.29.2", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.25.9", "@babel/runtime@^7.29.2", "@babel/runtime@^7.9.2": version "7.29.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e" integrity sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g== @@ -1174,59 +1184,59 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" -"@biomejs/biome@^2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.4.16.tgz#241feeafcbc9c26ced1600e5c6016f4b3b599d24" - integrity sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA== +"@biomejs/biome@^2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/biome/-/biome-2.5.7.tgz#845a49fe90f271b4f280e4244ecaccb0306e9068" + integrity sha512-zr8K/DcY5tYsQOQwqMJ0AWElo6QgmgNI7idXgXLhevVszlt8RGVpesEJPqx3ThazLaOwjJ5Y8fz3BtH5fGZNsw== optionalDependencies: - "@biomejs/cli-darwin-arm64" "2.4.16" - "@biomejs/cli-darwin-x64" "2.4.16" - "@biomejs/cli-linux-arm64" "2.4.16" - "@biomejs/cli-linux-arm64-musl" "2.4.16" - "@biomejs/cli-linux-x64" "2.4.16" - "@biomejs/cli-linux-x64-musl" "2.4.16" - "@biomejs/cli-win32-arm64" "2.4.16" - "@biomejs/cli-win32-x64" "2.4.16" - -"@biomejs/cli-darwin-arm64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.16.tgz#c361db44920728d57e2b0a48bb88c09ad01101b9" - integrity sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A== - -"@biomejs/cli-darwin-x64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz#4e69cfecd92f2909b87a9a1dff61f18dbc013088" - integrity sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw== - -"@biomejs/cli-linux-arm64-musl@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz#5485d4a544d0818a29ce022256299ace49531779" - integrity sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg== - -"@biomejs/cli-linux-arm64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz#d6df1fb75ca5d05dec7985d74ffe503c4c3d33b1" - integrity sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ== - -"@biomejs/cli-linux-x64-musl@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz#4ccb530d703878a239c204b13aeb8d5c8cf80d8f" - integrity sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg== - -"@biomejs/cli-linux-x64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz#725c4e4dc0ec7182bb49c18c9d301184e669889e" - integrity sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ== - -"@biomejs/cli-win32-arm64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz#639e5433eb2c412c7798702708c96851de0b7827" - integrity sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A== - -"@biomejs/cli-win32-x64@2.4.16": - version "2.4.16" - resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.16.tgz#30fb75d856864ff9d3324da20c72c9f121c9ae16" - integrity sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw== + "@biomejs/cli-darwin-arm64" "2.5.7" + "@biomejs/cli-darwin-x64" "2.5.7" + "@biomejs/cli-linux-arm64" "2.5.7" + "@biomejs/cli-linux-arm64-musl" "2.5.7" + "@biomejs/cli-linux-x64" "2.5.7" + "@biomejs/cli-linux-x64-musl" "2.5.7" + "@biomejs/cli-win32-arm64" "2.5.7" + "@biomejs/cli-win32-x64" "2.5.7" + +"@biomejs/cli-darwin-arm64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.7.tgz#64a47b72f6405f80f6df92fa79246c23d91d5ddd" + integrity sha512-vxo/Ls3/PYdQWyLhYYcgMOCzQypAjcY+iihS8M0wW03l16TCLW4zqZzGo75gm1VdCMj38hTVZ31KBWrZ4G9dJw== + +"@biomejs/cli-darwin-x64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.7.tgz#3f58c2d6e7af46c7da1c2232797a2a9e325194f4" + integrity sha512-Cd3Ga61amT/Yl/0x8elP5hhGYaFy4bw6WuysTgf7oo8TA5tJ5A1k+DkVoJ2BHbTVil51gTX9VPzArnrlLJ3Kyg== + +"@biomejs/cli-linux-arm64-musl@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.7.tgz#f135313f59f9e126a3553ace4239e4279cc2e7ac" + integrity sha512-xPI5yB6XlpDbNkS+bm1t42olw5c4l3UrlOmLg7KtLJvjvkNF/1V4tnUgfkylGIeb3u/T+BzMGYqgQhzjAoJzuQ== + +"@biomejs/cli-linux-arm64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.7.tgz#3e98beda0cab6e1f33908805b1be2d182ae8ce3f" + integrity sha512-rR2QE0yF2GYSuYuKIa7pKvODGJqnOH+2eDREAM8wV+mWKSkMQKdAp4zXEZfTaxY8PMoNONnpgSWcBCyLDPDOKg== + +"@biomejs/cli-linux-x64-musl@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.7.tgz#2a21980331ef492601ef6c8e439953395f19bce1" + integrity sha512-rE5VZi+qtmPgQH+l7jVxYoZ18b/TiHEhulhMpjmCZH1PltSbjRcxNWywC3HZ9tYottG7ORkeTtoscBilKSBm0g== + +"@biomejs/cli-linux-x64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.7.tgz#f4511c8ca02d8d0a86d0b0d688b90aa2ad0d14ce" + integrity sha512-FQgqJhscrqJUFptGaRSUJWlXAExwWcDwLuK49dvKfkQ1bB5SEEyFssnsxQY83Xm6jR0EbbX3+8+D5bfvYqUG2Q== + +"@biomejs/cli-win32-arm64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.7.tgz#b827341236d6914f83777857d6b16ee7734143cf" + integrity sha512-Oq4x0CCwP4jirrcTywXs5kOGZ4v5vuEP+gWrbtjApOA2CL9F3F9GlIdQIci8AKSCa/zURanMRpX/4wQ7Am6hHg== + +"@biomejs/cli-win32-x64@2.5.7": + version "2.5.7" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.7.tgz#aba3fa4705d963ff8c89f26ab5d4534f8f963c96" + integrity sha512-V+0wu/nrj2S+MhP4EQ0uHNolP0IALEsz45pg0WoKkHfDeh0+ItHwP/p7bX5RPoMOl9NkpHYWdYPhIcy2mACHvQ== "@braintree/sanitize-url@^7.1.1": version "7.1.2" @@ -1756,10 +1766,10 @@ "@docsearch/core" "4.6.2" "@docsearch/css" "4.6.2" -"@docusaurus/babel@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.10.1.tgz#2f714f682117658ba43d308e9b35b6a73a105227" - integrity sha512-DZzFO1K3v/GoEt1fx1DiYHF4en+PuhtQf1AkQJa5zu3CoeKSpr5cpQRUlz3jr0m44wyzmSXu9bVpfir+N4+8bg== +"@docusaurus/babel@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.10.2.tgz#4d5f8ac4d16bfe26c06f256687831787edb46e8a" + integrity sha512-aJ1hpGyvfkte3dDAfNbWM4biW4yWZBVz7TIGLZP+v+tWOBgxX3e0N5ZIXHIvmfNNXTI77pcHUx3KmtOk05Ze3Q== dependencies: "@babel/core" "^7.25.9" "@babel/generator" "^7.25.9" @@ -1770,23 +1780,23 @@ "@babel/preset-typescript" "^7.25.9" "@babel/runtime" "^7.25.9" "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.10.1" - "@docusaurus/utils" "3.10.1" + "@docusaurus/logger" "3.10.2" + "@docusaurus/utils" "3.10.2" babel-plugin-dynamic-import-node "^2.3.3" fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/bundler@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.10.1.tgz#82fa5079f3787a67502e25f82d37d05ec5de0cc3" - integrity sha512-HIqQPvbqnnQRe4NsBd1774KRarjXqS6wHsWELtyuSs1gCfvixJO2jUGH/OEBtr1Gvzpw+ze5CjGMvSJ8UE1KUw== +"@docusaurus/bundler@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.10.2.tgz#323492eb0550b6a7f6e5fa6b9877cdb2c53b1be3" + integrity sha512-i0ZNcy0f0WhaOlYVgzLsWhIoEXO9kS3HRoKPtgE6vQtZUq7arKZaYdNBudr3mqCmd+TyOkwtwfHgs1ENj07r5g== dependencies: "@babel/core" "^7.25.9" - "@docusaurus/babel" "3.10.1" - "@docusaurus/cssnano-preset" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" + "@docusaurus/babel" "3.10.2" + "@docusaurus/cssnano-preset" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" babel-loader "^9.2.1" clean-css "^5.3.3" copy-webpack-plugin "^11.0.0" @@ -1806,18 +1816,18 @@ webpack "^5.95.0" webpackbar "^7.0.0" -"@docusaurus/core@3.10.1", "@docusaurus/core@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.10.1.tgz#3f8bdb97451b4df14f2a3b39ab0186366fbf8fbe" - integrity sha512-3pf2fXXw0eVk8WnC3T4LIigRDupcpvngpKo9Vy7mYyBhuddc0klDUuZAIfzMoK6z05pdlk6EFC/vBSX43+1O5w== - dependencies: - "@docusaurus/babel" "3.10.1" - "@docusaurus/bundler" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" +"@docusaurus/core@3.10.2", "@docusaurus/core@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.10.2.tgz#349cae728fc3769b3f8aef4cf538ccb79aace8d0" + integrity sha512-EYByj6nk+aD9KeVxV6Hmo2/nAAT79P21Y82ycTBOBtrmqilloIbIEhgL2/8Xpt2Jz/pgNqHAwyusOGwmbKeJmA== + dependencies: + "@docusaurus/babel" "3.10.2" + "@docusaurus/bundler" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" boxen "^6.2.1" chalk "^4.1.2" chokidar "^3.5.3" @@ -1825,7 +1835,7 @@ combine-promises "^1.1.0" commander "^5.1.0" core-js "^3.31.1" - detect-port "^1.5.1" + detect-port "^2.1.0" escape-html "^1.0.3" eta "^2.2.0" eval "^0.1.8" @@ -1854,25 +1864,25 @@ webpack-dev-server "^5.2.2" webpack-merge "^6.0.1" -"@docusaurus/cssnano-preset@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.1.tgz#4b6bafeca8bb9423364d2fd6683c28e2f85a4665" - integrity sha512-eNfHGcTKCSq6xmcavAkX3RRclHaE2xRCMParlDXLdXVP01/a2e/jKXMj/0ULnLFQSNwwuI62L0Ge8J+nZsR7UQ== +"@docusaurus/cssnano-preset@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.2.tgz#e3ac7e85585f77e8fdef95176ab7c211d1296630" + integrity sha512-4gCnHRbJLTloiwfvFAa92tgb2gI4KYhvjfQVYnEaiMO/EgvWfCo1LwytHXen+1oZAN0VAlS0JAPxp3MsvKDa3A== dependencies: cssnano-preset-advanced "^6.1.2" postcss "^8.5.4" postcss-sort-media-queries "^5.2.0" tslib "^2.6.0" -"@docusaurus/faster@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/faster/-/faster-3.10.1.tgz#a63d89ae980c98e1eeab3ff15ee083f7c20ed353" - integrity sha512-XTZhE5C1gZ/DaYYMlSk02dwP5vhpQON5QHVz1s3892mSESAywgWanURpXEDAvt4GvGuq7s+XP8rTWHZvfaJmdQ== +"@docusaurus/faster@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/faster/-/faster-3.10.2.tgz#6cacd14085445d5826990f7525c5df1cf371e04a" + integrity sha512-p/5E5/RyHv+QWusJMPN5i3OMJTqTgkhuwzVbB1AReDWTUHXQCmf5mlTFzGiDrWeQWIDOKsuOPn1jJh0s9LUOHA== dependencies: - "@docusaurus/types" "3.10.1" + "@docusaurus/types" "3.10.2" "@rspack/core" "^1.7.10" - "@swc/core" "^1.7.39" - "@swc/html" "^1.13.5" + "@swc/core" "^1.15.40" + "@swc/html" "^1.15.40" browserslist "^4.24.2" lightningcss "^1.27.0" semver "^7.5.4" @@ -1880,22 +1890,22 @@ tslib "^2.6.0" webpack "^5.95.0" -"@docusaurus/logger@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.10.1.tgz#34c964e32e18f120e30f80171a38cfefe72cfb4b" - integrity sha512-oPjNFnfJsRCkePVjkGrxWGq4MvJKRQT0r9jOP0eRBTZ7Wr9FAbzdP/Gjs0I2Ss6YRkPoEgygKG112OkE6skvJw== +"@docusaurus/logger@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.10.2.tgz#280bed53d0eb9cdc56e896a155036207910e89c9" + integrity sha512-gSEwqtPfCAnC3ZSJY6xL7tcIfgg0vFD39jbv93eakuweyvO2864xR0K+kmKwBhkTCtWRNjuGGnb5rdmkD/ndqw== dependencies: chalk "^4.1.2" tslib "^2.6.0" -"@docusaurus/mdx-loader@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.10.1.tgz#050ae9bc614158a4ec07a628aa75fa9ae90d7e82" - integrity sha512-GRmeb/wQ+iXRrFwcHBfgQhrJxGElgCsoTWZYDhccjsZVne1p8MK/EpQVIloXttz76TCe78kKD5AEG9n1xc1oxQ== +"@docusaurus/mdx-loader@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.10.2.tgz#3b4e7ffacff4ed856db2ec4e94c13b0a652d62eb" + integrity sha512-9Fd4V/SFjfrVQ0JH5EN0+iPWyFunvTeQE3gfyFeetqPaXMP0OylIjOw16dCuXG4NZJrYdBqwzjh18/h3gRi47w== dependencies: - "@docusaurus/logger" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/logger" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" "@mdx-js/mdx" "^3.0.0" "@slorber/remark-comment" "^1.0.0" escape-html "^1.0.3" @@ -1918,12 +1928,12 @@ vfile "^6.0.1" webpack "^5.88.1" -"@docusaurus/module-type-aliases@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.1.tgz#22d39177c296786eb6e0d940699cd590cc93ca77" - integrity sha512-YoOZKUdGlp8xSYhuAkGdSo5Ydkbq4V4eK3sD8v0a2hloxCWdQbNBhkc+Ko9QyjpESc0BYcIGM5iHVAy5hdFV6w== +"@docusaurus/module-type-aliases@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.2.tgz#7c3b940c77d72e71d33a1e76f0e003b418e6163a" + integrity sha512-h/I5e4jaAhDHW4vaLENi1i2hnOEnXY1t9R+nnRTbgUl7ymVRzN/HF7dDfj8rKYGj8gfIge+Ef+iYRAMtbGvsrQ== dependencies: - "@docusaurus/types" "3.10.1" + "@docusaurus/types" "3.10.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -1931,19 +1941,19 @@ react-helmet-async "npm:@slorber/react-helmet-async@1.3.0" react-loadable "npm:@docusaurus/react-loadable@6.0.0" -"@docusaurus/plugin-content-blog@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.1.tgz#0bd8de700ccbd8e95d920df2613304ef59abe72b" - integrity sha512-mmkgE6Q2+K74tnkou7tXlpDLvoCU/qkSa2GSQ3XUiHWvcebCoDQzS670RR3tO8PmaWlIyWWISYWzZLuMfxunRA== - dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" +"@docusaurus/plugin-content-blog@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.2.tgz#2374886ec3d76e8f014e85db8c3c010de6c419be" + integrity sha512-0cbEnNKf0InmLkhj/+nVRmqEnWEoOE8Mh+2x1qOXI0qYpCnphq4RXknVJ8BvybKRXqYVvbmdMfiJSup+k4tm5w== + dependencies: + "@docusaurus/core" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" cheerio "1.0.0-rc.12" combine-promises "^1.1.0" feed "^4.2.2" @@ -1956,20 +1966,20 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-docs@3.10.1", "@docusaurus/plugin-content-docs@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.1.tgz#261e0e982e4a937c05b462e3c5729374f433b752" - integrity sha512-2jRVrtzjf8LClGTHQlwlwuD3wQXRx3WEoF7XUarJ8Ou+0onV+SLtejsyfY9JLpfUh9hPhXM4pbBGkyAY4Bi3HQ== - dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/module-type-aliases" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" +"@docusaurus/plugin-content-docs@3.10.2", "@docusaurus/plugin-content-docs@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.2.tgz#249bbc806437f227b06410ecc771eb67d8910a9a" + integrity sha512-Sqwl4FPoZBDrlY8I2VU2H8O0M91CHp9T8ToMSkTZmjvHCif+1laqfXi6sTk8IfyVS/trN5yNjcWd1bFsGB6W5Q== + dependencies: + "@docusaurus/core" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/module-type-aliases" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" "@types/react-router-config" "^5.0.7" combine-promises "^1.1.0" fs-extra "^11.1.1" @@ -1980,142 +1990,141 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-pages@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.1.tgz#8c6ffc2079ed0262548ecc4df1dea6add6aa9673" - integrity sha512-huJpaRPMl42nsFwuCXvV8bVDj2MazuwRJIUylI/RSlmZeJssVoZXeCjVf1y+1Drtpa9SKcdGn8yoJ76IRJijtw== +"@docusaurus/plugin-content-pages@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.2.tgz#377c11b36a6a5e0c0c14dd9dea799f986d662ed7" + integrity sha512-h5R12sZ/vV9EPiVjvIl9YFCOwkpwXes7dQMYt3EvP6Pphu4amHxxTqWxf08Fl5DR8h+oZMbWpFTNw5vKEYfvzQ== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" fs-extra "^11.1.1" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/plugin-css-cascade-layers@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.1.tgz#440578d95cbe1a6120936fa83df868d2626cd1d8" - integrity sha512-r//fn+MNHkE1wCof8T29VAQezt1enGCpsFxoziBbvLgBM4JfXN2P3rxrBaavHmvLvm7lYkpJeitcDthwnmWCTw== +"@docusaurus/plugin-css-cascade-layers@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.2.tgz#54edc6450b0bb95be5990ea416b4c4dc5e6bdde0" + integrity sha512-UkdvQby5OQUKWrw3lLnSTJXQ6VETaUVTuPQX9AABtmFm5h+ifEBx1OQ+LN726Q4byuwBf2ElHkf4qU4hTxdvRg== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" tslib "^2.6.0" -"@docusaurus/plugin-debug@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.10.1.tgz#b8b7b24d9a7d185fd8a56a030f90145d3bfd8239" - integrity sha512-9KqOpKNfAyqGZykRb9LhIT/vyRF6sm/ykhjj/39JvaJahDS+jZJE0Z1Wfz9q3DUNDTMNN0Q7u/kk4rKKU+IJuA== +"@docusaurus/plugin-debug@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.10.2.tgz#2452f258668bb2514085d2d5fff700457c531aad" + integrity sha512-8vbZNOSCpnsT57EY6CgN7sgRVmx3KTYwO8Uvo2pbxOyb8tbqAwtT9SslqaQ41HbA1v1hpn5RP7u5s2KvRwAFpQ== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" fs-extra "^11.1.1" react-json-view-lite "^2.3.0" tslib "^2.6.0" -"@docusaurus/plugin-google-analytics@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.1.tgz#ac15afc77386e0352edb8a1698d993aa5de36ffc" - integrity sha512-8o0P1KtmgdYQHH+oInitPpRWI0Of5XednAX4+DMhQNSmGSRNrsEEHg1ebv35m9AgRClfAytCJ5jA9KvcASTyuA== +"@docusaurus/plugin-google-analytics@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.2.tgz#7a0375c5a238cd9220166d9be8afc00ba508c55d" + integrity sha512-kMHMBK9j4VAtgd5owwrRLRIi0EjkrpXlX7ePj1+y68XfVZV9I1T4S+koPDm+Hfw2TtnyHvh0uNrDvjz+DjQGVA== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" tslib "^2.6.0" -"@docusaurus/plugin-google-gtag@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.1.tgz#0482b83b9bc411aa99a432be2b39d2e53a00e2e0" - integrity sha512-pu3xIUo5o/zCMLfUY9BO5KOwSH0zIsAGyFRPvXHayFSA5XIhCU/SFuB0g0ZNjFn9niZLCaNvoeAuOGFJZq0fdw== +"@docusaurus/plugin-google-gtag@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.2.tgz#65df25eb5fb3f2a3f2d0fba8ddd423060e09e1ca" + integrity sha512-Vt90nNFhtAChRe9+it1hcHFgFvETdSnOkL5Bma+p6E/yU2tAYrvvyk+gv+LJGM2ZUkyKuKXLRsZ2Lb0bO7+Vog== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" - "@types/gtag.js" "^0.0.20" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" tslib "^2.6.0" -"@docusaurus/plugin-google-tag-manager@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.1.tgz#eaf5765d6f82b4fb661d92a793d1883f9d1ec106" - integrity sha512-f6fyGHiCm7kJHBtAisGQS5oNBnpnMTYQZxDXeVrnw/3zWU+LMA22pr6UHGYkBKDbN+qPC5QHG3NuOfzQLq3+Lw== +"@docusaurus/plugin-google-tag-manager@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.2.tgz#882a24e51dc42487d2c1d4f2cde3f59c99a276cb" + integrity sha512-MLCffCldysi/R0nzJQP7ZWd0xAoGNnSTiVOo6TTR6mKVGFhE+/XArGe67ZcaZv1uytgQXoXs92VJrgVDrz80rQ== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" tslib "^2.6.0" -"@docusaurus/plugin-sitemap@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.1.tgz#66a6974bb2fd1b9d8f5cb0f3c5ecd2201c118565" - integrity sha512-C26MbmmqgdjkDq1htaZ3aD7LzEDKFWXfpyQpt0EOUThuq5nV77zDaedV20yHcVo9p+3ey9aZ4pbHA0D3QcZTzg== - dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" +"@docusaurus/plugin-sitemap@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.2.tgz#6c662c7df3bb7d36887f8b73f54d85dc4d36371d" + integrity sha512-PODkwg5XetLML3hU/3xpCKJUZ9cqExLaBnD/Fzzwj2VHogLeqnDisLIujae87zuze7T4mCm2A6KEqZkyiz07EQ== + dependencies: + "@docusaurus/core" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" fs-extra "^11.1.1" sitemap "^7.1.1" tslib "^2.6.0" -"@docusaurus/plugin-svgr@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.1.tgz#c217c24d6d23fd2bc6f54d44c040635b49d6b36e" - integrity sha512-6SFxsmjWFkVLDmBUvFK6i72QjUwqyQFe4Ovz+SUJophJjOyVG3ZZG5IQpBC/kX/Gfv1yWeU9nWauH6F6Q7QX/Q== +"@docusaurus/plugin-svgr@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.2.tgz#916fd0a5d39bf73cb621de9789cce243a7ef1754" + integrity sha512-JgfT3jWM0TJ8Uw0cEcqxHpybngQY1vlBYpuuNO+gEh5iPh5Ar+vxq/u9CFrYsWeXy48BN7Db76Pzp2edNXUQ8A== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" "@svgr/core" "8.1.0" "@svgr/webpack" "^8.1.0" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/preset-classic@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.10.1.tgz#faf330d96aedc9083a59bec09d966ae4dfc8b2fb" - integrity sha512-YO/FL8v1zmbxoTso6mjMz/RDjhaTJxb1UpFFTDdY5847LLDCeyYiYlrhyTbgN1RIN3xnkLKZ9Lj1x8hUzI4JOg== - dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/plugin-content-blog" "3.10.1" - "@docusaurus/plugin-content-docs" "3.10.1" - "@docusaurus/plugin-content-pages" "3.10.1" - "@docusaurus/plugin-css-cascade-layers" "3.10.1" - "@docusaurus/plugin-debug" "3.10.1" - "@docusaurus/plugin-google-analytics" "3.10.1" - "@docusaurus/plugin-google-gtag" "3.10.1" - "@docusaurus/plugin-google-tag-manager" "3.10.1" - "@docusaurus/plugin-sitemap" "3.10.1" - "@docusaurus/plugin-svgr" "3.10.1" - "@docusaurus/theme-classic" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/theme-search-algolia" "3.10.1" - "@docusaurus/types" "3.10.1" - -"@docusaurus/theme-classic@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.10.1.tgz#deed8cf73cc0f56113e53775cbb3b168c3c61566" - integrity sha512-VU1RK0qb2pab0si4r7HFK37cYco8VzqLj3u1PspVipSr/z/GPVKHO4/HXbnePqHoWDk8urjyGSeatH0NIMBM1A== - dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/module-type-aliases" "3.10.1" - "@docusaurus/plugin-content-blog" "3.10.1" - "@docusaurus/plugin-content-docs" "3.10.1" - "@docusaurus/plugin-content-pages" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/theme-translations" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" +"@docusaurus/preset-classic@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.10.2.tgz#e4419c811723ab913a946c63efcc15e7f5f60a0a" + integrity sha512-a4B3VczmDl99zK0EufDQYomdJ186WDingjmDXxhN2PNPS9Ty/Y2M5CLFX1KQMRKqRTLiRDKfutzG5IY1FC/ceg== + dependencies: + "@docusaurus/core" "3.10.2" + "@docusaurus/plugin-content-blog" "3.10.2" + "@docusaurus/plugin-content-docs" "3.10.2" + "@docusaurus/plugin-content-pages" "3.10.2" + "@docusaurus/plugin-css-cascade-layers" "3.10.2" + "@docusaurus/plugin-debug" "3.10.2" + "@docusaurus/plugin-google-analytics" "3.10.2" + "@docusaurus/plugin-google-gtag" "3.10.2" + "@docusaurus/plugin-google-tag-manager" "3.10.2" + "@docusaurus/plugin-sitemap" "3.10.2" + "@docusaurus/plugin-svgr" "3.10.2" + "@docusaurus/theme-classic" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/theme-search-algolia" "3.10.2" + "@docusaurus/types" "3.10.2" + +"@docusaurus/theme-classic@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.10.2.tgz#a64bd600c789b33c67c30c256b07e2ca0f57e2ae" + integrity sha512-JqTSLQmqmA9uKWZsD5iwBGJ4JyKB4/yTw6PsSXVPRJG/6GAm/u+add9Iip+hvwP12/AnPNztrdxsI14NJW4KeA== + dependencies: + "@docusaurus/core" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/module-type-aliases" "3.10.2" + "@docusaurus/plugin-content-blog" "3.10.2" + "@docusaurus/plugin-content-docs" "3.10.2" + "@docusaurus/plugin-content-pages" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/theme-translations" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" "@mdx-js/react" "^3.0.0" clsx "^2.0.0" copy-text-to-clipboard "^3.2.0" @@ -2130,15 +2139,15 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-common@3.10.1", "@docusaurus/theme-common@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.10.1.tgz#cbfec82b1b107be5c229811ed9caae14a501361c" - integrity sha512-0YtmIeoNo1fIw65LO8+/1dPgmDV86UmhMkow37gzjytuiCSQm9xob6PJy0L4kuQEMTLfUOGvkXvZr7GPrHquMA== +"@docusaurus/theme-common@3.10.2", "@docusaurus/theme-common@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.10.2.tgz#5cf2a8b76554b8b38c6afe8448470c411f683e5b" + integrity sha512-R9b/vMpK1yye6hNZTA6x/ivRv+at6GhxnXcxkpzCGzO1R1RwiquqiFg2wMFh6aqlJTpWRFKpFD2TzCDQcyOU0A== dependencies: - "@docusaurus/mdx-loader" "3.10.1" - "@docusaurus/module-type-aliases" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" + "@docusaurus/mdx-loader" "3.10.2" + "@docusaurus/module-type-aliases" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -2148,33 +2157,33 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-mermaid@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-mermaid/-/theme-mermaid-3.10.1.tgz#dada9c50c780524d246906234ace8a35446f26fc" - integrity sha512-2gxpmln8Pc4EN1oWzshQEx2HTs67jk14v7MmgqGs8ZU7Nm8oihg+fTouof2u4vN8DtB3Fln4cDJu4UprSX1S3Q== +"@docusaurus/theme-mermaid@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-mermaid/-/theme-mermaid-3.10.2.tgz#826e47a01fefbe49fdbb0f4f575c9399d3ccd92c" + integrity sha512-Stssh5MYQJ+EdYugUXf+ZcpeJFQPKXf0KCd/SWp10o3CmXNaOoh5IEgVjVqY1e1XhQf3on4+Y4BnrMiD95E2SQ== dependencies: - "@docusaurus/core" "3.10.1" - "@docusaurus/module-type-aliases" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/module-type-aliases" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" mermaid ">=11.6.0" tslib "^2.6.0" -"@docusaurus/theme-search-algolia@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.1.tgz#6f422058711629ce8d7c2f17e1e54efa075c626e" - integrity sha512-OTaARARVZj2GvkJQjB+1jOIxntRaXea+G+fMsNqrZBAU1O1vJKDW22R7kECOHW27oJCLFN9HKaZeRrfAUyviug== +"@docusaurus/theme-search-algolia@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.2.tgz#e7756d4088a7df4d11fd734bfe0e8fa28ceac1dd" + integrity sha512-1msxllyhi/5m77JukXtp5UFnUAriwZIC1oJ7MTnpQpCwLTbclJi5BK5n28CTZuSXpQN2ewbbnqRgAhMM6c6ihg== dependencies: "@algolia/autocomplete-core" "^1.19.2" "@docsearch/react" "^3.9.0 || ^4.3.2" - "@docusaurus/core" "3.10.1" - "@docusaurus/logger" "3.10.1" - "@docusaurus/plugin-content-docs" "3.10.1" - "@docusaurus/theme-common" "3.10.1" - "@docusaurus/theme-translations" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-validation" "3.10.1" + "@docusaurus/core" "3.10.2" + "@docusaurus/logger" "3.10.2" + "@docusaurus/plugin-content-docs" "3.10.2" + "@docusaurus/theme-common" "3.10.2" + "@docusaurus/theme-translations" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-validation" "3.10.2" algoliasearch "^5.37.0" algoliasearch-helper "^3.26.0" clsx "^2.0.0" @@ -2184,18 +2193,18 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-translations@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.10.1.tgz#c3119a015652290eea560ca45ac775963d6eb75b" - integrity sha512-cLMyaKivjBVWKMJuWqyFVVgtqe8DPJNPkog0bn8W1MDVAKcPdxRFycBfC1We1RaNp7Rdk513bmtW78RR6OBxBw== +"@docusaurus/theme-translations@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.10.2.tgz#cd649083babd12df324e7129008aaccacd4cfb13" + integrity sha512-iv20wrxnyXkY89LM3TzRlzGlt5fIGO5UnaR6UL1ZVfB9RRFjxQFQ6awDrwAc6Km8Y5gD8pInuwYPF+6/TiCxXA== dependencies: fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/types@3.10.1", "@docusaurus/types@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.10.1.tgz#d42837938ae43ca2be0ca47e63e00476b5eb94be" - integrity sha512-XYMK8k1szDCFMw2V+Xyen0g7Kee1sP3dtFnl7vkGkZOkeAJ/oPDQPL8iz4HBKOo/cwU8QeV6onVjMqtP+tFzsw== +"@docusaurus/types@3.10.2", "@docusaurus/types@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.10.2.tgz#9ffe35adfb4587e49158ee9e10d94b86419a5932" + integrity sha512-B6rvfwIFSapUqUJjMriZswX13K8l5Z7AcmVE6uTEJpYddQieSTR12DsGaFtcZAIDsQd4p+0WTl0Vc6jmZK0Trw== dependencies: "@mdx-js/mdx" "^3.0.0" "@types/history" "^4.7.11" @@ -2208,43 +2217,43 @@ webpack "^5.95.0" webpack-merge "^5.9.0" -"@docusaurus/utils-common@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.10.1.tgz#6350b4898691e765de750f90eade0e0fa7902d99" - integrity sha512-5mFSgEADtnFxFH7RLw02QA5MpU5JVUCj0MPeIvi/aF4Fi45tQRIuTwXoXDqJ+1VfQJuYJGz3SI63wmGz4HvXzA== +"@docusaurus/utils-common@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.10.2.tgz#a65fcfffafa4e15a59fe61d7ba315ee5d4c49269" + integrity sha512-x3Dz6jv6iQKBNjBmVTu8p57abMp/VNTUgKBMgRVXJc5444orBTsArv0+cdfrXTiz/VMmHfDRVkPbL7GH2B7T7w== dependencies: - "@docusaurus/types" "3.10.1" + "@docusaurus/types" "3.10.2" tslib "^2.6.0" -"@docusaurus/utils-validation@3.10.1", "@docusaurus/utils-validation@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.10.1.tgz#ddbcce997a5506424cdd16abf6845cc51692acae" - integrity sha512-cRv1X69jwaWv47waglllgZVWzeBFLhl53XT/XED/83BerVBTC5FTP8WTcVl8Z6sZOegDSwitu/wpCSPCDOT6lg== +"@docusaurus/utils-validation@3.10.2", "@docusaurus/utils-validation@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.10.2.tgz#2624b0ca6675675da2f063828115b43c9a22de47" + integrity sha512-sn8unbDfUL585NtR3cwHefPicOyaHvPaX7VD0aOg/siIxUBoKyKKaGEqzJZDS64mM43TnxurkYDtmB1wsJlZsw== dependencies: - "@docusaurus/logger" "3.10.1" - "@docusaurus/utils" "3.10.1" - "@docusaurus/utils-common" "3.10.1" + "@docusaurus/logger" "3.10.2" + "@docusaurus/utils" "3.10.2" + "@docusaurus/utils-common" "3.10.2" fs-extra "^11.2.0" joi "^17.9.2" js-yaml "^4.1.0" lodash "^4.17.21" tslib "^2.6.0" -"@docusaurus/utils@3.10.1", "@docusaurus/utils@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.10.1.tgz#535968caa2c9bff69f997a081b98b95b3c5d3785" - integrity sha512-3ojeJry9xBYdJO6qoyyzqeJFSJBVx2mXhyDzSdjwL2+URFQMf+h25gG38iswGImicK0ELjTd1EL2xzk8hf3QPw== +"@docusaurus/utils@3.10.2", "@docusaurus/utils@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.10.2.tgz#d99c1ffc5c7961e912344269a8728ce2aad8b3dc" + integrity sha512-xx0W3eav2uW1NRIpuHJWNwLTC15xPNjU4Uxi9NSnd3swYC96BE3vFiT93SD8s24kmAAWNwgZwfZ2fghGZ01Lcw== dependencies: - "@docusaurus/logger" "3.10.1" - "@docusaurus/types" "3.10.1" - "@docusaurus/utils-common" "3.10.1" + "@11ty/gray-matter" "^1.0.0" + "@docusaurus/logger" "3.10.2" + "@docusaurus/types" "3.10.2" + "@docusaurus/utils-common" "3.10.2" escape-string-regexp "^4.0.0" execa "^5.1.1" file-loader "^6.2.0" fs-extra "^11.1.1" github-slugger "^1.5.0" globby "^11.1.0" - gray-matter "^4.0.3" jiti "^1.20.0" js-yaml "^4.1.0" lodash "^4.17.21" @@ -2644,13 +2653,13 @@ lodash "~4.17.0" tslib "~2.6.0" -"@graphql-codegen/plugin-helpers@latest": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.3.0.tgz#d4ba4660c68cb703291fbc6616a6510df26dd5f3" - integrity sha512-Auc+/B7okDx9+pVgLVliZtZLYh6iltWXlnzzM+bRE+zh1T4r3hKbnr8xAmtT937ArfSgk5GHcQHr8LfPYnrRBg== +"@graphql-codegen/plugin-helpers@^7.0.1": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-7.1.0.tgz#cc28ad447ae8fc8be6a49f7eb0166910dff0aca0" + integrity sha512-ieJH7kZ5oSZKBPJs7CvHMrFY/CLYLklqv74ir93qMwRna6geZsbIMoJzTDBXohxcQTITiProiYSGrEtZjIpYGg== dependencies: - "@graphql-tools/utils" "^11.0.0" - change-case-all "1.0.15" + "@graphql-tools/utils" "^11.2.0" + change-case-all "^2.1.0" common-tags "1.8.2" import-from "4.0.0" tslib "^2.8.0" @@ -2911,7 +2920,7 @@ cross-inspect "1.0.1" tslib "^2.4.0" -"@graphql-tools/utils@^11.0.0", "@graphql-tools/utils@^11.0.1": +"@graphql-tools/utils@^11.0.1": version "11.0.1" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-11.0.1.tgz#68705689e106cb21da838cf30e64ae9ad85982b4" integrity sha512-pNyCOb95ab/z3zkkiPwIPYxigX7IcpyFVcgD1XACDEvg/7yGnKCESx3k/XHEeneKYx/aWKGzEh/uuf6M6Q8HOw== @@ -2921,6 +2930,16 @@ cross-inspect "1.0.1" tslib "^2.4.0" +"@graphql-tools/utils@^11.2.0": + version "11.2.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-11.2.2.tgz#5e2c8458dc31d856c94cab0a02aabfd9a5e6e616" + integrity sha512-Do2A/t6ayqOma8m7PvpYMsCBswL+NB35BQSng4GWSBqafL2/BnfAZy/NSENPwV721Rm2fG0BHETFC0+FJJZmLw== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@whatwg-node/promise-helpers" "^1.0.0" + cross-inspect "1.0.1" + tslib "^2.4.0" + "@graphql-tools/utils@^9.0.0", "@graphql-tools/utils@^9.1.1", "@graphql-tools/utils@^9.2.1": version "9.2.1" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57" @@ -3907,16 +3926,28 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@radix-ui/number@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.1.tgz#7b2c9225fbf1b126539551f5985769d0048d9090" - integrity sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g== +"@radix-ui/number@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.3.tgz#9661c4bb44de93355993e1e09fed4fc8dfa9f7a6" + integrity sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA== "@radix-ui/primitive@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.3.tgz#e2dbc13bdc5e4168f4334f75832d7bdd3e2de5ba" integrity sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg== +"@radix-ui/primitive@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.7.tgz#0d0929d20299f60b0cd8a0deafad79f8048f9306" + integrity sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q== + +"@radix-ui/react-arrow@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz#66658c78e9046b7f6000c1ec23d98dd80e1de58a" + integrity sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-arrow@1.1.7": version "1.1.7" resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz#e14a2657c81d961598c5e72b73dd6098acc04f09" @@ -3924,19 +3955,15 @@ dependencies: "@radix-ui/react-primitive" "2.1.3" -"@radix-ui/react-checkbox@^1.1.4": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz#db45ca8a6d5c056a92f74edbb564acee05318b79" - integrity sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw== +"@radix-ui/react-collection@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.15.tgz#6f045630d6f9778ab1b0c456ae97b474aec8a20b" + integrity sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA== dependencies: - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-compose-refs" "1.1.2" - "@radix-ui/react-context" "1.1.2" - "@radix-ui/react-presence" "1.1.5" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-use-controllable-state" "1.2.2" - "@radix-ui/react-use-previous" "1.1.1" - "@radix-ui/react-use-size" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" "@radix-ui/react-collection@1.1.7": version "1.1.7" @@ -3953,11 +3980,21 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== +"@radix-ui/react-compose-refs@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz#883e642c5ec0ba393dd1bf586e7e772985770d87" + integrity sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA== + "@radix-ui/react-context@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== +"@radix-ui/react-context@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.2.2.tgz#fe2548e98465f5f9b776c5953de35d04a8919b6b" + integrity sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA== + "@radix-ui/react-dialog@^1.0.4", "@radix-ui/react-dialog@^1.1.14", "@radix-ui/react-dialog@^1.1.6": version "1.1.15" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz#1de3d7a7e9a17a9874d29c07f5940a18a119b632" @@ -3978,11 +4015,37 @@ aria-hidden "^1.2.4" react-remove-scroll "^2.6.3" +"@radix-ui/react-dialog@^1.1.18": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz#b7d8e83a3ccf97e46f3c3f477a0bf563f0de8239" + integrity sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" + "@radix-ui/react-direction@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz#39e5a5769e676c753204b792fbe6cf508e550a14" integrity sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw== +"@radix-ui/react-direction@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.4.tgz#e7b7049f3c3ab8e6e014c4600f9f1974a52c05f1" + integrity sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg== + "@radix-ui/react-dismissable-layer@1.1.11": version "1.1.11" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz#e33ab6f6bdaa00f8f7327c408d9f631376b88b37" @@ -3994,7 +4057,18 @@ "@radix-ui/react-use-callback-ref" "1.1.1" "@radix-ui/react-use-escape-keydown" "1.1.1" -"@radix-ui/react-dropdown-menu@^2.0.5", "@radix-ui/react-dropdown-menu@^2.1.6": +"@radix-ui/react-dismissable-layer@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz#ef64a08943bdf04e00996f55472456353014fa68" + integrity sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-effect-event" "0.0.5" + +"@radix-ui/react-dropdown-menu@^2.0.5": version "2.1.16" resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz#5ee045c62bad8122347981c479d92b1ff24c7254" integrity sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw== @@ -4007,11 +4081,38 @@ "@radix-ui/react-primitive" "2.1.3" "@radix-ui/react-use-controllable-state" "1.2.2" +"@radix-ui/react-dropdown-menu@^2.1.19": + version "2.1.24" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.24.tgz#3ed6d50cdacb1e68a5230c13510b6a87131b577b" + integrity sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-menu" "2.1.24" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-focus-guards@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz#2a5669e464ad5fde9f86d22f7fdc17781a4dfa7f" integrity sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw== +"@radix-ui/react-focus-guards@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz#853985fb77fb7f6f65ab2e4750d1cfde9c702e36" + integrity sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ== + +"@radix-ui/react-focus-scope@1.1.16": + version "1.1.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz#1221498b222efaae678a25ae4b81025c5feda195" + integrity sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ== + dependencies: + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-focus-scope@1.1.7": version "1.1.7" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d" @@ -4028,6 +4129,13 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-id@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.4.tgz#e642714bdaf551c1bfacbe51508ed843a3a27980" + integrity sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-menu@2.1.16": version "2.1.16" resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.16.tgz#528a5a973c3a7413d3d49eb9ccd229aa52402911" @@ -4052,26 +4160,50 @@ aria-hidden "^1.2.4" react-remove-scroll "^2.6.3" -"@radix-ui/react-popover@^1.1.15": - version "1.1.15" - resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.15.tgz#9c852f93990a687ebdc949b2c3de1f37cdc4c5d5" - integrity sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA== - dependencies: - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-compose-refs" "1.1.2" - "@radix-ui/react-context" "1.1.2" - "@radix-ui/react-dismissable-layer" "1.1.11" - "@radix-ui/react-focus-guards" "1.1.3" - "@radix-ui/react-focus-scope" "1.1.7" - "@radix-ui/react-id" "1.1.1" - "@radix-ui/react-popper" "1.2.8" - "@radix-ui/react-portal" "1.1.9" - "@radix-ui/react-presence" "1.1.5" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-slot" "1.2.3" - "@radix-ui/react-use-controllable-state" "1.2.2" +"@radix-ui/react-menu@2.1.24": + version "2.1.24" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.24.tgz#cd875e66fb0eb5ec5381132933e0d790d043edcc" + integrity sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-callback-ref" "1.1.4" aria-hidden "^1.2.4" - react-remove-scroll "^2.6.3" + react-remove-scroll "^2.7.2" + +"@radix-ui/react-popover@^1.1.18": + version "1.1.23" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.23.tgz#0d3bfb292d4ac14625022c581029d0e596a52308" + integrity sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + aria-hidden "^1.2.4" + react-remove-scroll "^2.7.2" "@radix-ui/react-popper@1.2.8": version "1.2.8" @@ -4089,6 +4221,30 @@ "@radix-ui/react-use-size" "1.1.1" "@radix-ui/rect" "1.1.1" +"@radix-ui/react-popper@1.3.7": + version "1.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.3.7.tgz#a46002dec97f989e6279453727b1b0ba63691677" + integrity sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-rect" "1.1.4" + "@radix-ui/react-use-size" "1.1.4" + "@radix-ui/rect" "1.1.3" + +"@radix-ui/react-portal@1.1.17": + version "1.1.17" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.17.tgz#f3b60bb5d78f12143e17553c45ed0506b026ec18" + integrity sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-portal@1.1.9": version "1.1.9" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz#14c3649fe48ec474ac51ed9f2b9f5da4d91c4472" @@ -4097,6 +4253,13 @@ "@radix-ui/react-primitive" "2.1.3" "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-presence@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.10.tgz#49041cb9c41c3e8d1791d6b96a1d3bcd8429a151" + integrity sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-presence@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.5.tgz#5d8f28ac316c32f078afce2996839250c10693db" @@ -4105,6 +4268,13 @@ "@radix-ui/react-compose-refs" "1.1.2" "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-primitive@2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz#292b7476499d17227f337c8d1c59f270c683842a" + integrity sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg== + dependencies: + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-primitive@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz#db9b8bcff49e01be510ad79893fb0e4cda50f1bc" @@ -4134,46 +4304,57 @@ "@radix-ui/react-use-callback-ref" "1.1.1" "@radix-ui/react-use-controllable-state" "1.2.2" -"@radix-ui/react-select@^2.2.6": - version "2.2.6" - resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.2.6.tgz#022cf8dab16bf05d0d1b4df9e53e4bea1b744fd9" - integrity sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ== - dependencies: - "@radix-ui/number" "1.1.1" - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-collection" "1.1.7" - "@radix-ui/react-compose-refs" "1.1.2" - "@radix-ui/react-context" "1.1.2" - "@radix-ui/react-direction" "1.1.1" - "@radix-ui/react-dismissable-layer" "1.1.11" - "@radix-ui/react-focus-guards" "1.1.3" - "@radix-ui/react-focus-scope" "1.1.7" - "@radix-ui/react-id" "1.1.1" - "@radix-ui/react-popper" "1.2.8" - "@radix-ui/react-portal" "1.1.9" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-slot" "1.2.3" - "@radix-ui/react-use-callback-ref" "1.1.1" - "@radix-ui/react-use-controllable-state" "1.2.2" - "@radix-ui/react-use-layout-effect" "1.1.1" - "@radix-ui/react-use-previous" "1.1.1" - "@radix-ui/react-visually-hidden" "1.2.3" +"@radix-ui/react-roving-focus@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz#2abc0676448f4ebae8c43a61f9531aebe0f5c823" + integrity sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-is-hydrated" "0.1.3" + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-select@^2.3.2": + version "2.3.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-select/-/react-select-2.3.7.tgz#fc83ddd866decff8ca99e63f093c6e387ad54790" + integrity sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg== + dependencies: + "@radix-ui/number" "1.1.3" + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-collection" "1.1.15" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-focus-guards" "1.1.6" + "@radix-ui/react-focus-scope" "1.1.16" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-callback-ref" "1.1.4" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-previous" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" aria-hidden "^1.2.4" - react-remove-scroll "^2.6.3" - -"@radix-ui/react-separator@1.1.7": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.7.tgz#a18bd7fd07c10fda1bba14f2a3032e7b1a2b3470" - integrity sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA== - dependencies: - "@radix-ui/react-primitive" "2.1.3" + react-remove-scroll "^2.7.2" -"@radix-ui/react-separator@^1.1.2": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.8.tgz#24f871fbf9630af316d0c14cbc7519a6e33aa11e" - integrity sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g== +"@radix-ui/react-separator@1.1.15", "@radix-ui/react-separator@^1.1.11": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.15.tgz#0b59a55ce42f881bda6da45a1cc8069214a8606c" + integrity sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw== dependencies: - "@radix-ui/react-primitive" "2.1.4" + "@radix-ui/react-primitive" "2.1.10" "@radix-ui/react-slot@1.2.3": version "1.2.3" @@ -4182,49 +4363,56 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.2" -"@radix-ui/react-slot@1.2.4", "@radix-ui/react-slot@^1.1.2", "@radix-ui/react-slot@^1.2.0": +"@radix-ui/react-slot@1.2.4", "@radix-ui/react-slot@^1.2.0": version "1.2.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.4.tgz#63c0ba05fdf90cc49076b94029c852d7bac1fb83" integrity sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA== dependencies: "@radix-ui/react-compose-refs" "1.1.2" -"@radix-ui/react-toggle-group@1.1.11": - version "1.1.11" - resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz#e513d6ffdb07509b400ab5b26f2523747c0d51c1" - integrity sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q== - dependencies: - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-context" "1.1.2" - "@radix-ui/react-direction" "1.1.1" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-roving-focus" "1.1.11" - "@radix-ui/react-toggle" "1.1.10" - "@radix-ui/react-use-controllable-state" "1.2.2" - -"@radix-ui/react-toggle@1.1.10": - version "1.1.10" - resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz#b04ba0f9609599df666fce5b2f38109a197f08cf" - integrity sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ== - dependencies: - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-use-controllable-state" "1.2.2" - -"@radix-ui/react-toolbar@^1.1.2": - version "1.1.11" - resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz#2a71f1d91535788f88145d542159e2faaa561db7" - integrity sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg== - dependencies: - "@radix-ui/primitive" "1.1.3" - "@radix-ui/react-context" "1.1.2" - "@radix-ui/react-direction" "1.1.1" - "@radix-ui/react-primitive" "2.1.3" - "@radix-ui/react-roving-focus" "1.1.11" - "@radix-ui/react-separator" "1.1.7" - "@radix-ui/react-toggle-group" "1.1.11" - -"@radix-ui/react-tooltip@^1.0.6", "@radix-ui/react-tooltip@^1.2.8": +"@radix-ui/react-slot@1.3.3", "@radix-ui/react-slot@^1.3.0": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.3.3.tgz#ccc8c8936fff12f7e324d6917fe5167357097676" + integrity sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q== + dependencies: + "@radix-ui/react-compose-refs" "1.1.5" + +"@radix-ui/react-toggle-group@1.1.19": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.19.tgz#cefc32db4e117e5a15812bb944676a4d14d9e59b" + integrity sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-toggle" "1.1.18" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-toggle@1.1.18": + version "1.1.18" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.1.18.tgz#3b464b235e76193142d9ea276611a9c8ef3babc7" + integrity sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-use-controllable-state" "1.2.6" + +"@radix-ui/react-toolbar@^1.1.14": + version "1.1.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.1.19.tgz#91add5b6fa994cb79b0a857d57ab08bfa472f079" + integrity sha512-Ph0IvtYw4VB12ZnZg+YtrGs8yJQsnizwo/zu0R4Y/nWugtJzA7Pg1eWeuDR9+LSqn+xjamss+UOSOJJJ4gx8jw== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-direction" "1.1.4" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-roving-focus" "1.1.19" + "@radix-ui/react-separator" "1.1.15" + "@radix-ui/react-toggle-group" "1.1.19" + +"@radix-ui/react-tooltip@^1.0.6": version "1.2.8" resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz#3f50267e25bccfc9e20bb3036bfd9ab4c2c30c2c" integrity sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg== @@ -4242,11 +4430,35 @@ "@radix-ui/react-use-controllable-state" "1.2.2" "@radix-ui/react-visually-hidden" "1.2.3" +"@radix-ui/react-tooltip@^1.2.11": + version "1.2.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.2.16.tgz#b38fc8475b4d5619b0f50fa057390b278a5d4e69" + integrity sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.5" + "@radix-ui/react-context" "1.2.2" + "@radix-ui/react-dismissable-layer" "1.1.19" + "@radix-ui/react-id" "1.1.4" + "@radix-ui/react-popper" "1.3.7" + "@radix-ui/react-portal" "1.1.17" + "@radix-ui/react-presence" "1.1.10" + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-slot" "1.3.3" + "@radix-ui/react-use-controllable-state" "1.2.6" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-visually-hidden" "1.2.11" + "@radix-ui/react-use-callback-ref@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== +"@radix-ui/react-use-callback-ref@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz#1e55d37148e60a3f47de4bc7ea7cff6fa3f425ae" + integrity sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ== + "@radix-ui/react-use-controllable-state@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz#905793405de57d61a439f4afebbb17d0645f3190" @@ -4255,6 +4467,15 @@ "@radix-ui/react-use-effect-event" "0.0.2" "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-use-controllable-state@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz#0f109eff004c3c1ff5f9709570f45dee9955513e" + integrity sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ== + dependencies: + "@radix-ui/primitive" "1.1.7" + "@radix-ui/react-use-effect-event" "0.0.5" + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-effect-event@0.0.2": version "0.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" @@ -4262,6 +4483,13 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-use-effect-event@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz#7732a4ae6bc032c7f654e658203df92d3520f8d1" + integrity sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + "@radix-ui/react-use-escape-keydown@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29" @@ -4269,15 +4497,25 @@ dependencies: "@radix-ui/react-use-callback-ref" "1.1.1" +"@radix-ui/react-use-is-hydrated@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.3.tgz#f0ffa47394726046ba6c6d0b7c97239f48c8df45" + integrity sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw== + "@radix-ui/react-use-layout-effect@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== -"@radix-ui/react-use-previous@1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz#1a1ad5568973d24051ed0af687766f6c7cb9b5b5" - integrity sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ== +"@radix-ui/react-use-layout-effect@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz#51a0bbc342315070983383b3f8f00061083782a8" + integrity sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw== + +"@radix-ui/react-use-previous@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.4.tgz#4a2789c168d85a78e51f812c3e9727ef01d302da" + integrity sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg== "@radix-ui/react-use-rect@1.1.1": version "1.1.1" @@ -4286,6 +4524,13 @@ dependencies: "@radix-ui/rect" "1.1.1" +"@radix-ui/react-use-rect@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz#9d68dd1d149a0af4f228c5c9ae4646d3ceaa0e2a" + integrity sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ== + dependencies: + "@radix-ui/rect" "1.1.3" + "@radix-ui/react-use-size@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz#6de276ffbc389a537ffe4316f5b0f24129405b37" @@ -4293,6 +4538,20 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-use-size@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz#2d6d0a97a5cd11a76f4f09984239d9e26c59ce4e" + integrity sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.4" + +"@radix-ui/react-visually-hidden@1.2.11": + version "1.2.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz#3e02aebf825d74042d1b863a20ccc67316b78e7b" + integrity sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ== + dependencies: + "@radix-ui/react-primitive" "2.1.10" + "@radix-ui/react-visually-hidden@1.2.3": version "1.2.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz#a8c38c8607735dc9f05c32f87ab0f9c2b109efbf" @@ -4312,6 +4571,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.1.tgz#78244efe12930c56fd255d7923865857c41ac8cb" integrity sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw== +"@radix-ui/rect@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.3.tgz#5a58fbae3deefb7f8cfe6ea314287d699eb694a9" + integrity sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw== + "@react-aria/focus@^3.17.1": version "3.21.5" resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.21.5.tgz#1d9692f9ac97057be83a5878382d1ddd3e443500" @@ -4784,86 +5048,86 @@ "@svgr/plugin-jsx" "8.1.0" "@svgr/plugin-svgo" "8.1.0" -"@swc/core-darwin-arm64@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.24.tgz#e812659bb23c5a078c05c8b18aad25e9d3a12e39" - integrity sha512-uM5ZGfFXjtvtJ+fe448PVBEbn/CSxS3UAyLj3O9xOqKIWy3S6hPTXSPbszxkSsGDYKi+YFhzAsR4r/eXLxEQ0g== - -"@swc/core-darwin-x64@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.24.tgz#99e38bdb00a6975d54471f77c345b4ee9bbb4502" - integrity sha512-fMIb/Zfn929pw25VMBhV7Ji2Dl+lCWtUPNdYJQYOke+00E5fcQ9ynxtP8+qhUo/HZc+mYQb1gJxwHM9vty+lXg== - -"@swc/core-linux-arm-gnueabihf@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.24.tgz#3555ef64268825e4975409b7ed3e9f614e2f9759" - integrity sha512-vOkjsyjjxnoYx3hMEWcGxQrMgnNrRm6WAegBXrN8foHtDAR+zpdhpGF5a4lj1bNPgXAvmysjui8cM1ov/Clkaw== - -"@swc/core-linux-arm64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.24.tgz#15677103362e56826bb8bc4e15090228f81ef448" - integrity sha512-h/oNu+upkXJ6Cicnq7YGVj9PkdfarLCdQa8l/FlHYvfv8CEiMaeeTnpLU7gSBH/rGxosM6Qkfa/J9mThGF9CLA== - -"@swc/core-linux-arm64-musl@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.24.tgz#d1655edac4d0101b9c21193770fb8642ced7ef37" - integrity sha512-ZpF/pRe1guk6sKzQI9D1jAORtjTdNlyeXn9GDz8ophof/w2WhojRblvSDJaGe7rJjcPN8AaOkhwdRUh7q8oYIg== - -"@swc/core-linux-ppc64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.24.tgz#65dc9265686cc24a63d5d8a41a01efe432993181" - integrity sha512-QZEsZfisHTSJlmyChgDFNmKPb3W6Lhbfo/O76HhIngfEdnQNmukS38/VSe1feho+xkV5A5hETyCbx3sALBZKAQ== - -"@swc/core-linux-s390x-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.24.tgz#89c575dbfa39fde1d83033bf4d13e1bf93c93f45" - integrity sha512-DLdJKVsJgglqQrJBuoUYNmzm3leI7kUZhLbZGHv42onfKsGf6JDS3+bzCUQfte/XOqDjh/tmmn1DR/CF/tCJFw== - -"@swc/core-linux-x64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.24.tgz#5275c0b24b01b26fdb7a1b5da6bd062d94f9581f" - integrity sha512-IpLYfposPA/XLxYOKpRfeccl1p5dDa3+okZDHHTchBkXEaVCnq5MADPmIWwIYj1tudt7hORsEHccG5no6IUQRw== - -"@swc/core-linux-x64-musl@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.24.tgz#e65e6f0d7215ded63c0711c2284fe13127772209" - integrity sha512-JHy3fMSc0t/EPWgo74+OK5TGr51aElnzqfUPaiRf2qJ/BfX5CUCfMiWVBuhI7qmVMBnk1jTRnL/xZnOSHDPLYg== - -"@swc/core-win32-arm64-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.24.tgz#12dff91f148bc4e2e48d7990f175f108199f6f0d" - integrity sha512-Txj+qUH1z2bUd1P3JvwByfjKFti3cptlAxhWgmunBUUxy/IW3CXLZ6l6Gk4liANadKkU71nIU1X30Z5vpMT3BA== - -"@swc/core-win32-ia32-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.24.tgz#eb3747533a3c078bfee5d857b086774647506a4a" - integrity sha512-15D/nl3XwrhFpMv+MADFOiVwv3FvH9j8c6Rf8EXBT3Q5LoMh8YnDnSgPYqw1JzPnksvsBX6QPXLiPqmcR/Z4qQ== - -"@swc/core-win32-x64-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.24.tgz#a0ad3bb9b8755093efe656299aa167138a589708" - integrity sha512-PR0PlTlPra2JbaDphrOAzm6s0v9rA0F17YzB+XbWD95B4g2cWcZY9LAeTa4xll70VLw9Jr7xBrlohqlQmelMFQ== - -"@swc/core@^1.7.39": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.24.tgz#258dd1f74c662d9a2535fcfa2aa8ff30fd23883d" - integrity sha512-5Hj8aNasue7yusUt8LGCUe/AjM7RMAce8ZoyDyiFwx7Al+GbYKL+yE7g4sJk8vEr1dKIkTRARkNIJENc4CjkBQ== +"@swc/core-darwin-arm64@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.47.tgz#345ce6a1bf4033da189c2e3eff1244190195d15b" + integrity sha512-GsoMtan3ojGGMGFbl31mmRu5ctZ56re8grGE8mO/OHJ8O+JRkzod02fe7X6ZQ8JvamA3imkEkx/h3u+vsOgPgA== + +"@swc/core-darwin-x64@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.47.tgz#f3debf50b5c1602bf392acb412bd33fd6d7e4f98" + integrity sha512-leTi7Rx3KF4zcC637iqWgk9SoV8VXAD8ppQYXsep63px5A/UftOcxLN1pmr8Z1si/YvX90ompP/rHgpYkgwXWg== + +"@swc/core-linux-arm-gnueabihf@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.47.tgz#14a247a12c6d3de1ee63fa4fdbf5a4302936b5d6" + integrity sha512-hBqHuoWKKIsKmDBn9qVeWqj5GWZhtlcczVaqQmNRXsDfq+voR5CxKRfamA367QjJXtceYuliLFfEL8QsskRM2g== + +"@swc/core-linux-arm64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.47.tgz#3b8d09c481ae51c7b72d98fb6ce98f7b90065a1a" + integrity sha512-TBxvRz+B4K205TWHHZxWVxkC2RFNP/Mz3PNcECBos5PsKwxjg3QSJzdoebr0VCf0Bfh8HOPldKxAP/8XkFe9gA== + +"@swc/core-linux-arm64-musl@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.47.tgz#7ff2baa16e67b29017fdf7c6b69e40de7920ce1a" + integrity sha512-3Yu3Uq/VgytqsPjTMbkPU1ExADytbdWbruJYhA584E9jrpE2Ki+R6VVPoZCeAVk1Cb7QxcRTgblw6bSa6a/R+w== + +"@swc/core-linux-ppc64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.47.tgz#a3841982fe2eb2d889648c8e212b6d821db316d6" + integrity sha512-wfdMi5IaOaNtmh2/6geRoxIdNfqylUZFdtzTKS655y1axWfIWyx7As74vv0wVdjeCIZ3WmCI9odDd4rUttXOSQ== + +"@swc/core-linux-s390x-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.47.tgz#edbfd705d6285f7dce48915871478bc9603904c3" + integrity sha512-3hHYBY0yx8Ez7GMRrkhXHQzMdR5IZA6Wq5Ee4svlgwvSECLpnAJ9+0AimEGUFDvuLwE7nV/2+PYe8+Nm4rvNcQ== + +"@swc/core-linux-x64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.47.tgz#e7f61a7771d6a9b5b274521ba61809b3d7644325" + integrity sha512-TjfhjgP/jGCfFHYC3JQPhJA1HwErbIJ9JfREDc1KNkvY6P0LodCgKVIlQ5deeTbkG7ih3bF5PHJLuLpaZjdRyQ== + +"@swc/core-linux-x64-musl@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.47.tgz#7c1ef8305444bcc7894de177fe225f2d8f3be609" + integrity sha512-CQpS8Ge/avfjZd0UEwG/sds83Uu32deQXcV1Jo3jD0mmvQQqtYAjpsDZXugmheeAwmt+YIuoVtVHro8LMYHqsQ== + +"@swc/core-win32-arm64-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.47.tgz#953856d26b28956d1a18ef10e5f221202b2cb8f1" + integrity sha512-0W8IKHsUTYiT7G2RqtOoVWk+89yzZikIiDUb/sCK6BmQDBhN91hQSfyUtW12jhEWLzYgcfmisfsZrmZE+84U1A== + +"@swc/core-win32-ia32-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.47.tgz#2743a5bccc49f252c23bad3135193640cbdcef3a" + integrity sha512-ZIp49d2Z4/ka2jO9otOg4hDvTdPmp86kVOgS2M5FCPI7eKKZ1W0boxWn+8XeZrfERtFGW0AlMRm4JhlJa7l3NA== + +"@swc/core-win32-x64-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.47.tgz#9674ad0c9187b7cbe5cc3080b31b960d3ee688b9" + integrity sha512-2h8Iek95vnixkBRCo+H8p09+Q5ll2NgSMFrWTy0iKt7+/t+8/T5mBpiT6c0ZxSS7wcWjwZ9sGZkK70tTSYHdDw== + +"@swc/core@^1.15.40": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.47.tgz#6226e842160e247eb79a9aeac1095ebddb56639f" + integrity sha512-FbsO5JcfOjfH38W/rohBRBweJeERsAuIP4f377lmkmxTcq9exjtx4SkRuZY5CdfhR2CBVwDIJegBpJDffwNsOg== dependencies: "@swc/counter" "^0.1.3" - "@swc/types" "^0.1.26" + "@swc/types" "^0.1.27" optionalDependencies: - "@swc/core-darwin-arm64" "1.15.24" - "@swc/core-darwin-x64" "1.15.24" - "@swc/core-linux-arm-gnueabihf" "1.15.24" - "@swc/core-linux-arm64-gnu" "1.15.24" - "@swc/core-linux-arm64-musl" "1.15.24" - "@swc/core-linux-ppc64-gnu" "1.15.24" - "@swc/core-linux-s390x-gnu" "1.15.24" - "@swc/core-linux-x64-gnu" "1.15.24" - "@swc/core-linux-x64-musl" "1.15.24" - "@swc/core-win32-arm64-msvc" "1.15.24" - "@swc/core-win32-ia32-msvc" "1.15.24" - "@swc/core-win32-x64-msvc" "1.15.24" + "@swc/core-darwin-arm64" "1.15.47" + "@swc/core-darwin-x64" "1.15.47" + "@swc/core-linux-arm-gnueabihf" "1.15.47" + "@swc/core-linux-arm64-gnu" "1.15.47" + "@swc/core-linux-arm64-musl" "1.15.47" + "@swc/core-linux-ppc64-gnu" "1.15.47" + "@swc/core-linux-s390x-gnu" "1.15.47" + "@swc/core-linux-x64-gnu" "1.15.47" + "@swc/core-linux-x64-musl" "1.15.47" + "@swc/core-win32-arm64-msvc" "1.15.47" + "@swc/core-win32-ia32-msvc" "1.15.47" + "@swc/core-win32-x64-msvc" "1.15.47" "@swc/counter@^0.1.3": version "0.1.3" @@ -4877,90 +5141,90 @@ dependencies: tslib "^2.8.0" -"@swc/html-darwin-arm64@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-darwin-arm64/-/html-darwin-arm64-1.15.24.tgz#bb05a9f3f7aa97b4935e9ed5f1dd02646d691ff2" - integrity sha512-2yH5kkeBM6mcSajWdIvh482HZDthvWM+SkH17CAzmgDgP2WGZ3IpdeIQxdV8Jj9kRdJaI0VqdXGT0qRRt6zw4A== - -"@swc/html-darwin-x64@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-darwin-x64/-/html-darwin-x64-1.15.24.tgz#54b748beb47aa753f6004ae00a7e7a87914d59ce" - integrity sha512-1k4Wl1eExT9yal3fX6MGcrpWOvYo+f7jnzw+ksg+8ifpYqpcrcy6Rv6cB78SgXzZJRpx8zBY1luk+zYyoDlrWA== - -"@swc/html-linux-arm-gnueabihf@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-arm-gnueabihf/-/html-linux-arm-gnueabihf-1.15.24.tgz#a2fa025c307b7d4b9a4be7e8f23c12e33c0eea3f" - integrity sha512-XbqWgyBE6tukUs+0zwzW+Xo3N/P6SoiJJ44QfB3RCb5Naz/1vwJbNgn9erFDgoq7CChmCooFuMfNnmh/E/Orsg== - -"@swc/html-linux-arm64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.15.24.tgz#f4a68ec6294fa1221b8aaa6b79030986be73683d" - integrity sha512-GqJgkJHTlLM0tzJHX0tmU0ZAU4rIfMYZ2yJwCBwnFaLw4NacpimyWnWGJxH83SViVZ33DfLD2LG/dHN8xDAmRA== - -"@swc/html-linux-arm64-musl@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-arm64-musl/-/html-linux-arm64-musl-1.15.24.tgz#a77304d121ddceda0202b04b2fe81fc2e39c16a8" - integrity sha512-+7Xw69Y4p/LwhudMJZOQ++mKeXWTnh3vpNv5Ar+X1x8kfPBHKRXI3sRKf5JqE0oJqJXTgFP5xByzmO/KBee3sQ== - -"@swc/html-linux-ppc64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-ppc64-gnu/-/html-linux-ppc64-gnu-1.15.24.tgz#7bf94806da6eb65c5c01efbe01f35408dbf4a9cc" - integrity sha512-ZKxckgQkOY2a54jiCnIBs5TkMNx7zvuKbe1WsM/WV0BiTfMfw5iMmtCKAIuYCz/PJRXVK0dY4VH3DS7jabBvwg== - -"@swc/html-linux-s390x-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-s390x-gnu/-/html-linux-s390x-gnu-1.15.24.tgz#11a61c14a42ade262ff18a8178e1e9523631a321" - integrity sha512-y0WBjqDZALqOzasxrEOlgHq6SX34nAE4+0MATufmSoFEdiQIBYkm9m4C8XQNCNHv52ERCu/EPGK3Q8RfXaBLhQ== - -"@swc/html-linux-x64-gnu@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.15.24.tgz#89f52a32fe6cd3ce68e9188e4087f55d9ba4bf32" - integrity sha512-U//u302yBSgh6vFfJmrw17Xm7k9a17m/E3AcHK4w12CZOFtsKHQnxE3i9uFWhNbW5F70w2A9QENml5b0Us8XMg== - -"@swc/html-linux-x64-musl@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-linux-x64-musl/-/html-linux-x64-musl-1.15.24.tgz#686b5b5d9a4e623c7208d81e410e38a20e5595c9" - integrity sha512-U9gsAQCPiCROWKhLhSnW4JzkkOY6X4q0ZP/nA6UeKoahDdw4E8onPujtRSivt4ZxwdJKfAnsxeJY07V9YLZu9Q== - -"@swc/html-win32-arm64-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-win32-arm64-msvc/-/html-win32-arm64-msvc-1.15.24.tgz#d2f455b487670b02148cb21e167c6c21bf122b29" - integrity sha512-AETh78z9ig4e1eAlx8a02BnIS5iNIJ7C43swQsxMraSDZvZuBxnvEXHqnt94jRlw7fzmJRRpJdVcInQ21u/xGA== - -"@swc/html-win32-ia32-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-win32-ia32-msvc/-/html-win32-ia32-msvc-1.15.24.tgz#57089de21d103098dafaa1b250debf1d1352adfb" - integrity sha512-ymJkEATvFF1+So41/SkulPBoRzRXP6HxUGfvdSJ29qeYejxWMrIWyjDE1+vAalo4IAR0cWFE2Ef2A2Qeg8QbGA== - -"@swc/html-win32-x64-msvc@1.15.24": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html-win32-x64-msvc/-/html-win32-x64-msvc-1.15.24.tgz#15d225058a641907e0c302d961a4ac4ed2355950" - integrity sha512-l+Gv0+jcSaDILljpEMC8pQE+ubRoZcft+woUgKTTlJQEFS+MgxKKLQjNCXx3hzhuru5/Yo8x71Ng/aVT7PwprA== - -"@swc/html@^1.13.5": - version "1.15.24" - resolved "https://registry.yarnpkg.com/@swc/html/-/html-1.15.24.tgz#e2f22ea05793d940b3b25441eccd0bd6ecf3e61f" - integrity sha512-2kWRCU09lBBg3bZLz8Kc37azQ6sBwiV1P7VDvqwKEJC2CtREe5y1XgLLd78kqSpFli52hZ6l3CNPDqkaX6ceAg== +"@swc/html-darwin-arm64@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-darwin-arm64/-/html-darwin-arm64-1.15.47.tgz#a42a07365512956f57f6fa64533b17d2a7f1cf26" + integrity sha512-Qe3FXNLO/k2WN7xmBP8SzBrtLvlIbyqa8cceUOI0opE4gk+myk5qIk022MiGJOgiF1B21/wMXgA08gYjQ2lP2Q== + +"@swc/html-darwin-x64@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-darwin-x64/-/html-darwin-x64-1.15.47.tgz#a39820dafa0d742886d9445aa11c01d64ebd6fed" + integrity sha512-khCOiWmqlqi8yz+F/ePExhht/+3/cz1XzKV7raPKVynzd6sPxYtFQlNubj305s2soEXgkYYIH0zVVLwiMOVn6Q== + +"@swc/html-linux-arm-gnueabihf@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-arm-gnueabihf/-/html-linux-arm-gnueabihf-1.15.47.tgz#f411e12920cb4927d904a738840a55f1ad7533b0" + integrity sha512-7VRqaOEQEFPHSbUcnobmI59WbFK9M35Sse8TFN3hHxOlK9fINJ9yN5FuE9XEeRQAk+PFdR6WrIcF1Xwx1Cpi8A== + +"@swc/html-linux-arm64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-arm64-gnu/-/html-linux-arm64-gnu-1.15.47.tgz#1707179cc03a9ab3dc94e79c903ddb2a423f2625" + integrity sha512-Ri9MmQqVRiEWuRfpkSTqz0bguvejXQcqQAkoW1Hke6+DColfzETcgNWa/Kw/ii5A/SS9Nb7acKaYdIw1vMBPwA== + +"@swc/html-linux-arm64-musl@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-arm64-musl/-/html-linux-arm64-musl-1.15.47.tgz#bafc864c6a7154e82f2cec5423cf782d8e28a351" + integrity sha512-NyXRQiVBkeutgCwCxUUaFqZdDmpZONs7Zz3AZGoY35s9GwXF412Nt22fK/e7lO/sM6G/+S3rOom/0xTmUQSK6A== + +"@swc/html-linux-ppc64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-ppc64-gnu/-/html-linux-ppc64-gnu-1.15.47.tgz#060c636010ba48fe5282ca69c996163d5e7bde2e" + integrity sha512-rQ+XLJHFzu0e4M5p1+8kF2FKzI7WO9KPPji87OuicHZVrDCEqg7/jSGu3hys9CjIQIYVfR+tAFuZz3Q1/jOoNA== + +"@swc/html-linux-s390x-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-s390x-gnu/-/html-linux-s390x-gnu-1.15.47.tgz#68bd3ef44ee0a2e508c6fb7c7cf3d78c7d1f9241" + integrity sha512-w6bitHrllrE3lqmf14cT3spmWhZHGts1O08O4adzxztSPto7O5GM3IerqZm/NtsqlxNsfbVHnhaNXxXWe/8Q+Q== + +"@swc/html-linux-x64-gnu@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-x64-gnu/-/html-linux-x64-gnu-1.15.47.tgz#8b9369d350f22fe8835813850488b977302da7da" + integrity sha512-FTA7E29gcyadd71prg8sJUVacYrIhAXS8L7p48yCfgcNOKquofN1TDOrHVOyYMoxplL3FUwwbN+AZxWO7QfWPQ== + +"@swc/html-linux-x64-musl@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-linux-x64-musl/-/html-linux-x64-musl-1.15.47.tgz#3ec864d713f8be8b62072ea22221ca7a32479d9d" + integrity sha512-g+K1GKUrj+S9o8Qsgii2g7ooMzZ750R4IAqH5CVElIA5FTMAx7KGnu9ga6aEnRwwLYxY3s1k/nN+ls0NEk240g== + +"@swc/html-win32-arm64-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-win32-arm64-msvc/-/html-win32-arm64-msvc-1.15.47.tgz#60bca26237cc018c189f88d26bedfcc846444372" + integrity sha512-5Iw3i00JdTySi+ccc2CM5bxY+8TZivQmcTqUC6mUdAY0/KYBgSe1/L294UJQ4OTLQqNDOYXY9jdb070zZUX7jg== + +"@swc/html-win32-ia32-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-win32-ia32-msvc/-/html-win32-ia32-msvc-1.15.47.tgz#e76e1954f4d9301748ff9dc540ed65156bf6299e" + integrity sha512-YkKd0hbIOeuFC1Sg7uGKkU2JhL+c9vAJlT6P0nRbWCAL71n01IPbdtbW6PmvgVmI7pxRYucXpr4pg839nX5+9Q== + +"@swc/html-win32-x64-msvc@1.15.47": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html-win32-x64-msvc/-/html-win32-x64-msvc-1.15.47.tgz#4df3dd604985971992b1745bf7b1e7a925f4138f" + integrity sha512-w9Ug+VB9hlHT4hTWIJSB40AdF+qs5w07CYq/+ef1vQRjT5naN6/SKuXmr9/CKLn3T7A9z3lRMPKE4+lmtUkBOQ== + +"@swc/html@^1.15.40": + version "1.15.47" + resolved "https://registry.yarnpkg.com/@swc/html/-/html-1.15.47.tgz#2d9c24d2cd032b3880a4464a77188817f507e083" + integrity sha512-Olu/8OORvYB+43v2/85nHe1EA8WSvWp8D3kctEAput/o4F+EWCK0nr4yGTqvWB7Z+ODz0k+vnxpvHQYzsKP2LA== dependencies: "@swc/counter" "^0.1.3" optionalDependencies: - "@swc/html-darwin-arm64" "1.15.24" - "@swc/html-darwin-x64" "1.15.24" - "@swc/html-linux-arm-gnueabihf" "1.15.24" - "@swc/html-linux-arm64-gnu" "1.15.24" - "@swc/html-linux-arm64-musl" "1.15.24" - "@swc/html-linux-ppc64-gnu" "1.15.24" - "@swc/html-linux-s390x-gnu" "1.15.24" - "@swc/html-linux-x64-gnu" "1.15.24" - "@swc/html-linux-x64-musl" "1.15.24" - "@swc/html-win32-arm64-msvc" "1.15.24" - "@swc/html-win32-ia32-msvc" "1.15.24" - "@swc/html-win32-x64-msvc" "1.15.24" - -"@swc/types@^0.1.26": - version "0.1.26" - resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.26.tgz#2a976a1870caef1992316dda1464150ee36968b5" - integrity sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw== + "@swc/html-darwin-arm64" "1.15.47" + "@swc/html-darwin-x64" "1.15.47" + "@swc/html-linux-arm-gnueabihf" "1.15.47" + "@swc/html-linux-arm64-gnu" "1.15.47" + "@swc/html-linux-arm64-musl" "1.15.47" + "@swc/html-linux-ppc64-gnu" "1.15.47" + "@swc/html-linux-s390x-gnu" "1.15.47" + "@swc/html-linux-x64-gnu" "1.15.47" + "@swc/html-linux-x64-musl" "1.15.47" + "@swc/html-win32-arm64-msvc" "1.15.47" + "@swc/html-win32-ia32-msvc" "1.15.47" + "@swc/html-win32-x64-msvc" "1.15.47" + +"@swc/types@^0.1.27": + version "0.1.28" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.28.tgz#e3cd892383fba3b8904c40518bbe1265a50753f2" + integrity sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw== dependencies: "@swc/counter" "^0.1.3" @@ -4986,10 +5250,10 @@ resolved "https://registry.yarnpkg.com/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz#9a759ce2cb8736a4c6a0cb93aeb740573a731974" integrity sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA== -"@tailwindcss/typography@^0.5.16": - version "0.5.19" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.19.tgz#ecb734af2569681eb40932f09f60c2848b909456" - integrity sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg== +"@tailwindcss/typography@^0.5.20": + version "0.5.20" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.20.tgz#9feb7fb1d5f2f7b5360c22e24651210db74c34df" + integrity sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw== dependencies: postcss-selector-parser "6.0.10" @@ -5017,16 +5281,16 @@ resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.13.23.tgz#72bcaad8bbf6bd86e0d02776dc7dc968d0aba07b" integrity sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg== -"@tinacms/app@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@tinacms/app/-/app-2.5.2.tgz#82d26964c8c69d9593a8a6c12a72e339d67b53d1" - integrity sha512-LWEJq3ZuqeTLNohdVfiKXEIdNg4gC9iGz97uQj4LowHDwmuE76eKIUk71W/7XRny30QpJdJPoXCt28Y3mN+IZg== +"@tinacms/app@^2.5.10": + version "2.5.10" + resolved "https://registry.yarnpkg.com/@tinacms/app/-/app-2.5.10.tgz#1bb23fee0282621302b4fb1e3be5e500ffaee2e5" + integrity sha512-G1XKneo6vtMnzcT/OU2WXXh0ljw3rufo9wyHjIe/LzPDAcZPBfFozqMFMzYyuXa+4bnUgB453AMlu5+QkdRezQ== dependencies: "@graphiql/toolkit" "0.8.4" "@headlessui/react" "2.1.8" "@heroicons/react" "^1.0.6" "@monaco-editor/react" "4.7.0-rc.0" - "@tinacms/mdx" "2.1.6" + "@tinacms/mdx" "^2.1.11" final-form "4.20.10" graphiql "3.0.0-alpha.1" graphql "15.8.0" @@ -5034,22 +5298,22 @@ react "^18.3.1" react-dom "^18.3.1" react-router-dom "^6.30.3" - tinacms "3.8.4" + tinacms "^3.11.0" typescript "^5.7.3" zod "^3.24.2" -"@tinacms/bridge@0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@tinacms/bridge/-/bridge-0.3.0.tgz#9a51dcdfbaba96bc735c1eec72df17d60d5dedb5" - integrity sha512-I7rHRprsL+9e4W5kcyWVEk+ApGGxEZgXBEt5W+rMrODpFxmmxaTMLks7It2DIBVOeXCPZguvirUd3DNqC0Yy0Q== +"@tinacms/bridge@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@tinacms/bridge/-/bridge-0.3.1.tgz#33dee1eeb1a59ddca1c4886412197dc0e2b3a773" + integrity sha512-HgFZGFec+92FvXR5NVinQtPmkidWIubkjyYkNnRWlqFmGbhzIZE6GhMX/RWZ9uNYek6kRQUtpFnGaQeBkXo95Q== -"@tinacms/cli@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@tinacms/cli/-/cli-2.4.2.tgz#d93e2763db000d60b0c429bb457bcd9b4db4efdb" - integrity sha512-8BCFnHjCd5SdAQif0FxBbb0cQcbFWYPNtrFnHFn6LY8BDD1nhRNtYi6YTLy/TVRqnf1vS5Hfl5tzZ6Qaxe6J+Q== +"@tinacms/cli@^2.5.6": + version "2.5.6" + resolved "https://registry.yarnpkg.com/@tinacms/cli/-/cli-2.5.6.tgz#fea41464dc84d55667fea4fd9dcaca5b8846676b" + integrity sha512-QYH5Dw9GDn7XoHRnpZfW83Euth6TLKHXUGe0NFBTFFMvOEDqkTHqQWdOvVMF9igjUJVf4HfPWjGXiqtvCdmsCg== dependencies: "@graphql-codegen/core" "^2.6.8" - "@graphql-codegen/plugin-helpers" latest + "@graphql-codegen/plugin-helpers" "^7.0.1" "@graphql-codegen/typescript" "^4.1.3" "@graphql-codegen/typescript-operations" "^4.4.1" "@graphql-codegen/visitor-plugin-common" "^4.1.2" @@ -5060,12 +5324,12 @@ "@svgr/core" "8.1.0" "@tailwindcss/aspect-ratio" "^0.4.2" "@tailwindcss/container-queries" "^0.1.1" - "@tailwindcss/typography" "^0.5.16" - "@tinacms/app" "2.5.2" - "@tinacms/graphql" "2.4.3" - "@tinacms/metrics" "2.1.0" - "@tinacms/schema-tools" "2.8.1" - "@tinacms/search" "1.2.17" + "@tailwindcss/typography" "^0.5.20" + "@tinacms/app" "^2.5.10" + "@tinacms/graphql" "^2.4.9" + "@tinacms/metrics" "^2.1.1" + "@tinacms/schema-tools" "^2.8.3" + "@tinacms/search" "^1.2.23" "@vitejs/plugin-react" "3.1.0" altair-express-middleware "^7.3.6" async-lock "^1.4.1" @@ -5093,23 +5357,23 @@ prompts "^2.4.2" readable-stream "^4.7.0" tailwindcss "^3.4.17" - tinacms "3.8.4" + tinacms "^3.11.0" typanion "3.13.0" typescript "^5.7.3" vite "^4.5.9" yup "^1.6.1" zod "^3.24.2" -"@tinacms/graphql@2.4.3": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@tinacms/graphql/-/graphql-2.4.3.tgz#18736e7b51522aeac681b42c4e40a97888d1d437" - integrity sha512-fawyTX2a/W34RQx6esV8H/G+33KrnqQtJJGhmLe4kX68cDXPbuoSIN73czC7c9R9/SGS0Y0ybe2riqbwi3Qnug== +"@tinacms/graphql@^2.4.9": + version "2.4.9" + resolved "https://registry.yarnpkg.com/@tinacms/graphql/-/graphql-2.4.9.tgz#0ccf92ed7b6d0540141a928a54e0f936e0c0c24b" + integrity sha512-jqVqxXdNUSiU3reT+X9ZiRFPA+tSIYcN3EmdGYy3pYq9oZkVhjoQUEinGj/lPOv5wdcvYGl8cEAmRyKD6oYjSQ== dependencies: "@iarna/toml" "^2.2.5" - "@tinacms/mdx" "2.1.6" - "@tinacms/schema-tools" "2.8.1" + "@tinacms/mdx" "^2.1.11" + "@tinacms/schema-tools" "^2.8.3" abstract-level "^1.0.4" - date-fns "^2.30.0" + date-fns "4.1.0" es-toolkit "^1.42.0" fast-glob "^3.3.3" fs-extra "^11.3.0" @@ -5126,12 +5390,12 @@ readable-stream "^4.7.0" yup "^1.6.1" -"@tinacms/mdx@2.1.6": - version "2.1.6" - resolved "https://registry.yarnpkg.com/@tinacms/mdx/-/mdx-2.1.6.tgz#88a9f118f498c0452d266992843fce207997fd3b" - integrity sha512-AXrGJgqxoDx4n3QxY0zrjReVufJ43ozDajeoUFLTGXS5v/y5bnqxTI/YIJ+3RDjNbu7fEbcgP4HqKzelsQR8ZA== +"@tinacms/mdx@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tinacms/mdx/-/mdx-2.1.11.tgz#a3c71d23d4fc34186260c5fa72b822ebb6b34dc8" + integrity sha512-RG9ZkL6VZQwuug8a+74d7yaHr5rwe0p9fmGuHEaSKIttO0aUjQZ/VpxCrT6PxEf7naNimE26BI9qSztRbu8yug== dependencies: - "@tinacms/schema-tools" "2.8.1" + "@tinacms/schema-tools" "^2.8.3" acorn "8.8.2" ccount "2.0.1" estree-util-is-identifier-name "2.1.0" @@ -5161,27 +5425,27 @@ uvu "0.5.6" vfile-message "3.1.4" -"@tinacms/metrics@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@tinacms/metrics/-/metrics-2.1.0.tgz#0db4971733c1d428a20ca71d7efbc4109cd3fb12" - integrity sha512-gNGW7Q2Pez09OFqOrs0oJnuPnl1fkpFwgUXzPFJi1K6RzPDaVzb9blkM38efFLp+coI6ZvkdcrofYWxAu1+MMA== +"@tinacms/metrics@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinacms/metrics/-/metrics-2.1.1.tgz#44183b1c67e8631b7f2228b60ee21c5d1efaa007" + integrity sha512-XfSLdplNI5Fq0YklCpUY4ydfvPuskptIovjMC13Up3fERggV7q9rhtlkVldidfNoX/K94KLyfY4Atsjuxmu9mg== -"@tinacms/schema-tools@2.8.1": - version "2.8.1" - resolved "https://registry.yarnpkg.com/@tinacms/schema-tools/-/schema-tools-2.8.1.tgz#9cf373b8990df78aa046f7a4f8216f2224f08920" - integrity sha512-ItCAlelP0gJq3G9rVY9w3kNecnF7vVtQajSfVwXLc+gKDDiC58ZoAm4H4/FNPwLGTG5g3RVZiQM/iOTr8Q3/gA== +"@tinacms/schema-tools@^2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@tinacms/schema-tools/-/schema-tools-2.8.3.tgz#993b7061e261ef96f63a5c7fc67282f906b9053e" + integrity sha512-9wuFzy5B/M9rOmnVeJszT1VbPBMpzLunFp390Fwgp59edbyRy0TaXX/QSg9t/+EHmsUUt9fNwUdujCP1eF/Jcw== dependencies: picomatch-browser "2.2.6" url-pattern "^1.0.3" zod "^3.24.2" -"@tinacms/search@1.2.17": - version "1.2.17" - resolved "https://registry.yarnpkg.com/@tinacms/search/-/search-1.2.17.tgz#10ae31f6d09450575e59da11d83a301b844e9a63" - integrity sha512-Jf+GFzXjK+XvXi3mvF866OMJZgo0DToXF4vmr1w7Ux05DgfuAFoGvwZMj49mebZE/MRWMOwyqp64t35/JHi/Xg== +"@tinacms/search@^1.2.23": + version "1.2.23" + resolved "https://registry.yarnpkg.com/@tinacms/search/-/search-1.2.23.tgz#161b597ba65d83e5516fdb84e9721760519dd6de" + integrity sha512-wc1XKphE89oJUUA5QAa714eKMhsubh11fzlurYCKLRH3+Y9oyHd4xS0s4okjrKfNJGP2+I9GQ65Hn3l1wT0WzQ== dependencies: - "@tinacms/graphql" "2.4.3" - "@tinacms/schema-tools" "2.8.1" + "@tinacms/graphql" "^2.4.9" + "@tinacms/schema-tools" "^2.8.3" memory-level "^1.0.0" search-index "4.0.0" sqlite-level "^2.1.0" @@ -5534,11 +5798,6 @@ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.16.tgz#8ebe53d69efada7044454e3305c19017d97ced2a" integrity sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg== -"@types/gtag.js@^0.0.20": - version "0.0.20" - resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.20.tgz#e47edabb4ed5ecac90a079275958e6c929d7c08a" - integrity sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg== - "@types/hast@^2.0.0": version "2.3.10" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" @@ -5713,10 +5972,10 @@ dependencies: csstype "^3.2.2" -"@types/react@^19.2.15": - version "19.2.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.15.tgz#9e2c6a4251a290f5c525c3143caa872fa6e01e0d" - integrity sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q== +"@types/react@^19.2.18": + version "19.2.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.18.tgz#eb0b6a1fb635d1a9692d5f84a3495bd8ad153707" + integrity sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w== dependencies: csstype "^3.2.2" @@ -6327,15 +6586,10 @@ acorn@^8.0.0, acorn@^8.0.4, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== -add@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235" - integrity sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q== - -address@^1.0.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" - integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== +address@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/address/-/address-2.0.3.tgz#e910900615db3d8a20c040d4c710631062fc4ba8" + integrity sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA== aggregate-error@^3.0.0: version "3.1.0" @@ -7033,6 +7287,16 @@ change-case-all@1.0.15: upper-case "^2.0.2" upper-case-first "^2.0.2" +change-case-all@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-2.1.0.tgz#c838988531bba9fa9e4db124f2d3f53a9607acc1" + integrity sha512-v6b0WWWkZUMHVuYk82l+WROgkUm4qEN2w5hKRNWtEOYwWqUGoi8C6xH0l1RLF1EoWqDFK6MFclmN3od6ws3/uw== + dependencies: + change-case "^5.2.0" + sponge-case "^2.0.2" + swap-case "^3.0.2" + title-case "^3.0.3" + change-case@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" @@ -7051,6 +7315,11 @@ change-case@^4.1.2: snake-case "^3.0.4" tslib "^2.0.3" +change-case@^5.2.0: + version "5.4.4" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-5.4.4.tgz#0d52b507d8fb8f204343432381d1a6d7bff97a02" + integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -8167,13 +8436,6 @@ date-fns@4.1.0, date-fns@^4.1.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14" integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== -date-fns@^2.30.0: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== - dependencies: - "@babel/runtime" "^7.21.0" - dayjs@^1.11.19: version "1.11.20" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.20.tgz#88d919fd639dc991415da5f4cb6f1b6650811938" @@ -8196,7 +8458,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.4.3: +debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -8332,13 +8594,12 @@ detect-package-manager@^3.0.2: dependencies: execa "^5.1.1" -detect-port@^1.5.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.6.1.tgz#45e4073997c5f292b957cb678fb0bb8ed4250a67" - integrity sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q== +detect-port@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-2.1.0.tgz#03d72644891fa451ca5609b83107a8a0ebd03f91" + integrity sha512-epZuWb/6Q62L+nDHJc/hQAqf8pylsqgk3BpZXVBx1CDnr3nkrVNn73Uu1rXcFzkNcc+hkP3whuOg7JZYaQB65Q== dependencies: - address "^1.0.1" - debug "4" + address "^2.0.1" devlop@^1.0.0, devlop@^1.1.0: version "1.1.0" @@ -8664,10 +8925,10 @@ enhanced-resolve@^5.20.0: graceful-fs "^4.2.4" tapable "^2.3.0" -enhanced-resolve@^5.22.0: - version "5.22.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz#c34bc3f414298496fc244b21bbe316440782da17" - integrity sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww== +enhanced-resolve@^5.24.4: + version "5.24.5" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz#b4dad3255b7545f07ba5535189868e9f85f47573" + integrity sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A== dependencies: graceful-fs "^4.2.4" tapable "^2.3.3" @@ -10857,7 +11118,7 @@ khroma@^2.1.0: resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.1.0.tgz#45f2ce94ce231a437cf5b63c2e886e6eb42bbbb1" integrity sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw== -kind-of@^6.0.0, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -11049,11 +11310,6 @@ loader-runner@^4.3.1: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.1.tgz#6c76ed29b0ccce9af379208299f07f876de737e3" integrity sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q== -loader-runner@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.2.tgz#9913d3a15971f8f635915e601fb5c9d495d918e9" - integrity sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w== - loader-utils@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" @@ -12826,6 +13082,16 @@ minimisted@^2.0.0: dependencies: minimist "^1.2.5" +minimizer-webpack-plugin@^5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz#289922a4c96c4ed1ddb76b8a00bd8074e89a2f7f" + integrity sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.25" + jest-worker "^27.4.5" + schema-utils "^4.3.0" + terser "^5.31.1" + minipass@^7.1.2, minipass@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" @@ -12856,23 +13122,6 @@ module-error@^1.0.1, module-error@^1.0.2: resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== -moment-timezone@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.6.1.tgz#c324a71a8285583eb679ced4ba3dcfa53fdce500" - integrity sha512-1B9lmAhB9D9/sHaPC1N7wLFEVUoFldxOpOO96lOD1PvJ43vCd0ozDPbu0FEL3++VvawOlDkq8YD373tJmP5JHw== - dependencies: - moment "^2.29.4" - -moment@2.29.4: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -moment@^2.29.4: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - monaco-editor@0.31.0: version "0.31.0" resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.31.0.tgz#ec53566e40b612a96c0d54f77d37acef6d9dd70e" @@ -14452,7 +14701,7 @@ prop-types@15.7.2: object-assign "^4.1.1" react-is "^16.8.1" -prop-types@^15.5.0, prop-types@^15.5.7, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -14651,13 +14900,6 @@ react-colorful@^5.6.1: resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.6.1.tgz#7dc2aed2d7c72fac89694e834d179e32f3da563b" integrity sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw== -react-datetime@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/react-datetime/-/react-datetime-3.3.1.tgz#60870ef7cb70f3a98545385e068f16344a50b1db" - integrity sha512-CMgQFLGidYu6CAlY6S2Om2UZiTfZsjC6j4foXcZ0kb4cSmPomdJ2S1PhK0v3fwflGGVuVARGxwkEUWtccHapJA== - dependencies: - prop-types "^15.5.7" - react-day-picker@^9.13.0: version "9.14.0" resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-9.14.0.tgz#b2975b48366d0c3a180520e1a4063b5a7d6c5a57" @@ -14694,10 +14936,10 @@ react-dom@^18.3.1: loose-envify "^1.1.0" scheduler "^0.23.2" -react-dom@^19.2.6: - version "19.2.6" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.6.tgz#44a81b0bcca22da814c00847d09d01c8615529b7" - integrity sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g== +react-dom@^19.2.8: + version "19.2.8" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.8.tgz#3b46b9eeda877cdff2cf13d2770fff4ae36c2ec2" + integrity sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ== dependencies: scheduler "^0.27.0" @@ -14841,7 +15083,7 @@ react-remove-scroll-bar@^2.3.7: react-style-singleton "^2.2.2" tslib "^2.0.0" -react-remove-scroll@^2.6.3: +react-remove-scroll@^2.6.3, react-remove-scroll@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz#6442da56791117661978ae99cd29be9026fecca0" integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q== @@ -14950,10 +15192,10 @@ react@^18.3.1: dependencies: loose-envify "^1.1.0" -react@^19.2.6: - version "19.2.6" - resolved "https://registry.yarnpkg.com/react/-/react-19.2.6.tgz#3dadb8e12b2a7934c1d5317973e5dce1301f9a4d" - integrity sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q== +react@^19.2.8: + version "19.2.8" + resolved "https://registry.yarnpkg.com/react/-/react-19.2.8.tgz#a80663dbb58d69c6fe3fd291d3cb324e8a7dff2d" + integrity sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw== read-cache@^1.0.0: version "1.0.0" @@ -15536,10 +15778,10 @@ sass-loader@^16.0.2, sass-loader@^16.0.5: dependencies: neo-async "^2.6.2" -sass@^1.100.0: - version "1.100.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.100.0.tgz#b4cab1bed286fe22ac6c879c514f71cd36aa06c8" - integrity sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ== +sass@^1.102.0: + version "1.102.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.102.0.tgz#4ed9378f37ca4186a76d6d1f52a6680c92b6bd80" + integrity sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw== dependencies: chokidar "^5.0.0" immutable "^5.1.5" @@ -16150,6 +16392,11 @@ sponge-case@^1.0.1: dependencies: tslib "^2.0.3" +sponge-case@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-2.0.3.tgz#9e004d04332c307e4895b79eeb6c1f3da86eb203" + integrity sha512-i4h9ZGRfxV6Xw3mpZSFOfbXjf0cQcYmssGWutgNIfFZ2VM+YIWfD71N/kjjwK6X/AAHzBr+rciEcn/L34S8TGw== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -16438,6 +16685,11 @@ swap-case@^2.0.2: dependencies: tslib "^2.0.3" +swap-case@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-3.0.3.tgz#363883b0e8a2837c24d2e0eccb6bdff92e32d711" + integrity sha512-6p4op8wE9CQv7uDFzulI6YXUw4lD9n4oQierdbFThEKVWVQcbQcUjdP27W8XE7V4QnWmnq9jueSHceyyQnqQVA== + swc-loader@^0.2.6: version "0.2.7" resolved "https://registry.yarnpkg.com/swc-loader/-/swc-loader-0.2.7.tgz#2d1611ab314c5d8342d74aa5e5901b3fbf490de2" @@ -16534,16 +16786,6 @@ terser-webpack-plugin@^5.3.17, terser-webpack-plugin@^5.3.9: schema-utils "^4.3.0" terser "^5.31.1" -terser-webpack-plugin@^5.5.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz#8e7caad248183ab9e91ff08a83b0fc9f0439c3c3" - integrity sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - jest-worker "^27.4.5" - schema-utils "^4.3.0" - terser "^5.31.1" - terser@^5.10.0, terser@^5.15.1, terser@^5.31.1: version "5.46.1" resolved "https://registry.yarnpkg.com/terser/-/terser-5.46.1.tgz#40e4b1e35d5f13130f82793a8b3eeb7ec3a92eee" @@ -16583,10 +16825,10 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -tinacms@3.8.4, tinacms@^3.8.4: - version "3.8.4" - resolved "https://registry.yarnpkg.com/tinacms/-/tinacms-3.8.4.tgz#e158285804daa553890575071fa77b4da18a0ddb" - integrity sha512-SLF/M70yOmDul8fVv0hDdSnRT1FvMFAuCTRV5fzsSxBaqiTpbDiON1czg1YHtnHokZmruNkHmTYO/wMTHjfiog== +tinacms@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/tinacms/-/tinacms-3.11.0.tgz#1874fd5e2cb6b552e775a18ee4a94b046319baa3" + integrity sha512-zMXsF0gTqP/WxThNeCSWtte4igToFeW93b+1aRLpWdobxt54j58xspzsLz7MaONHIvTK4GobTONJoCmzF647DQ== dependencies: "@ariakit/react" "^0.4.15" "@dnd-kit/core" "^6.1.0" @@ -16598,21 +16840,20 @@ tinacms@3.8.4, tinacms@^3.8.4: "@headlessui/react" "2.1.8" "@heroicons/react" "^1.0.6" "@monaco-editor/react" "4.7.0-rc.0" - "@radix-ui/react-checkbox" "^1.1.4" - "@radix-ui/react-dialog" "^1.1.6" - "@radix-ui/react-dropdown-menu" "^2.1.6" - "@radix-ui/react-popover" "^1.1.15" - "@radix-ui/react-select" "^2.2.6" - "@radix-ui/react-separator" "^1.1.2" - "@radix-ui/react-slot" "^1.1.2" - "@radix-ui/react-toolbar" "^1.1.2" - "@radix-ui/react-tooltip" "^1.2.8" + "@radix-ui/react-dialog" "^1.1.18" + "@radix-ui/react-dropdown-menu" "^2.1.19" + "@radix-ui/react-popover" "^1.1.18" + "@radix-ui/react-select" "^2.3.2" + "@radix-ui/react-separator" "^1.1.11" + "@radix-ui/react-slot" "^1.3.0" + "@radix-ui/react-toolbar" "^1.1.14" + "@radix-ui/react-tooltip" "^1.2.11" "@react-hook/window-size" "^3.1.1" "@tanstack/react-table" "^8.21.3" - "@tinacms/bridge" "0.3.0" - "@tinacms/mdx" "2.1.6" - "@tinacms/schema-tools" "2.8.1" - "@tinacms/search" "1.2.17" + "@tinacms/bridge" "^0.3.1" + "@tinacms/mdx" "^2.1.11" + "@tinacms/schema-tools" "^2.8.3" + "@tinacms/search" "^1.2.23" "@udecode/cmdk" "^0.2.1" "@udecode/cn" "^48.0.3" "@udecode/plate" "^48.0.3" @@ -16637,7 +16878,6 @@ tinacms@3.8.4, tinacms@^3.8.4: "@udecode/plate-slash-command" "^48.0.0" "@udecode/plate-table" "^48.0.0" "@udecode/plate-trailing-block" "^48.0.0" - add "^2.0.6" async-lock "^1.4.1" class-variance-authority "^0.7.1" clsx "^2.1.1" @@ -16654,14 +16894,11 @@ tinacms@3.8.4, tinacms@^3.8.4: is-hotkey "^0.2.0" lucide-react "^0.424.0" mermaid "^11.12.2" - moment "2.29.4" - moment-timezone "^0.6.0" monaco-editor "0.31.0" posthog-js "^1.347.1" prism-react-renderer "^2.4.1" prop-types "15.7.2" react-colorful "^5.6.1" - react-datetime "^3.3.1" react-day-picker "^9.13.0" react-dnd "^16.0.1" react-dnd-html5-backend "^16.0.1" @@ -17566,6 +17803,13 @@ watchpack@^2.5.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +watchpack@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.2.tgz#e12e82d84674266fc1c6dbfe38891b92ff0522ec" + integrity sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg== + dependencies: + graceful-fs "^4.1.2" + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" @@ -17701,15 +17945,15 @@ webpack-sources@^3.3.4: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.3.4.tgz#a338b95eb484ecc75fbb196cbe8a2890618b4891" integrity sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q== -webpack-sources@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.5.0.tgz#87bf7f5801a4e985b1f1c92b64b9620a02f76d08" - integrity sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ== +webpack-sources@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.5.1.tgz#76c2418486dcc02b2aa0694c104176c2858fe84a" + integrity sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw== -webpack@^5.107.2: - version "5.107.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.107.2.tgz#dea14dcb177b46b29de15f952f7303691ee2b596" - integrity sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ== +webpack@^5.109.2: + version "5.109.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.109.2.tgz#b58dc289561c3282db35c210a99379a836a4c28d" + integrity sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw== dependencies: "@types/estree" "^1.0.8" "@types/json-schema" "^7.0.15" @@ -17717,23 +17961,20 @@ webpack@^5.107.2: "@webassemblyjs/wasm-edit" "^1.14.1" "@webassemblyjs/wasm-parser" "^1.14.1" acorn "^8.16.0" - acorn-import-phases "^1.0.3" browserslist "^4.28.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.22.0" + enhanced-resolve "^5.24.4" es-module-lexer "^2.1.0" eslint-scope "5.1.1" events "^3.2.0" - glob-to-regexp "^0.4.1" graceful-fs "^4.2.11" - loader-runner "^4.3.2" mime-db "^1.54.0" + minimizer-webpack-plugin "^5.6.1" neo-async "^2.6.2" schema-utils "^4.3.3" tapable "^2.3.0" - terser-webpack-plugin "^5.5.0" - watchpack "^2.5.1" - webpack-sources "^3.5.0" + watchpack "^2.5.2" + webpack-sources "^3.5.1" webpack@^5.88.1, webpack@^5.95.0: version "5.106.1"