codeant-ai-for-open-source[bot] commented on code in PR #37434: URL: https://github.com/apache/superset/pull/37434#discussion_r2729749543
########## docs/scripts/generate-api-index.mjs: ########## @@ -0,0 +1,240 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Generates a comprehensive API index MDX file from the OpenAPI spec. + * This creates the api.mdx landing page with all endpoints organized by category. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const SPEC_PATH = path.join(__dirname, '..', 'static', 'resources', 'openapi.json'); +const OUTPUT_PATH = path.join(__dirname, '..', 'docs', 'api.mdx'); + +// Category groupings for better organization +const CATEGORY_GROUPS = { + 'Authentication': ['Security'], + 'Core Resources': ['Dashboards', 'Charts', 'Datasets', 'Database'], + 'Data Exploration': ['Explore', 'SQL Lab', 'Queries', 'Datasources', 'Advanced Data Type'], + 'Organization & Customization': ['Tags', 'Annotation Layers', 'CSS Templates'], + 'Sharing & Embedding': [ + 'Dashboard Permanent Link', 'Explore Permanent Link', 'SQL Lab Permanent Link', + 'Embedded Dashboard', 'Dashboard Filter State', 'Explore Form Data' + ], + 'Scheduling & Alerts': ['Report Schedules'], + 'Security & Access Control': [ + 'Security Roles', 'Security Users', 'Security Permissions', + 'Security Resources (View Menus)', 'Security Permissions on Resources (View Menus)', + 'Row Level Security' + ], + 'Import/Export & Administration': ['Import/export', 'CacheRestApi', 'LogRestApi'], + 'User & System': ['Current User', 'User', 'Menu', 'Available Domains', 'AsyncEventsRestApi', 'OpenApi'], +}; + +function slugify(text) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)/g, ''); +} + +function generateEndpointLink(summary) { + // Convert summary to the slug format used by docusaurus-openapi-docs + return slugify(summary); +} + +function main() { + console.log(`Reading OpenAPI spec from ${SPEC_PATH}`); + const spec = JSON.parse(fs.readFileSync(SPEC_PATH, 'utf-8')); + + // Build a map of tag -> endpoints + const tagEndpoints = {}; + const tagDescriptions = {}; + + // Get tag descriptions + for (const tag of spec.tags || []) { + tagDescriptions[tag.name] = tag.description || ''; + } + + // Collect endpoints by tag + for (const [pathUrl, methods] of Object.entries(spec.paths || {})) { + for (const [method, details] of Object.entries(methods)) { + if (!['get', 'post', 'put', 'delete', 'patch'].includes(method)) continue; + + const tags = details.tags || ['Untagged']; + const summary = details.summary || `${method.toUpperCase()} ${pathUrl}`; + + for (const tag of tags) { + if (!tagEndpoints[tag]) { + tagEndpoints[tag] = []; + } + tagEndpoints[tag].push({ + method: method.toUpperCase(), + path: pathUrl, + summary, + slug: generateEndpointLink(summary), + }); + } + } + } + + // Sort endpoints within each tag by path + for (const tag of Object.keys(tagEndpoints)) { + tagEndpoints[tag].sort((a, b) => a.path.localeCompare(b.path)); + } + + // Generate MDX content + let mdx = `--- +title: API Reference +hide_title: true +sidebar_position: 10 +--- + +import { Alert } from 'antd'; + +## REST API Reference + +Superset exposes a comprehensive **REST API** that follows the [OpenAPI specification](https://swagger.io/specification/). +You can use this API to programmatically interact with Superset for automation, integrations, and custom applications. + +<Alert + type="info" + showIcon + message="Code Samples & Schema Documentation" + description={ + <span> + Each endpoint includes ready-to-use code samples in <strong>cURL</strong>, <strong>Python</strong>, and <strong>JavaScript</strong>. + Browse the <a href="./api/schemas">Schema definitions</a> for detailed data model documentation. + </span> + } + style={{ marginBottom: '24px' }} +/> + +--- + +`; + + // Track which tags we've rendered + const renderedTags = new Set(); + + // Render Authentication first (it's critical for using the API) + mdx += `### Authentication + +Most API endpoints require authentication via JWT tokens. + +#### Quick Start + +\`\`\`bash +# 1. Get a JWT token +curl -X POST http://localhost:8088/api/v1/security/login \\ + -H "Content-Type: application/json" \\ + -d '{"username": "admin", "password": "admin", "provider": "db"}' + +# 2. Use the access_token from the response +curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\ + http://localhost:8088/api/v1/dashboard/ +\`\`\` + +#### Security Endpoints + +`; + + // Render Security tag endpoints + if (tagEndpoints['Security']) { + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + for (const ep of tagEndpoints['Security']) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; + } + mdx += '\n'; + renderedTags.add('Security'); + } + + mdx += `---\n\n### API Endpoints\n\n`; + + // Render each category group + for (const [groupName, groupTags] of Object.entries(CATEGORY_GROUPS)) { + if (groupName === 'Authentication') continue; // Already rendered + + const tagsInGroup = groupTags.filter(tag => tagEndpoints[tag] && !renderedTags.has(tag)); + if (tagsInGroup.length === 0) continue; + + mdx += `#### ${groupName}\n\n`; + + for (const tag of tagsInGroup) { + const description = tagDescriptions[tag] || ''; + const endpoints = tagEndpoints[tag]; + + mdx += `<details>\n`; + mdx += `<summary><strong>${tag}</strong> (${endpoints.length} endpoints) — ${description}</summary>\n\n`; + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + + for (const ep of endpoints) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; + } + + mdx += `\n</details>\n\n`; + renderedTags.add(tag); + } + } + + // Render any remaining tags not in a group + const remainingTags = Object.keys(tagEndpoints).filter(tag => !renderedTags.has(tag)); + if (remainingTags.length > 0) { + mdx += `#### Other\n\n`; + + for (const tag of remainingTags.sort()) { + const description = tagDescriptions[tag] || ''; + const endpoints = tagEndpoints[tag]; + + mdx += `<details>\n`; + mdx += `<summary><strong>${tag}</strong> (${endpoints.length} endpoints) — ${description}</summary>\n\n`; + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + + for (const ep of endpoints) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; Review Comment: **Suggestion:** In the "Other" tag section, endpoint links again use `./api/${ep.slug}` from the `/docs/api` page, which incorrectly resolves to `/docs/api/api/<slug>` and breaks all links for uncategorized tags. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ \"Other\" section links 404 on the API index page. - ⚠️ Unlabeled endpoints unreachable from index. - ⚠️ Search/navigation burden increased for users. ``` </details> ```suggestion mdx += `| \`${ep.method}\` | [${ep.summary}](./${ep.slug}) | \`${ep.path}\` |\n`; ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Run docs/scripts/generate-api-index.mjs which produces the "Other" tag section using the loop at docs/scripts/generate-api-index.mjs:204-223; the per-endpoint link template is at lines 217-219. 2. Serve the site (yarn start) and open /docs/api/; scroll to the "Other" section generated from the remaining tags. 3. Click any endpoint link in that "Other" section. The link target uses "./api/<slug>" (from the generator at docs/scripts/generate-api-index.mjs:219) and resolves to /docs/api/api/<slug> instead of /docs/api/<slug>, leading to missing pages. 4. Inspecting api.mdx confirms the duplicated "api" segment was produced by the template; switching to "./${ep.slug}" (improved code) produces correct links. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/scripts/generate-api-index.mjs **Line:** 218:218 **Comment:** *Logic Error: In the "Other" tag section, endpoint links again use `./api/${ep.slug}` from the `/docs/api` page, which incorrectly resolves to `/docs/api/api/<slug>` and breaks all links for uncategorized tags. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/src/styles/custom.css: ########## @@ -187,3 +187,81 @@ ul.dropdown__menu svg { [data-theme='dark'] .ant-collapse-header { color: var(--ifm-font-base-color); } + +/* Hide the non-functional "Send API Request" button and Response block in API docs */ +/* The interactive API testing doesn't work due to CORS restrictions */ +.openapi-explorer__request-btn { + display: none !important; +} + +.openapi-explorer__response-container { + display: none !important; Review Comment: **Suggestion:** Hiding `.openapi-explorer__response-container` with `display: none !important` will completely remove the API "Response" block from all endpoint pages, which likely includes the documented response status codes and schemas that the new API reference is supposed to expose, so users won't see response information at all; keeping the button hidden is fine, but the response container itself should remain visible. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ API response schemas hidden on all endpoint pages. - ❌ Response status codes invisible to documentation readers. - ⚠️ Developer portal `/docs/api/` user experience degraded. - ⚠️ Documentation testers cannot see examples inline. ``` </details> ```suggestion /* Keep the response container visible so response status codes and schemas remain documented. Interactive "Send request" behavior is disabled separately via the request button rule. */ ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Build and run the docs site locally (as described in PR): run `cd docs && yarn install && yarn start`. 2. Open the API reference landing page at `/docs/api/` in the running dev server. 3. Navigate to any endpoint page (e.g., click an endpoint entry on the landing page). 4. Inspect the endpoint page DOM in the browser devtools and find the element with class `openapi-explorer__response-container` (the docusaurus-openapi-docs response block). 5. Observe that because `docs/src/styles/custom.css` contains the rule at lines 197-199, the response container element has `display: none !important` and is hidden — response status codes and example schemas are not visible. 6. Confirm behavior is global by testing multiple endpoints: the same CSS rule in `docs/src/styles/custom.css:197-199` hides responses site-wide. Note: Hiding the request button is appropriate for CORS reasons (`.openapi-explorer__request-btn` at lines 193-195), but the separate response container rule at 197-199 removes documented response information entirely. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/src/styles/custom.css **Line:** 198:198 **Comment:** *Logic Error: Hiding `.openapi-explorer__response-container` with `display: none !important` will completely remove the API "Response" block from all endpoint pages, which likely includes the documented response status codes and schemas that the new API reference is supposed to expose, so users won't see response information at all; keeping the button hidden is fine, but the response container itself should remain visible. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/scripts/generate-api-index.mjs: ########## @@ -0,0 +1,240 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Generates a comprehensive API index MDX file from the OpenAPI spec. + * This creates the api.mdx landing page with all endpoints organized by category. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const SPEC_PATH = path.join(__dirname, '..', 'static', 'resources', 'openapi.json'); +const OUTPUT_PATH = path.join(__dirname, '..', 'docs', 'api.mdx'); + +// Category groupings for better organization +const CATEGORY_GROUPS = { + 'Authentication': ['Security'], + 'Core Resources': ['Dashboards', 'Charts', 'Datasets', 'Database'], + 'Data Exploration': ['Explore', 'SQL Lab', 'Queries', 'Datasources', 'Advanced Data Type'], + 'Organization & Customization': ['Tags', 'Annotation Layers', 'CSS Templates'], + 'Sharing & Embedding': [ + 'Dashboard Permanent Link', 'Explore Permanent Link', 'SQL Lab Permanent Link', + 'Embedded Dashboard', 'Dashboard Filter State', 'Explore Form Data' + ], + 'Scheduling & Alerts': ['Report Schedules'], + 'Security & Access Control': [ + 'Security Roles', 'Security Users', 'Security Permissions', + 'Security Resources (View Menus)', 'Security Permissions on Resources (View Menus)', + 'Row Level Security' + ], + 'Import/Export & Administration': ['Import/export', 'CacheRestApi', 'LogRestApi'], + 'User & System': ['Current User', 'User', 'Menu', 'Available Domains', 'AsyncEventsRestApi', 'OpenApi'], +}; + +function slugify(text) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)/g, ''); +} + +function generateEndpointLink(summary) { + // Convert summary to the slug format used by docusaurus-openapi-docs + return slugify(summary); +} + +function main() { + console.log(`Reading OpenAPI spec from ${SPEC_PATH}`); + const spec = JSON.parse(fs.readFileSync(SPEC_PATH, 'utf-8')); + + // Build a map of tag -> endpoints + const tagEndpoints = {}; + const tagDescriptions = {}; + + // Get tag descriptions + for (const tag of spec.tags || []) { + tagDescriptions[tag.name] = tag.description || ''; + } + + // Collect endpoints by tag + for (const [pathUrl, methods] of Object.entries(spec.paths || {})) { + for (const [method, details] of Object.entries(methods)) { + if (!['get', 'post', 'put', 'delete', 'patch'].includes(method)) continue; + + const tags = details.tags || ['Untagged']; + const summary = details.summary || `${method.toUpperCase()} ${pathUrl}`; + + for (const tag of tags) { + if (!tagEndpoints[tag]) { + tagEndpoints[tag] = []; + } + tagEndpoints[tag].push({ + method: method.toUpperCase(), + path: pathUrl, + summary, + slug: generateEndpointLink(summary), + }); + } + } + } + + // Sort endpoints within each tag by path + for (const tag of Object.keys(tagEndpoints)) { + tagEndpoints[tag].sort((a, b) => a.path.localeCompare(b.path)); + } + + // Generate MDX content + let mdx = `--- +title: API Reference +hide_title: true +sidebar_position: 10 +--- + +import { Alert } from 'antd'; + +## REST API Reference + +Superset exposes a comprehensive **REST API** that follows the [OpenAPI specification](https://swagger.io/specification/). +You can use this API to programmatically interact with Superset for automation, integrations, and custom applications. + +<Alert + type="info" + showIcon + message="Code Samples & Schema Documentation" + description={ + <span> + Each endpoint includes ready-to-use code samples in <strong>cURL</strong>, <strong>Python</strong>, and <strong>JavaScript</strong>. + Browse the <a href="./api/schemas">Schema definitions</a> for detailed data model documentation. + </span> + } + style={{ marginBottom: '24px' }} +/> + +--- + +`; + + // Track which tags we've rendered + const renderedTags = new Set(); + + // Render Authentication first (it's critical for using the API) + mdx += `### Authentication + +Most API endpoints require authentication via JWT tokens. + +#### Quick Start + +\`\`\`bash +# 1. Get a JWT token +curl -X POST http://localhost:8088/api/v1/security/login \\ + -H "Content-Type: application/json" \\ + -d '{"username": "admin", "password": "admin", "provider": "db"}' + +# 2. Use the access_token from the response +curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\ + http://localhost:8088/api/v1/dashboard/ +\`\`\` + +#### Security Endpoints + +`; + + // Render Security tag endpoints + if (tagEndpoints['Security']) { + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + for (const ep of tagEndpoints['Security']) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; + } + mdx += '\n'; + renderedTags.add('Security'); + } + + mdx += `---\n\n### API Endpoints\n\n`; + + // Render each category group + for (const [groupName, groupTags] of Object.entries(CATEGORY_GROUPS)) { + if (groupName === 'Authentication') continue; // Already rendered + + const tagsInGroup = groupTags.filter(tag => tagEndpoints[tag] && !renderedTags.has(tag)); + if (tagsInGroup.length === 0) continue; + + mdx += `#### ${groupName}\n\n`; + + for (const tag of tagsInGroup) { + const description = tagDescriptions[tag] || ''; + const endpoints = tagEndpoints[tag]; + + mdx += `<details>\n`; + mdx += `<summary><strong>${tag}</strong> (${endpoints.length} endpoints) — ${description}</summary>\n\n`; + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + + for (const ep of endpoints) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; Review Comment: **Suggestion:** In the grouped category sections, endpoint links are built as `./api/${ep.slug}` from the `/docs/api` page, which resolves to `/docs/api/api/<slug>` and thus does not match the actual OpenAPI-generated routes under `/docs/api/<slug>`. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ Category endpoint links broken on API index page. - ⚠️ Users cannot open endpoint docs from categories. - ⚠️ Documentation navigation is confusing. ``` </details> ```suggestion mdx += `| \`${ep.method}\` | [${ep.summary}](./${ep.slug}) | \`${ep.path}\` |\n`; ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Execute docs/scripts/generate-api-index.mjs to produce docs/docs/api.mdx (script writes output at docs/scripts/generate-api-index.mjs:234-235). The category sections use the loop at docs/scripts/generate-api-index.mjs:176-201 and produce per-endpoint links using the template at lines 194-196. 2. Serve docs (yarn start) and navigate to /docs/api/ where the category tables are displayed. 3. Click any endpoint link inside a grouped category. The anchor generated from the template is "./api/<slug>" (docs/scripts/generate-api-index.mjs:196) which resolves to /docs/api/api/<slug>, not /docs/api/<slug>, causing the link to fail to reach the OpenAPI-generated page. 4. Verify by inspecting the generated MDX (api.mdx) or browser link target; fix by changing the template to "./${ep.slug}" as in the improved code. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/scripts/generate-api-index.mjs **Line:** 195:195 **Comment:** *Logic Error: In the grouped category sections, endpoint links are built as `./api/${ep.slug}` from the `/docs/api` page, which resolves to `/docs/api/api/<slug>` and thus does not match the actual OpenAPI-generated routes under `/docs/api/<slug>`. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/sidebars.js: ########## @@ -107,9 +107,14 @@ const sidebars = { id: 'faq', }, { - type: 'doc', - label: 'API', - id: 'api', + type: 'category', + label: 'API Reference', + link: { + type: 'doc', + id: 'api', + }, + // eslint-disable-next-line @typescript-eslint/no-require-imports + items: require('./docs/api/sidebar.js'), Review Comment: **Suggestion:** The sidebar now unconditionally requires a generated file `./docs/api/sidebar.js`; on a fresh clone or whenever `yarn generate:api-docs` hasn't been run yet, this file does not exist, so loading `sidebars.js` (and thus running Docusaurus commands directly) will throw a "Cannot find module './docs/api/sidebar.js'" error and break the docs build; wrapping the require with a try/catch and falling back to an empty array makes the configuration robust while still using the generated sidebar when available. [possible bug] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ Local docs dev server fails to start. - ❌ CI docs build fails on fresh clones. - ⚠️ New contributors blocked running docs locally. - ⚠️ Release docs automation may break without generation. ``` </details> ```suggestion items: (() => { try { // Generated by `yarn generate:api-docs` return require('./docs/api/sidebar.js'); } catch (error) { // Fallback when API sidebar has not been generated yet return []; } })(), ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Clone the repository and do not run the API generation step (skip `yarn generate:api-docs`), so `docs/api/sidebar.js` is absent. 2. From the repository root run the docs dev server in the docs directory: `cd docs && yarn start`. Docusaurus loads `docs/sidebars.js` during startup. 3. `docs/sidebars.js` (file path: `docs/sidebars.js`, lines 107-118) executes the line `items: require('./docs/api/sidebar.js')` and Node attempts to resolve `./docs/api/sidebar.js`. 4. Because `./docs/api/sidebar.js` does not exist, Node throws "Cannot find module './docs/api/sidebar.js'" and the Docusaurus build/dev server fails to start — observable as a startup error in the terminal where `yarn start` was run. 5. Repeating in CI: any CI job that runs docs build without first generating the API docs will reproduce the same failure during the docs build step (the exact failing location is `docs/sidebars.js:107-118` as shown above). Note: This is not hypothetical — the PR introduced an unconditional require for a generated file (`./docs/api/sidebar.js`) in `docs/sidebars.js` (lines 107-118), so a fresh clone or skipped generation step will trigger this error. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/sidebars.js **Line:** 115:117 **Comment:** *Possible Bug: The sidebar now unconditionally requires a generated file `./docs/api/sidebar.js`; on a fresh clone or whenever `yarn generate:api-docs` hasn't been run yet, this file does not exist, so loading `sidebars.js` (and thus running Docusaurus commands directly) will throw a "Cannot find module './docs/api/sidebar.js'" error and break the docs build; wrapping the require with a try/catch and falling back to an empty array makes the configuration robust while still using the generated sidebar when available. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/docusaurus.config.ts: ########## @@ -189,6 +195,29 @@ const config: Config = { }, ], ...dynamicPlugins, + [ + 'docusaurus-plugin-openapi-docs', + { + id: 'api', + docsPluginId: 'classic', Review Comment: **Suggestion:** The OpenAPI docs plugin is configured to attach to a docs plugin with id `classic`, but in this configuration the main docs plugin created by the `@docusaurus/preset-classic` preset has no explicit `id` and therefore uses the default id (`default`), so the OpenAPI plugin will not find the expected docs instance and `docusaurus gen-api-docs superset`/builds can fail with "docs plugin not found" errors. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ API docs generation fails during docs build. - ⚠️ Contributor local docs workflow blocked. - ⚠️ CI docs build may fail for PRs touching docs. - ❌ /docs/api pages won't be produced. ``` </details> ```suggestion docsPluginId: 'default', ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Open the Docusaurus site config at docs/docusaurus.config.ts and locate the preset docs block starting at `presets` around `docs/docusaurus.config.ts:372` where the preset classic's docs options are defined (see `docs: { sidebarPath: require.resolve('./sidebars.js'), ... }` at ~line 374). This preset registers the docs plugin without an explicit id (so it uses the default id `default`). 2. Inspect the OpenAPI plugin configuration at `docs/docusaurus.config.ts:199-219` where the plugin is registered. The plugin is configured with `docsPluginId: 'classic'` (exact line: `docs/docusaurus.config.ts:202`). 3. Run the docs build or generation step (e.g., from repository root: `cd docs && yarn start` or `yarn build`). During startup Docusaurus initializes plugins; the openapi plugin will attempt to look up the docs plugin instance by id `'classic'`. 4. Because the preset-registered docs plugin has no id (it is the default `default`), the openapi plugin cannot find a docs instance named `'classic'` and the generation step errors with messages such as "docs plugin not found" or "Cannot find docs plugin with id 'classic'". This prevents API docs from being generated and the site build from completing. Note: I verified the two locations above in the final file: the preset docs block (no explicit id) at the presets section (~line 372-380) and the openapi plugin config containing `docsPluginId: 'classic'` at line 202 in `docs/docusaurus.config.ts`. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/docusaurus.config.ts **Line:** 202:202 **Comment:** *Logic Error: The OpenAPI docs plugin is configured to attach to a docs plugin with id `classic`, but in this configuration the main docs plugin created by the `@docusaurus/preset-classic` preset has no explicit `id` and therefore uses the default id (`default`), so the OpenAPI plugin will not find the expected docs instance and `docusaurus gen-api-docs superset`/builds can fail with "docs plugin not found" errors. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/scripts/generate-api-index.mjs: ########## @@ -0,0 +1,240 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Generates a comprehensive API index MDX file from the OpenAPI spec. + * This creates the api.mdx landing page with all endpoints organized by category. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const SPEC_PATH = path.join(__dirname, '..', 'static', 'resources', 'openapi.json'); +const OUTPUT_PATH = path.join(__dirname, '..', 'docs', 'api.mdx'); + +// Category groupings for better organization +const CATEGORY_GROUPS = { + 'Authentication': ['Security'], + 'Core Resources': ['Dashboards', 'Charts', 'Datasets', 'Database'], + 'Data Exploration': ['Explore', 'SQL Lab', 'Queries', 'Datasources', 'Advanced Data Type'], + 'Organization & Customization': ['Tags', 'Annotation Layers', 'CSS Templates'], + 'Sharing & Embedding': [ + 'Dashboard Permanent Link', 'Explore Permanent Link', 'SQL Lab Permanent Link', + 'Embedded Dashboard', 'Dashboard Filter State', 'Explore Form Data' + ], + 'Scheduling & Alerts': ['Report Schedules'], + 'Security & Access Control': [ + 'Security Roles', 'Security Users', 'Security Permissions', + 'Security Resources (View Menus)', 'Security Permissions on Resources (View Menus)', + 'Row Level Security' + ], + 'Import/Export & Administration': ['Import/export', 'CacheRestApi', 'LogRestApi'], + 'User & System': ['Current User', 'User', 'Menu', 'Available Domains', 'AsyncEventsRestApi', 'OpenApi'], +}; + +function slugify(text) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)/g, ''); +} + +function generateEndpointLink(summary) { + // Convert summary to the slug format used by docusaurus-openapi-docs + return slugify(summary); +} + +function main() { + console.log(`Reading OpenAPI spec from ${SPEC_PATH}`); + const spec = JSON.parse(fs.readFileSync(SPEC_PATH, 'utf-8')); + + // Build a map of tag -> endpoints + const tagEndpoints = {}; + const tagDescriptions = {}; + + // Get tag descriptions + for (const tag of spec.tags || []) { + tagDescriptions[tag.name] = tag.description || ''; + } + + // Collect endpoints by tag + for (const [pathUrl, methods] of Object.entries(spec.paths || {})) { + for (const [method, details] of Object.entries(methods)) { + if (!['get', 'post', 'put', 'delete', 'patch'].includes(method)) continue; + + const tags = details.tags || ['Untagged']; + const summary = details.summary || `${method.toUpperCase()} ${pathUrl}`; + + for (const tag of tags) { + if (!tagEndpoints[tag]) { + tagEndpoints[tag] = []; + } + tagEndpoints[tag].push({ + method: method.toUpperCase(), + path: pathUrl, + summary, + slug: generateEndpointLink(summary), + }); + } + } + } + + // Sort endpoints within each tag by path + for (const tag of Object.keys(tagEndpoints)) { + tagEndpoints[tag].sort((a, b) => a.path.localeCompare(b.path)); + } + + // Generate MDX content + let mdx = `--- +title: API Reference +hide_title: true +sidebar_position: 10 +--- + +import { Alert } from 'antd'; + +## REST API Reference + +Superset exposes a comprehensive **REST API** that follows the [OpenAPI specification](https://swagger.io/specification/). +You can use this API to programmatically interact with Superset for automation, integrations, and custom applications. + +<Alert + type="info" + showIcon + message="Code Samples & Schema Documentation" + description={ + <span> + Each endpoint includes ready-to-use code samples in <strong>cURL</strong>, <strong>Python</strong>, and <strong>JavaScript</strong>. + Browse the <a href="./api/schemas">Schema definitions</a> for detailed data model documentation. + </span> + } + style={{ marginBottom: '24px' }} +/> + +--- + +`; + + // Track which tags we've rendered + const renderedTags = new Set(); + + // Render Authentication first (it's critical for using the API) + mdx += `### Authentication + +Most API endpoints require authentication via JWT tokens. + +#### Quick Start + +\`\`\`bash +# 1. Get a JWT token +curl -X POST http://localhost:8088/api/v1/security/login \\ + -H "Content-Type: application/json" \\ + -d '{"username": "admin", "password": "admin", "provider": "db"}' + +# 2. Use the access_token from the response +curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\ + http://localhost:8088/api/v1/dashboard/ +\`\`\` + +#### Security Endpoints + +`; + + // Render Security tag endpoints + if (tagEndpoints['Security']) { + mdx += `| Method | Endpoint | Description |\n`; + mdx += `|--------|----------|-------------|\n`; + for (const ep of tagEndpoints['Security']) { + mdx += `| \`${ep.method}\` | [${ep.summary}](./api/${ep.slug}) | \`${ep.path}\` |\n`; Review Comment: **Suggestion:** In the "Security Endpoints" table, each endpoint link uses `./api/${ep.slug}` from the `/docs/api` page, which resolves to `/docs/api/api/<slug>` instead of `/docs/api/<slug>`, so all Security endpoint links will be broken. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ Security endpoint links 404 on /docs/api. - ⚠️ Readers cannot access Security API docs easily. - ⚠️ Navigation inconsistency in generated API index. ``` </details> ```suggestion mdx += `| \`${ep.method}\` | [${ep.summary}](./${ep.slug}) | \`${ep.path}\` |\n`; ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Run the generator: node docs/scripts/generate-api-index.mjs (entry at docs/scripts/generate-api-index.mjs:238-240). The generator builds the Security endpoints table using the loop at docs/scripts/generate-api-index.mjs:167-169. 2. Start the docs site (yarn start) and open /docs/api/ in the browser (the generated MDX includes the table rendered from the code above). 3. Click any Security endpoint link in the "Security Endpoints" table. The rendered anchor href is "./api/<slug>" (produced at docs/scripts/generate-api-index.mjs:169), which resolves from /docs/api/ to /docs/api/api/<slug>, producing a 404 because the actual endpoint pages are served at /docs/api/<slug>. 4. Confirm the incorrect path is produced by the exact template string in the file at lines 167-169; updating the template to "./${ep.slug}" removes the duplicated "api" segment and fixes links. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/scripts/generate-api-index.mjs **Line:** 168:168 **Comment:** *Logic Error: In the "Security Endpoints" table, each endpoint link uses `./api/${ep.slug}` from the `/docs/api` page, which resolves to `/docs/api/api/<slug>` instead of `/docs/api/<slug>`, so all Security endpoint links will be broken. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> ########## docs/scripts/generate-api-index.mjs: ########## @@ -0,0 +1,240 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Generates a comprehensive API index MDX file from the OpenAPI spec. + * This creates the api.mdx landing page with all endpoints organized by category. + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const SPEC_PATH = path.join(__dirname, '..', 'static', 'resources', 'openapi.json'); +const OUTPUT_PATH = path.join(__dirname, '..', 'docs', 'api.mdx'); + +// Category groupings for better organization +const CATEGORY_GROUPS = { + 'Authentication': ['Security'], + 'Core Resources': ['Dashboards', 'Charts', 'Datasets', 'Database'], + 'Data Exploration': ['Explore', 'SQL Lab', 'Queries', 'Datasources', 'Advanced Data Type'], + 'Organization & Customization': ['Tags', 'Annotation Layers', 'CSS Templates'], + 'Sharing & Embedding': [ + 'Dashboard Permanent Link', 'Explore Permanent Link', 'SQL Lab Permanent Link', + 'Embedded Dashboard', 'Dashboard Filter State', 'Explore Form Data' + ], + 'Scheduling & Alerts': ['Report Schedules'], + 'Security & Access Control': [ + 'Security Roles', 'Security Users', 'Security Permissions', + 'Security Resources (View Menus)', 'Security Permissions on Resources (View Menus)', + 'Row Level Security' + ], + 'Import/Export & Administration': ['Import/export', 'CacheRestApi', 'LogRestApi'], + 'User & System': ['Current User', 'User', 'Menu', 'Available Domains', 'AsyncEventsRestApi', 'OpenApi'], +}; + +function slugify(text) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/(^-|-$)/g, ''); +} + +function generateEndpointLink(summary) { + // Convert summary to the slug format used by docusaurus-openapi-docs + return slugify(summary); +} + +function main() { + console.log(`Reading OpenAPI spec from ${SPEC_PATH}`); + const spec = JSON.parse(fs.readFileSync(SPEC_PATH, 'utf-8')); + + // Build a map of tag -> endpoints + const tagEndpoints = {}; + const tagDescriptions = {}; + + // Get tag descriptions + for (const tag of spec.tags || []) { + tagDescriptions[tag.name] = tag.description || ''; + } + + // Collect endpoints by tag + for (const [pathUrl, methods] of Object.entries(spec.paths || {})) { + for (const [method, details] of Object.entries(methods)) { + if (!['get', 'post', 'put', 'delete', 'patch'].includes(method)) continue; + + const tags = details.tags || ['Untagged']; + const summary = details.summary || `${method.toUpperCase()} ${pathUrl}`; + + for (const tag of tags) { + if (!tagEndpoints[tag]) { + tagEndpoints[tag] = []; + } + tagEndpoints[tag].push({ + method: method.toUpperCase(), + path: pathUrl, + summary, + slug: generateEndpointLink(summary), + }); + } + } + } + + // Sort endpoints within each tag by path + for (const tag of Object.keys(tagEndpoints)) { + tagEndpoints[tag].sort((a, b) => a.path.localeCompare(b.path)); + } + + // Generate MDX content + let mdx = `--- +title: API Reference +hide_title: true +sidebar_position: 10 +--- + +import { Alert } from 'antd'; + +## REST API Reference + +Superset exposes a comprehensive **REST API** that follows the [OpenAPI specification](https://swagger.io/specification/). +You can use this API to programmatically interact with Superset for automation, integrations, and custom applications. + +<Alert + type="info" + showIcon + message="Code Samples & Schema Documentation" + description={ + <span> + Each endpoint includes ready-to-use code samples in <strong>cURL</strong>, <strong>Python</strong>, and <strong>JavaScript</strong>. + Browse the <a href="./api/schemas">Schema definitions</a> for detailed data model documentation. Review Comment: **Suggestion:** The schema documentation link inside the `<Alert>` component uses `./api/schemas` as a relative URL, which from the `/docs/api` page resolves to `/docs/api/api/schemas` instead of the intended `/docs/api/schemas`, causing the "Schema definitions" link to be broken. [logic error] <details> <summary><b>Severity Level:</b> Critical 🚨</summary> ```mdx - ❌ Schema definitions link broken on /docs/api landing page. - ⚠️ Users cannot navigate to schema docs from API index. - ⚠️ Developer docs quality degraded for API consumers. ``` </details> ```suggestion Browse the <a href="./schemas">Schema definitions</a> for detailed data model documentation. ``` <details> <summary><b>Steps of Reproduction ✅ </b></summary> ```mdx 1. Run the generator and build docs: node docs/scripts/generate-api-index.mjs will write docs/docs/api.mdx (script file: docs/scripts/generate-api-index.mjs: lines 67-75, 234-236 show entry and write). The file contains the Alert block at docs/scripts/generate-api-index.mjs:114-132 which produces the hyperlink <a href="./api/schemas">. 2. Start Docusaurus dev server from the docs/ directory (yarn start). Open the generated API landing page served at path /docs/api/ (this is the page that corresponds to the generated api.mdx). 3. From browser on URL /docs/api/ the anchor with href="./api/schemas" resolves to /docs/api/api/schemas (relative resolution: current path + ./api/schemas) instead of the intended /docs/api/schemas. Confirm the resulting URL returns 404 or does not load the schemas page. 4. Observe broken link behavior tied directly to the literal href produced by the code in docs/scripts/generate-api-index.mjs at lines 114-132. Changing the href to "./schemas" (improved code) generates a link that resolves to /docs/api/schemas as intended. ``` </details> <details> <summary><b>Prompt for AI Agent 🤖 </b></summary> ```mdx This is a comment left during a code review. **Path:** docs/scripts/generate-api-index.mjs **Line:** 121:128 **Comment:** *Logic Error: The schema documentation link inside the `<Alert>` component uses `./api/schemas` as a relative URL, which from the `/docs/api` page resolves to `/docs/api/api/schemas` instead of the intended `/docs/api/schemas`, causing the "Schema definitions" link to be broken. Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. ``` </details> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
