From 610e876ef01e98bf8c54c75d2291db394a134146 Mon Sep 17 00:00:00 2001 From: Karl Cardenas Date: Fri, 29 Sep 2023 07:15:35 -0700 Subject: [PATCH] chore: api version dropdown feature (#1627) * swizzle dropdown * chore: update core files * chore: updated version script * chore: updated node version script * ci: updated gitignore * chore: updated versions script * ci: verify API logic works * ci: minor edit to the test YAML * ci: adding versioning build step * ci: removed test CI file for version validation --------- Co-authored-by: Nageshwara sairam <113401242+nagesh161007@users.noreply.github.com> --- .gitignore | 3 + Makefile | 5 + docusaurus.config.js | 577 ++++++++++-------- scripts/update_docusarus_config.js | 178 ++++-- scripts/versions.sh | 36 +- .../DocsVersionDropdownNavbarItem.js | 18 + 6 files changed, 503 insertions(+), 314 deletions(-) create mode 100644 src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js diff --git a/.gitignore b/.gitignore index ef5e842269..60435292c7 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,9 @@ docs/api-content/api-docs/v1/sidebar.js versions.json versioned_docs/ versioned_sidebars/ +api_versions.json +api_versioned_docs/ +api_versioned_sidebars/ versioned_sidebars/* temp.docusaurus.config.js staging_docs/ diff --git a/Makefile b/Makefile index db552749e2..4c7bffcb9f 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,11 @@ clean: ## Clean build artifacts rm -rf node_modules build public .cache .docusaurus docker image rm $(IMAGE) || echo "No image exists." +clean-versions: ## Clean Docusarus content versions + @echo "cleaning versions" + rm -rf api_versions.json versions.json versioned_docs versioned_sidebars api_versioned_sidebars api_versioned_docs + git checkout -- docusaurus.config.js + ##@ npm Targets init: ## Initialize npm dependencies diff --git a/docusaurus.config.js b/docusaurus.config.js index 6886fe88c6..08a8d27861 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -30,277 +30,344 @@ const config = { // to replace "en" with "zh-Hans". i18n: { defaultLocale: "en", - locales: ["en"] + locales: ["en"], }, staticDirectories: ["static", "static/assets/docs/images", "static/assets"], - headTags: [{ - tagName: "script", - attributes: { - type: "text/plain", - "data-usercentrics": "FullStory", - src: "/scripts/fullstory.js" - } - }, { - tagName: "link", - attributes: { - rel: "preconnect", - href: "https://api.usercentrics.eu" - } - }, { - tagName: "link", - attributes: { - rel: "preload", - href: "https://app.usercentrics.eu/browser-ui/latest/loader.js", - as: "script" - } - }, { - tagName: "script", - attributes: { - src: "https://app.usercentrics.eu/browser-ui/latest/loader.js", - "data-settings-id": "0IhiFXOBwy0Z2U", - id: "usercentrics-cmp", - async: "true" - } - }, { - tagName: "link", - attributes: { - rel: "preconnect", - href: "https://www.googletagmanager.com" - } - }, { - tagName: "script", - attributes: { - type: "text/javascript", - "data-usercentrics": "Google Tag Manager", - src: "/scripts/googleTagManager.js" - } - }], - stylesheets: [], - presets: [["classic", /** @type {import('@docusaurus/preset-classic').Options} */ - { - docs: { - path: "docs/docs-content", - showLastUpdateAuthor: false, - showLastUpdateTime: true, - routeBasePath: "/", - lastVersion: "current", - includeCurrentVersion: true, - versions: { - current: { - label: "latest" - } + headTags: [ + { + tagName: "script", + attributes: { + type: "text/plain", + "data-usercentrics": "FullStory", + src: "/scripts/fullstory.js", }, - // exclude: ["api/v1/palette-apis-3-4"], - - sidebarPath: require.resolve("./sidebars.js"), - async sidebarItemsGenerator({ - defaultSidebarItemsGenerator, - ...args - }) { - const { - docs - } = args; - const filteredDocs = docs.filter(doc => { - return true; - }); - const sidebarItems = await defaultSidebarItemsGenerator({ - ...args, - docs: filteredDocs - }); - return sidebarItems; + }, + { + tagName: "link", + attributes: { + rel: "preconnect", + href: "https://api.usercentrics.eu", }, - editUrl: "https://github.com/spectrocloud/librarium/blob/master" }, - sitemap: { - changefreq: "weekly", - priority: 0.5, - ignorePatterns: ["/tags/**"], - filename: "sitemap.xml" + { + tagName: "link", + attributes: { + rel: "preload", + href: "https://app.usercentrics.eu/browser-ui/latest/loader.js", + as: "script", + }, }, - theme: { - customCss: require.resolve("./src/css/custom.scss") - } - }]], - plugins: ["docusaurus-plugin-sass", ["@docusaurus/plugin-content-docs", { - id: "api", - path: "docs/api-content/api-docs", - routeBasePath: "api", - docItemComponent: "@theme/ApiItem", - sidebarPath: require.resolve("./apisidebar.js") - }], ["docusaurus-plugin-openapi-docs", { - id: "apidocs", - docsPluginId: "api", - config: { - palette: { - specPath: "docs/api-content/api-docs/v1/api.json", - outputDir: "docs/api-content/api-docs/v1", - downloadUrl: "https://github.com/spectrocloud/librarium/blob/master/docs/api-content/api-docs/palette-apis.json", - sidebarOptions: { - groupPathsBy: "tag", - categoryLinkSource: "tag" + { + tagName: "script", + attributes: { + src: "https://app.usercentrics.eu/browser-ui/latest/loader.js", + "data-settings-id": "0IhiFXOBwy0Z2U", + id: "usercentrics-cmp", + async: "true", + }, + }, + { + tagName: "link", + attributes: { + rel: "preconnect", + href: "https://www.googletagmanager.com", + }, + }, + { + tagName: "script", + attributes: { + type: "text/javascript", + "data-usercentrics": "Google Tag Manager", + src: "/scripts/googleTagManager.js", + }, + }, + ], + stylesheets: [], + presets: [ + [ + "classic", + /** @type {import('@docusaurus/preset-classic').Options} */ + { + docs: { + path: "docs/docs-content", + showLastUpdateAuthor: false, + showLastUpdateTime: true, + routeBasePath: "/", + lastVersion: "current", + includeCurrentVersion: true, + versions: { + current: { + label: "latest", + }, + }, + // exclude: ["api/v1/palette-apis-3-4"], + + sidebarPath: require.resolve("./sidebars.js"), + async sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) { + const { docs } = args; + const filteredDocs = docs.filter((doc) => { + return true; + }); + const sidebarItems = await defaultSidebarItemsGenerator({ + ...args, + docs: filteredDocs, + }); + return sidebarItems; + }, + editUrl: "https://github.com/spectrocloud/librarium/blob/master", + }, + sitemap: { + changefreq: "weekly", + priority: 0.5, + ignorePatterns: ["/tags/**"], + filename: "sitemap.xml", }, - template: "api.mustache", - // Customize API MDX with mustache template - hideSendButton: true - } - } - }], process.env.NODE_ENV !== "production" && [() => ({ - name: "plugin-enable-source-map", - configureWebpack() { + theme: { + customCss: require.resolve("./src/css/custom.scss"), + }, + }, + ], + ], + plugins: [ + "docusaurus-plugin-sass", + [ + "@docusaurus/plugin-content-docs", + { + id: "api", + path: "docs/api-content/api-docs", + routeBasePath: "api", + docItemComponent: "@theme/ApiItem", + lastVersion: "current", + includeCurrentVersion: true, + versions: { + current: { + label: "latest" + }, + }, + sidebarPath: require.resolve("./apisidebar.js"), + }, + ], + [ + "docusaurus-plugin-openapi-docs", + { + // Visit https://docusaurus-openapi.tryingpan.dev/#config to learn more about this plugin's config options. + id: "apidocs", + docsPluginId: "api", + config: { + palette: { + specPath: "docs/api-content/api-docs/v1/api.json", + outputDir: "docs/api-content/api-docs/v1", + downloadUrl: + "https://github.com/spectrocloud/librarium/blob/master/docs/api-content/api-docs/palette-apis.json", + sidebarOptions: { + groupPathsBy: "tag", + categoryLinkSource: "tag", + }, + template: "api.mustache", + // Customize API MDX with mustache template + hideSendButton: true, + }, + }, + }, + ], + process.env.NODE_ENV !== "production" && [ + () => ({ + name: "plugin-enable-source-map", + configureWebpack() { + return { + devtool: "source-map", + }; + }, + }), + { + id: "enable-source-map", + }, + ], + pluginPacksAndIntegrationsData, + pluginImportFontAwesomeIcons, + function () { return { - devtool: "source-map" + name: "plugin-watch-custom-plugin-path", + getPathsToWatch() { + return ["plugins/font-awesome.js", "plugins/packs-integrations.js"]; + }, }; - } - }), { - id: "enable-source-map" - }], pluginPacksAndIntegrationsData, pluginImportFontAwesomeIcons, function () { - return { - name: "plugin-watch-custom-plugin-path", - getPathsToWatch() { - return ["plugins/font-awesome.js", "plugins/packs-integrations.js"]; - } - }; - }, ["@docusaurus/plugin-ideal-image", { - quality: 50, - max: 1035, - min: 640, - steps: 4, - disableInDev: false - }], [require.resolve("docusaurus-plugin-image-zoom"), { - id: "docusaurus-plugin-image-zoom" - }], ["@docusaurus/plugin-client-redirects", { - redirects: [...redirects] - }]].filter(Boolean), - scripts: [{ - src: `https://w.appzi.io/w.js?token=${process.env.APPZI_TOKEN}`, - defer: true - }], + }, + [ + "@docusaurus/plugin-ideal-image", + { + quality: 50, + max: 1035, + steps: 4, + disableInDev: false, + }, + ], + [ + require.resolve("docusaurus-plugin-image-zoom"), + { + id: "docusaurus-plugin-image-zoom", + }, + ], + [ + "@docusaurus/plugin-client-redirects", + { + redirects: [...redirects], + }, + ], + ].filter(Boolean), + scripts: [ + { + src: `https://w.appzi.io/w.js?token=${process.env.APPZI_TOKEN}`, + defer: true, + }, + ], themes: ["docusaurus-theme-openapi-docs"], customFields: { // Put your custom environment here - mendableKey: process.env.MENDABLE_API_KEY + mendableKey: process.env.MENDABLE_API_KEY, }, - themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - { - colorMode: { - respectPrefersColorScheme: true - }, - docs: { + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + { + colorMode: { + respectPrefersColorScheme: true, + }, + docs: { + sidebar: { + hideable: false, + autoCollapseCategories: true, + }, + }, + tableOfContents: { + minHeadingLevel: 2, + maxHeadingLevel: 6, + }, + // Replace with your project's social card + image: "img/spectro-cloud-social-card.png", + navbar: { + title: "", + logo: { + href: "/", + target: "self", + width: 144, + height: 36, + alt: "Spectro cloud logo", + src: "img/spectrocloud-logo-light.svg", + srcDark: "img/spectrocloud-logo-dark.svg", + }, + items: [ + { + to: "/", + label: "Docs", + position: "left", + activeBaseRegex: "^(?!/api/).*$", + }, + { + to: "/api/introduction", + label: "API", + position: "left", + }, + { + href: "https://github.com/spectrocloud/librarium", + position: "right", + className: "header-github-link", + "aria-label": "GitHub repository", + }, + { + type: "docsVersionDropdown", + position: "left", + docsPluginId: "default" + }, + { + type: "docsVersionDropdown", + position: "left", + docsPluginId: "api", + }, + ], + hideOnScroll: true, + }, + languageTabs: [ + { + highlight: "bash", + language: "curl", + logoClass: "bash", + }, + { + highlight: "python", + language: "python", + logoClass: "python", + variant: "requests", + }, + { + highlight: "go", + language: "go", + logoClass: "go", + }, + { + highlight: "javascript", + language: "nodejs", + logoClass: "nodejs", + variant: "axios", + }, + { + highlight: "java", + language: "java", + logoClass: "java", + variant: "unirest", + }, + ], + algolia: { + // The application ID provided by Algolia + appId: process.env.ALGOLIA_APP_ID, + // Public API key: it is safe to commit it + apiKey: process.env.ALGOLIA_SEARCH_KEY, + indexName: "prod-docusaurus-librarium", + // Optional: see doc section below + contextualSearch: true, + // Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them. + externalUrlRegex: "external\\.com|domain\\.com", + // Optional: Replace parts of the item URLs from Algolia. Useful when using the same search index for multiple deployments using a different baseUrl. You can use regexp or string in the `from` param. For example: localhost:3000 vs myCompany.com/docs + replaceSearchResultPathname: { + from: "/docs/", + // or as RegExp: /\/docs\// + to: "/", + }, + // Optional: Algolia search parameters + searchParameters: {}, + // Optional: path for search page that enabled by default (`false` to disable it) + searchPagePath: "search", + }, sidebar: { - hideable: false, - autoCollapseCategories: true - } - }, - tableOfContents: { - minHeadingLevel: 2, - maxHeadingLevel: 6 - }, - // Replace with your project's social card - image: "img/spectro-cloud-social-card.png", - navbar: { - title: "", - logo: { - href: "/", - target: "self", - width: 144, - height: 36, - alt: "Spectro cloud logo", - src: "img/spectrocloud-logo-light.svg", - srcDark: "img/spectrocloud-logo-dark.svg" + hideable: true, }, - items: [{ - to: "/", - label: "Docs", - position: "left", - activeBaseRegex: "^(?!/api/).*$" - }, { - to: "/api/introduction", - label: "API", - position: "left" - }, { - href: "https://github.com/spectrocloud/librarium", - position: "right", - className: "header-github-link", - "aria-label": "GitHub repository" - }, { - type: 'docsVersionDropdown', - position: 'left' - }], - hideOnScroll: true - }, - languageTabs: [{ - highlight: "bash", - language: "curl", - logoClass: "bash" - }, { - highlight: "python", - language: "python", - logoClass: "python", - variant: "requests" - }, { - highlight: "go", - language: "go", - logoClass: "go" - }, { - highlight: "javascript", - language: "nodejs", - logoClass: "nodejs", - variant: "axios" - }, { - highlight: "java", - language: "java", - logoClass: "java", - variant: "unirest" - }], - algolia: { - // The application ID provided by Algolia - appId: process.env.ALGOLIA_APP_ID, - // Public API key: it is safe to commit it - apiKey: process.env.ALGOLIA_SEARCH_KEY, - indexName: "prod-docusaurus-librarium", - // Optional: see doc section below - contextualSearch: true, - // Optional: Specify domains where the navigation should occur through window.location instead on history.push. Useful when our Algolia config crawls multiple documentation sites and we want to navigate with window.location.href to them. - externalUrlRegex: "external\\.com|domain\\.com", - // Optional: Replace parts of the item URLs from Algolia. Useful when using the same search index for multiple deployments using a different baseUrl. You can use regexp or string in the `from` param. For example: localhost:3000 vs myCompany.com/docs - replaceSearchResultPathname: { - from: "/docs/", - // or as RegExp: /\/docs\// - to: "/" + prism: { + defaultLanguage: "json", + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ["hcl", "bash", "json", "powershell", "go", "javascript", "rust"], + magicComments: [ + { + className: "theme-code-block-highlighted-line", + line: "highlight-next-line", + block: { + start: "highlight-start", + end: "highlight-end", + }, + }, + { + className: "code-block-error-line", + line: "This will error", + }, + ], }, - // Optional: Algolia search parameters - searchParameters: {}, - // Optional: path for search page that enabled by default (`false` to disable it) - searchPagePath: "search" - }, - sidebar: { - hideable: true - }, - prism: { - defaultLanguage: "json", - theme: lightCodeTheme, - darkTheme: darkCodeTheme, - additionalLanguages: ["hcl", "bash", "json", "powershell", "go", "javascript", "rust"], - magicComments: [{ - className: "theme-code-block-highlighted-line", - line: "highlight-next-line", - block: { - start: "highlight-start", - end: "highlight-end" - } - }, { - className: "code-block-error-line", - line: "This will error" - }] - }, - zoom: { - selector: ".markdown-image", - background: { - light: "rgb(255, 255, 255)", - dark: "rgb(50, 50, 50)" + zoom: { + selector: ".markdown-image", + background: { + light: "rgb(255, 255, 255)", + dark: "rgb(50, 50, 50)", + }, + config: {}, }, - config: {} - } - } + }, }; module.exports = config; \ No newline at end of file diff --git a/scripts/update_docusarus_config.js b/scripts/update_docusarus_config.js index f9d3036061..807a5924fc 100644 --- a/scripts/update_docusarus_config.js +++ b/scripts/update_docusarus_config.js @@ -8,81 +8,151 @@ const versionsJSONFile = 'versions.json'; const tempDirectory = process.argv[2]; const baseDirectory = process.argv[3]; + +// This reads the docusaurus.config.js file and parses it into an AST. +// We need to parse it into an AST so that we can add the new versions to the config object. +// This is how we dynamically add the new versions to the config object. +const configCode = fs.readFileSync(`${baseDirectory}/${docusaurusConfigFile}`, 'utf8'); +const ast = parser.parse(configCode, { + sourceType: 'module', +}); + +// This function finds the object containing the versions of the API docs plugin +const findApiDocsPluginVersionsObject = () => { + let apiVersionsObject; + + // Find the main "config" declaration + const configDeclaration = ast.program.body.find( + node => node.type === 'VariableDeclaration' && node.declarations[0].id.name === 'config' + ); + + // If the "config" declaration is not found, log an error and return + if (!configDeclaration) { + console.error('Could not locate the main "config" declaration.'); + return; + } + + // Find the "plugins" property in the "config" declaration + const pluginsProperty = configDeclaration.declarations[0].init.properties.find( + prop => prop.key.name === 'plugins' + ); + + // If the "plugins" property is not found, log an error and return + if (!pluginsProperty) { + console.error('Could not locate the "plugins" property.'); + return; + } + + let pluginsArray; + + // If the value of the "plugins" property is a call expression, get the object it's called on + if (pluginsProperty.value.type === 'CallExpression') { + pluginsArray = pluginsProperty.value.callee.object; + } + + // Loop through the elements of the "plugins" array + pluginsArray.elements.forEach(element => { + // If the element is an array containing the API docs plugin, get its versions object + if (element.type === 'ArrayExpression' && element.elements[0].value === '@docusaurus/plugin-content-docs') { + const idProperty = element.elements[1].properties.find(prop => prop.key.name === 'id'); + if (idProperty && idProperty.value.value === 'api') { + apiVersionsObject = element.elements[1].properties.find( + (prop) => prop.key.name === 'versions' + ).value; + } + } + }); + + // Return the object containing the versions of the API docs plugin + return apiVersionsObject; +}; + +// This function takes in a "versionsObject" parameter and updates it with new properties based on the "versionsArray" and "versionsOverride" arrays +const updateVersionsObject = (versionsObject) => { + // Loop through each version in the "versionsArray" + versionsArray.forEach((version) => { + // Find the corresponding object in the "versionsOverride" array, or use an empty object if not found + const override = versionsOverride.find((item) => item.version === version) || {}; + + // Get the "banner" and "label" values from the override object, or use default values if not found + const bannerValue = override.banner || 'none'; + const labelValue = override.label || `v${version}`; + + // Create a new object property with the version as the key and an object expression as the value + const versionProperty = t.objectProperty( + t.stringLiteral(version), + t.objectExpression([ + t.objectProperty(t.identifier('banner'), t.stringLiteral(bannerValue)), + t.objectProperty(t.identifier('label'), t.stringLiteral(labelValue)) + ]) + ); + + // Add the new object property to the "properties" array of the "versionsObject" parameter + versionsObject.properties.push(versionProperty); + }); +}; + // This creates an array that contains all the versions that are in the versions.json file. // The versions.json file is created by the bash script (versions.sh) that runs before this one. let versionsArray = []; try { - const versionsJson = fs.readFileSync(versionsJSONFile, 'utf8'); - versionsArray = JSON.parse(versionsJson); + const versionsJson = fs.readFileSync(versionsJSONFile, 'utf8'); + versionsArray = JSON.parse(versionsJson); } catch (err) { - console.error('Could not read versions.json:', err); + console.error('Could not read versions.json:', err); } - // This creates an array that contains all the versions that are in the versionsOverride.json file. // The versionsOverride.json file is a manually created file that allows us to override the banner and label for a specific version. // If the version is not in the versionsOverride.json file, then the banner will be set to 'none' and the label will be the version number. let versionsOverride = []; try { - const versionsOverrideJson = fs.readFileSync(`${baseDirectory}/versionsOverride.json`, 'utf8'); - versionsOverride = JSON.parse(versionsOverrideJson); + const versionsOverrideJson = fs.readFileSync(`${baseDirectory}/versionsOverride.json`, 'utf8'); + versionsOverride = JSON.parse(versionsOverrideJson); } catch (err) { - console.error('Could not read versionsOverride.json:', err); + console.error('Could not read versionsOverride.json:', err); } -// This reads the docusaurus.config.js file and parses it into an AST. -// We need to parse it into an AST so that we can add the new versions to the config object. -// This is how we dynamically add the new versions to the config object. -const configCode = fs.readFileSync(`${baseDirectory}/${docusaurusConfigFile}`, 'utf8'); -const ast = parser.parse(configCode, { - sourceType: 'module', -}); -// This is where the scripts loop through the AST to find the config object. -// We are after the config object and the docs object that is nested inside of it. -// Inside of the docs object is the versions object that we need to add the new versions to. -let configObject; +// This is where the main logic starts and the entry point for the script. +// This code searches for the object containing the versions of the main documentation in a Docusaurus config file. +// It loops through the nodes in the abstract syntax tree (AST) of the file and finds the "config" declaration. +// It then finds the "presets" property in the "config" declaration and gets the object it's called on. +// Inside of the "presets" object, it finds the "docs" property and gets the object it's called on. +// Inside of the "docs" object, it finds the "versions" property and gets the object it's called on. +let mainDocsVersionsObject; + +// Loop through the nodes in the AST of the file ast.program.body.forEach((node) => { - if ( - node.type === 'VariableDeclaration' && - node.declarations[0].id.name === 'config' - ) { - configObject = node.declarations[0].init.properties.find( - (prop) => prop.key.name === 'presets' - ).value.elements[0].elements[1].properties.find( - (prop) => prop.key.name === 'docs' - ).value.properties.find( - (prop) => prop.key.name === 'versions' - ).value; - } + // Find the "config" declaration + if ( + node.type === 'VariableDeclaration' && + node.declarations[0].id.name === 'config' + ) { + // Find the "presets" property in the "config" declaration and get the object it's called on + mainDocsVersionsObject = node.declarations[0].init.properties.find( + (prop) => prop.key.name === 'presets' + ).value.elements[0].elements[1].properties.find( + (prop) => prop.key.name === 'docs' + ).value.properties.find( + (prop) => prop.key.name === 'versions' + ).value; + } }); +// Update the main docs versions object +updateVersionsObject(mainDocsVersionsObject); -// This is where the scrip loops through the versions array and add the new versions to the config object. -// This also check to identify if the version is in the versionsOverride.json file. -// If it is, then use the banner and label from the versionsOverride.json file. -versionsArray.forEach((version) => { - const override = versionsOverride.find((item) => item.version === version) || {}; - const bannerValue = override.banner || 'none'; - const labelValue = override.label || `v${version}`; - - const versionProperty = t.objectProperty( - t.stringLiteral(version), - t.objectExpression([ - t.objectProperty(t.identifier('banner'), t.stringLiteral(bannerValue)), - t.objectProperty(t.identifier('label'), t.stringLiteral(labelValue)) - ]) - ); - - configObject.properties.push(versionProperty); -}); +// Find and update the API docs versions object. +const apiDocsVersionsObject = findApiDocsPluginVersionsObject(); +if (apiDocsVersionsObject) { + updateVersionsObject(apiDocsVersionsObject); +} // This is where the new config object is converted back into code. const updatedCode = generate(ast).code; - -// Lastly, this is where the new config object is written to the temp.docusaurus.config.js file. -// Catch the error if it fails. try { - fs.writeFileSync(`${tempDirectory}/temp.docusaurus.config.js`, updatedCode); + // Lastly, this is where the new config object is written to the temp.docusaurus.config.js file. + fs.writeFileSync(`${tempDirectory}/temp.docusaurus.config.js`, updatedCode); } catch (err) { - console.error('Could not write to temp.docusaurus.config.js:', err); -} + console.error('Could not write to temp.docusaurus.config.js:', err); +} \ No newline at end of file diff --git a/scripts/versions.sh b/scripts/versions.sh index 01a93a8372..2ae0e34b4f 100755 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -56,15 +56,22 @@ done # Remove the existing versioned directories in the temp directory. rm -rf $tempdir/staging_docs +rm -rf $tempdir/staging_api_docs rm -rf $tempdir/staging_sidebars +rm -rf $tempdir/staging_api_docs_sidebars rm -rf $tempdir/temp_versions.json +rm -rf $tempdir/temp_api_versions.json # Create the staging directory for all the versions mkdir -p $tempdir/staging_docs +mkdir -p $tempdir/staging_api_docs mkdir -p $tempdir/staging_sidebars +mkdir -p $tempdir/staging_api_docs_sidebars touch $tempdir/temp_versions.json +touch $tempdir/temp_api_versions.json echo '[]' > $tempdir/temp_versions.json # Initialize as an empty array if it doesn't exist +echo '[]' > $tempdir/temp_api_versions.json # Initialize as an empty array if it doesn't exist echo "Entering the loop to generate the versioned documentation" @@ -102,6 +109,7 @@ for item in $(git branch --format '%(refname:short)'); do # Add version to temp_versions.json and sort it jq --arg ver "$extracted_version" '. |= [$ver] + . | sort_by(. | split(".") | map(tonumber)) | reverse' $tempdir/temp_versions.json > $tempdir/temp.json && mv $tempdir/temp.json $tempdir/temp_versions.json + jq --arg ver "$extracted_version" '. |= [$ver] + . | sort_by(. | split(".") | map(tonumber)) | reverse' $tempdir/temp_api_versions.json > $tempdir/temp_api.json && mv $tempdir/temp_api.json $tempdir/temp_api_versions.json @@ -115,21 +123,34 @@ for item in $(git branch --format '%(refname:short)'); do echo "Running: npm run docusaurus docs:version $extracted_versionX" npm run docusaurus docs:version $extracted_versionX + # Generate the API docs + echo "Running: npm run generate-api-docs" + npm run generate-api-docs - # Copy the generated files to the staging directory - # echo "Copying files to staging directory" - # mkdir -p $tempdir/staging_docs/version-$extracted_versionX - # mkdir -p $tempdir/staging_sidebars/version-$extracted_versionX - + echo "Running: npm run docusaurus docs:version:api $extracted_versionX" + npm run docusaurus docs:version:api $extracted_versionX + + + # Copy version docs content cp -R versioned_docs/version-$extracted_versionX $tempdir/staging_docs/ cp -R versioned_sidebars/version-$extracted_versionX $tempdir/staging_sidebars/ || true cp versioned_sidebars/version-$extracted_versionX-sidebars.json $tempdir/staging_sidebars/version-$extracted_versionX-sidebars.json + # Copy version API docs content + cp -R api_versioned_docs/version-$extracted_versionX $tempdir/staging_api_docs/ + cp -R api_versioned_sidebars/version-$extracted_versionX $tempdir/staging_api_docs_sidebars/ || true + cp api_versioned_sidebars/version-$extracted_versionX-sidebars.json $tempdir/staging_api_docs_sidebars/version-$extracted_versionX-sidebars.json rm -rf versioned_docs/ rm -rf versioned_sidebars/ + rm -rf api_versioned_docs/ + rm -rf api_versioned_sidebars/ rm versions.json + rm api_versions.json + + # Remove API auto-generated files + npm run clean-api-docs # Switch back to the original branch git checkout $current_branch @@ -140,15 +161,20 @@ done # Rename the staging directory to the expected Docusarus versioned directory names cp -R $tempdir/staging_docs $baseDir/versioned_docs cp -R $tempdir/staging_sidebars $baseDir/versioned_sidebars +cp -R $tempdir/staging_api_docs $baseDir/api_versioned_docs +cp -R $tempdir/staging_api_docs_sidebars $baseDir/api_versioned_sidebars # Remove the existing versions.json if it exists [ -e versions.json ] && rm versions.json +[ -e api_versions.json ] && rm api_versions.json # Replace the last number with 'x' to indicate it's a version branch jq '.[] |= (split(".")[:-1] | join(".")) + ".x"' $tempdir/temp_versions.json > $tempdir/temp.json && mv $tempdir/temp.json $tempdir/temp_versions.json +jq '.[] |= (split(".")[:-1] | join(".")) + ".x"' $tempdir/temp_api_versions.json > $tempdir/temp_api.json && mv $tempdir/temp_api.json $tempdir/temp_api_versions.json # Rename temp_versions.json to versions.json mv $tempdir/temp_versions.json $baseDir/versions.json +mv $tempdir/temp_api_versions.json $baseDir/api_versions.json echo "Updating docusarus.config.js through the node script." node $baseDir/scripts/update_docusarus_config.js $tempdir $baseDir diff --git a/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js b/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js new file mode 100644 index 0000000000..304fc70a07 --- /dev/null +++ b/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.js @@ -0,0 +1,18 @@ +import React from "react"; +import DocsVersionDropdownNavbarItem from "@theme-original/NavbarItem/DocsVersionDropdownNavbarItem"; +import { useActivePluginAndVersion } from "@docusaurus/plugin-content-docs/client"; + +export default function DocsVersionDropdownNavbarItemWrapper(props) { + const { docsPluginId } = props; + const pluginData = useActivePluginAndVersion(); + const doesPathnameContainDocsPluginId = docsPluginId === pluginData?.activePlugin?.pluginId; + + if (!doesPathnameContainDocsPluginId) { + return null; + } + return ( + <> + + + ); +}