chore: remove design files
parent
e841ae15ca
commit
ed65fb4bee
|
|
@ -1,181 +0,0 @@
|
|||
# Standalone API Operation Pages Design
|
||||
|
||||
## Overview
|
||||
|
||||
Create individual pages for each API operation with path-based URLs, rendered using RapiDoc Mini with existing tag-level OpenAPI specs.
|
||||
|
||||
## Goals
|
||||
|
||||
- **SEO/discoverability**: Each operation indexable with its own URL and metadata
|
||||
- **Deep linking**: Reliable bookmarkable/shareable URLs for specific operations
|
||||
- **Navigation UX**: Sidebar links navigate to actual pages (not hash fragments)
|
||||
- **Content customization**: Foundation for adding operation-specific guides and examples
|
||||
|
||||
## URL Structure
|
||||
|
||||
Path-based URLs with HTTP method as the final segment:
|
||||
|
||||
| Operation | API Path | Page URL |
|
||||
| ------------------ | ----------------------------------- | ------------------------------------ |
|
||||
| PostV1Write | `POST /write` | `/api/write/post/` |
|
||||
| PostV2Write | `POST /api/v2/write` | `/api/v2/write/post/` |
|
||||
| PostWriteLP | `POST /api/v3/write_lp` | `/api/v3/write_lp/post/` |
|
||||
| GetV1ExecuteQuery | `GET /query` | `/api/query/get/` |
|
||||
| PostExecuteV1Query | `POST /query` | `/api/query/post/` |
|
||||
| GetExecuteQuerySQL | `GET /api/v3/query_sql` | `/api/v3/query_sql/get/` |
|
||||
| GetDatabases | `GET /api/v3/configure/database` | `/api/v3/configure/database/get/` |
|
||||
| DeleteDatabase | `DELETE /api/v3/configure/database` | `/api/v3/configure/database/delete/` |
|
||||
|
||||
## Architecture
|
||||
|
||||
### Existing Components (unchanged)
|
||||
|
||||
- **Tag pages**: `/api/write-data/`, `/api/query-data/` etc. remain as landing pages
|
||||
- **Tag-level specs**: `static/openapi/influxdb-{product}/tags/tags/ref-{tag}.yaml` (\~30-50KB each)
|
||||
- **Sidebar structure**: Tag-based groups with operation summaries as link text
|
||||
|
||||
### New Components
|
||||
|
||||
1. **Operation page content files**: Generated at path-based locations
|
||||
2. **Operation page template**: Hugo layout using RapiDoc Mini
|
||||
3. **Updated sidebar links**: Point to path-based URLs instead of hash fragments
|
||||
|
||||
## Content File Structure
|
||||
|
||||
Generated operation pages at `content/influxdb3/{product}/api/{path}/{method}/_index.md`:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Write line protocol (v1-compatible)
|
||||
description: Write data using InfluxDB v1-compatible line protocol endpoint
|
||||
type: api-operation
|
||||
layout: operation
|
||||
# RapiDoc Mini configuration
|
||||
specFile: /openapi/influxdb-influxdb3_core/tags/tags/ref-write-data.yaml
|
||||
matchPaths: post /write
|
||||
# Operation metadata
|
||||
operationId: PostV1Write
|
||||
method: POST
|
||||
apiPath: /write
|
||||
tag: Write data
|
||||
compatVersion: v1
|
||||
# Links
|
||||
related:
|
||||
- /influxdb3/core/write-data/http-api/compatibility-apis/
|
||||
---
|
||||
```
|
||||
|
||||
## Hugo Template
|
||||
|
||||
New layout `layouts/api-operation/operation.html`:
|
||||
|
||||
```html
|
||||
{{ define "main" }}
|
||||
<article class="api-operation-page">
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
<div class="api-operation-meta">
|
||||
<span class="api-method api-method--{{ lower .Params.method }}">{{ .Params.method }}</span>
|
||||
<code class="api-path">{{ .Params.apiPath }}</code>
|
||||
{{ with .Params.compatVersion }}
|
||||
<span class="api-compat-badge api-compat-badge--{{ . }}">{{ . }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<rapi-doc-mini
|
||||
spec-url="{{ .Params.specFile }}"
|
||||
match-paths="{{ .Params.matchPaths }}"
|
||||
theme="light"
|
||||
bg-color="transparent"
|
||||
paths-expanded="true"
|
||||
schema-expand-level="1">
|
||||
</rapi-doc-mini>
|
||||
|
||||
{{ with .Params.related }}
|
||||
<aside class="related-content">
|
||||
<h2>Related documentation</h2>
|
||||
<ul>
|
||||
{{ range . }}
|
||||
<li><a href="{{ . }}">{{ . }}</a></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</aside>
|
||||
{{ end }}
|
||||
</article>
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
## Sidebar Navigation Changes
|
||||
|
||||
Update `layouts/partials/sidebar/api-menu-items.html` to generate path-based URLs:
|
||||
|
||||
**Before:**
|
||||
|
||||
```go
|
||||
{{ $fragment := printf "#operation/%s" .operationId }}
|
||||
{{ $fullUrl := printf "%s%s" $tagPageUrl $fragment }}
|
||||
```
|
||||
|
||||
**After:**
|
||||
|
||||
```go
|
||||
{{ $apiPath := .path }}
|
||||
{{ $method := lower .method }}
|
||||
{{ $pathSlug := $apiPath | replaceRE "^/" "" }}
|
||||
{{ $operationUrl := printf "/%s/%s/api/%s/%s/" $product $version $pathSlug $method | relURL }}
|
||||
```
|
||||
|
||||
## Generator Changes
|
||||
|
||||
Update `api-docs/scripts/openapi-paths-to-hugo-data/index.ts`:
|
||||
|
||||
1. Add new function `generateOperationPages()` that creates content files for each operation
|
||||
2. Include operation metadata: specFile path, matchPaths filter, tag association
|
||||
3. Call from `generateHugoDataByTag()` after generating tag-based articles
|
||||
|
||||
## File Generation Summary
|
||||
|
||||
For InfluxDB 3 Core (\~43 operations), this creates:
|
||||
|
||||
- \~43 new content files at `content/influxdb3/core/api/{path}/{method}/_index.md`
|
||||
- No new spec files (reuses existing tag-level specs)
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
OpenAPI Spec
|
||||
↓
|
||||
Generator extracts operations
|
||||
↓
|
||||
Creates content files with frontmatter (specFile, matchPaths, metadata)
|
||||
↓
|
||||
Hugo builds pages using api-operation/operation.html template
|
||||
↓
|
||||
RapiDoc Mini loads tag-level spec, filters to single operation client-side
|
||||
```
|
||||
|
||||
## Testing Plan
|
||||
|
||||
1. Generate operation pages for Core product
|
||||
2. Verify URLs resolve correctly
|
||||
3. Verify RapiDoc Mini renders single operation
|
||||
4. Verify sidebar links navigate to operation pages
|
||||
5. Test deep linking (direct URL access)
|
||||
6. Check page titles and meta descriptions for SEO
|
||||
|
||||
## Future Improvements
|
||||
|
||||
- Generate operation-level specs for smaller payloads (if performance issues arise)
|
||||
- Add custom content sections per operation
|
||||
- Implement operation search/filtering on tag pages
|
||||
|
||||
## Migration Notes
|
||||
|
||||
When migrating other product specs from Redoc to RapiDoc:
|
||||
|
||||
1. **Remove `x-tagGroups`**: This is a Redoc-specific extension for sidebar navigation grouping. RapiDoc doesn't use it. The Hugo sidebar uses `data/api_nav_groups.yml` instead.
|
||||
|
||||
2. **Ensure tag consistency**: The sidebar navigation (`api_nav_groups.yml`) must match the tag names in the spec's `tags` section exactly.
|
||||
|
||||
3. **Single-tag operations**: Operations should ideally have a single tag to avoid duplicate rendering. If an operation has multiple tags, the generator restricts it to the primary tag in tag-specific specs.
|
||||
|
|
@ -1,779 +0,0 @@
|
|||
# API Code Review Fixes Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Fix code review violations by extracting inline JavaScript from rapidoc.html into a TypeScript component and removing unused Scalar renderer code.
|
||||
|
||||
**Architecture:** Create a new `api-rapidoc.ts` TypeScript component following the established component pattern (same as `rapidoc-mini.ts`). The component handles theme synchronization, shadow DOM manipulation, and MutationObserver setup. Remove the Scalar renderer, api-tabs component, and associated partials since they're no longer used.
|
||||
|
||||
**Tech Stack:** TypeScript, Hugo templates, SCSS, Cypress
|
||||
|
||||
***
|
||||
|
||||
## Task 1: Create api-rapidoc.ts TypeScript Component
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `assets/js/components/api-rapidoc.ts`
|
||||
|
||||
**Step 1: Create the TypeScript component file**
|
||||
|
||||
Create `assets/js/components/api-rapidoc.ts` with the following content:
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* RapiDoc API Documentation Component
|
||||
*
|
||||
* Initializes the full RapiDoc renderer with theme synchronization.
|
||||
* This is the component version of the inline JavaScript from rapidoc.html.
|
||||
*
|
||||
* Features:
|
||||
* - Theme detection from Hugo's stylesheet toggle system
|
||||
* - Automatic theme synchronization when user toggles dark/light mode
|
||||
* - Shadow DOM manipulation to hide unwanted UI elements
|
||||
* - CSS custom property injection for styling
|
||||
*
|
||||
* Usage:
|
||||
* <div data-component="api-rapidoc" data-spec-url="/path/to/spec.yml"></div>
|
||||
*
|
||||
* The component expects a <rapi-doc> element to already exist in the container
|
||||
* (created by Hugo template) or will wait for it to be added.
|
||||
*/
|
||||
|
||||
import { getPreference } from '../services/local-storage.js';
|
||||
|
||||
interface ComponentOptions {
|
||||
component: HTMLElement;
|
||||
}
|
||||
|
||||
interface ThemeColors {
|
||||
theme: 'light' | 'dark';
|
||||
bgColor: string;
|
||||
textColor: string;
|
||||
headerColor: string;
|
||||
primaryColor: string;
|
||||
navBgColor: string;
|
||||
navTextColor: string;
|
||||
navHoverBgColor: string;
|
||||
navHoverTextColor: string;
|
||||
navAccentColor: string;
|
||||
codeTheme: string;
|
||||
}
|
||||
|
||||
type CleanupFn = () => void;
|
||||
|
||||
/**
|
||||
* Get current theme from localStorage (source of truth for Hugo theme system)
|
||||
*/
|
||||
function getTheme(): 'dark' | 'light' {
|
||||
const theme = getPreference('theme');
|
||||
return theme === 'dark' ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get theme colors matching Hugo SCSS variables
|
||||
*/
|
||||
function getThemeColors(isDark: boolean): ThemeColors {
|
||||
if (isDark) {
|
||||
return {
|
||||
theme: 'dark',
|
||||
bgColor: '#14141F', // $grey10 ($article-bg in dark theme)
|
||||
textColor: '#D4D7DD', // $g15-platinum
|
||||
headerColor: '#D4D7DD',
|
||||
primaryColor: '#a0a0ff',
|
||||
navBgColor: '#1a1a2a',
|
||||
navTextColor: '#D4D7DD',
|
||||
navHoverBgColor: '#252535',
|
||||
navHoverTextColor: '#ffffff',
|
||||
navAccentColor: '#a0a0ff',
|
||||
codeTheme: 'monokai',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
theme: 'light',
|
||||
bgColor: '#ffffff', // $g20-white
|
||||
textColor: '#2b2b2b',
|
||||
headerColor: '#020a47', // $br-dark-blue
|
||||
primaryColor: '#020a47',
|
||||
navBgColor: '#f7f8fa',
|
||||
navTextColor: '#2b2b2b',
|
||||
navHoverBgColor: '#e8e8f0',
|
||||
navHoverTextColor: '#020a47',
|
||||
navAccentColor: '#020a47',
|
||||
codeTheme: 'prism',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply theme to RapiDoc element
|
||||
*/
|
||||
function applyTheme(rapiDoc: HTMLElement): void {
|
||||
const isDark = getTheme() === 'dark';
|
||||
const colors = getThemeColors(isDark);
|
||||
|
||||
rapiDoc.setAttribute('theme', colors.theme);
|
||||
rapiDoc.setAttribute('bg-color', colors.bgColor);
|
||||
rapiDoc.setAttribute('text-color', colors.textColor);
|
||||
rapiDoc.setAttribute('header-color', colors.headerColor);
|
||||
rapiDoc.setAttribute('primary-color', colors.primaryColor);
|
||||
rapiDoc.setAttribute('nav-bg-color', colors.navBgColor);
|
||||
rapiDoc.setAttribute('nav-text-color', colors.navTextColor);
|
||||
rapiDoc.setAttribute('nav-hover-bg-color', colors.navHoverBgColor);
|
||||
rapiDoc.setAttribute('nav-hover-text-color', colors.navHoverTextColor);
|
||||
rapiDoc.setAttribute('nav-accent-color', colors.navAccentColor);
|
||||
rapiDoc.setAttribute('code-theme', colors.codeTheme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom CSS properties on RapiDoc element
|
||||
*/
|
||||
function setInputBorderStyles(rapiDoc: HTMLElement): void {
|
||||
rapiDoc.style.setProperty('--border-color', '#00A3FF');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide unwanted elements in RapiDoc shadow DOM
|
||||
*/
|
||||
function hideExpandCollapseControls(rapiDoc: HTMLElement): void {
|
||||
const maxAttempts = 10;
|
||||
let attempts = 0;
|
||||
|
||||
const tryHide = (): void => {
|
||||
attempts++;
|
||||
|
||||
try {
|
||||
const shadowRoot = rapiDoc.shadowRoot;
|
||||
if (!shadowRoot) {
|
||||
if (attempts < maxAttempts) {
|
||||
setTimeout(tryHide, 500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all elements and hide those containing "Expand all" / "Collapse all"
|
||||
const allElements = shadowRoot.querySelectorAll('*');
|
||||
let hiddenCount = 0;
|
||||
|
||||
allElements.forEach((element) => {
|
||||
const text = element.textContent || '';
|
||||
|
||||
if (text.includes('Expand all') || text.includes('Collapse all')) {
|
||||
(element as HTMLElement).style.display = 'none';
|
||||
if (element.parentElement) {
|
||||
element.parentElement.style.display = 'none';
|
||||
}
|
||||
hiddenCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Hide "Overview" headings
|
||||
const headings = shadowRoot.querySelectorAll('h1, h2, h3, h4');
|
||||
headings.forEach((heading) => {
|
||||
const text = (heading.textContent || '').trim();
|
||||
if (text.includes('Overview')) {
|
||||
(heading as HTMLElement).style.display = 'none';
|
||||
hiddenCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// Inject CSS as backup
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.section-gap.section-tag,
|
||||
[id*="overview"],
|
||||
.regular-font.section-gap:empty,
|
||||
h1:empty, h2:empty, h3:empty {
|
||||
display: none !important;
|
||||
}
|
||||
`;
|
||||
shadowRoot.appendChild(style);
|
||||
|
||||
if (hiddenCount === 0 && attempts < maxAttempts) {
|
||||
setTimeout(tryHide, 500);
|
||||
}
|
||||
} catch (e) {
|
||||
if (attempts < maxAttempts) {
|
||||
setTimeout(tryHide, 500);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(tryHide, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch for theme changes via stylesheet toggle
|
||||
*/
|
||||
function watchThemeChanges(rapiDoc: HTMLElement): CleanupFn {
|
||||
const handleThemeChange = (): void => {
|
||||
applyTheme(rapiDoc);
|
||||
};
|
||||
|
||||
// Watch stylesheet disabled attribute changes (Hugo theme.js toggles this)
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (
|
||||
mutation.type === 'attributes' &&
|
||||
mutation.target instanceof HTMLLinkElement &&
|
||||
mutation.target.title?.includes('theme')
|
||||
) {
|
||||
handleThemeChange();
|
||||
break;
|
||||
}
|
||||
// Also watch data-theme changes as fallback
|
||||
if (mutation.attributeName === 'data-theme') {
|
||||
handleThemeChange();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Observe head for stylesheet changes
|
||||
observer.observe(document.head, {
|
||||
attributes: true,
|
||||
attributeFilter: ['disabled'],
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
// Observe documentElement for data-theme changes
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
|
||||
return (): void => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize RapiDoc component
|
||||
*/
|
||||
export default function ApiRapiDoc({
|
||||
component,
|
||||
}: ComponentOptions): CleanupFn | void {
|
||||
// Find the rapi-doc element inside the container
|
||||
const rapiDoc = component.querySelector('rapi-doc') as HTMLElement | null;
|
||||
|
||||
if (!rapiDoc) {
|
||||
console.warn('[API RapiDoc] No rapi-doc element found in container');
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply initial theme
|
||||
applyTheme(rapiDoc);
|
||||
|
||||
// Set custom CSS properties
|
||||
if (customElements && customElements.whenDefined) {
|
||||
customElements.whenDefined('rapi-doc').then(() => {
|
||||
setInputBorderStyles(rapiDoc);
|
||||
setTimeout(() => setInputBorderStyles(rapiDoc), 500);
|
||||
});
|
||||
} else {
|
||||
setInputBorderStyles(rapiDoc);
|
||||
setTimeout(() => setInputBorderStyles(rapiDoc), 500);
|
||||
}
|
||||
|
||||
// Hide unwanted UI elements
|
||||
hideExpandCollapseControls(rapiDoc);
|
||||
|
||||
// Watch for theme changes
|
||||
return watchThemeChanges(rapiDoc);
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: Verify the file was created correctly**
|
||||
|
||||
Run: `head -30 assets/js/components/api-rapidoc.ts`
|
||||
Expected: File header and imports visible
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add assets/js/components/api-rapidoc.ts
|
||||
git commit -m "feat(api): Create api-rapidoc TypeScript component
|
||||
|
||||
Extract inline JavaScript from rapidoc.html into a proper TypeScript
|
||||
component following the established component pattern."
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 2: Register api-rapidoc Component in main.js
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `assets/js/main.js:49-88`
|
||||
|
||||
**Step 1: Add import for ApiRapiDoc**
|
||||
|
||||
Add this import after line 52 (after RapiDocMini import):
|
||||
|
||||
```javascript
|
||||
import ApiRapiDoc from './components/api-rapidoc.ts';
|
||||
```
|
||||
|
||||
**Step 2: Register component in componentRegistry**
|
||||
|
||||
Add this entry in the componentRegistry object (after line 87, the 'rapidoc-mini' entry):
|
||||
|
||||
```javascript
|
||||
'api-rapidoc': ApiRapiDoc,
|
||||
```
|
||||
|
||||
**Step 3: Verify changes**
|
||||
|
||||
Run: `grep -n "api-rapidoc\|ApiRapiDoc" assets/js/main.js`
|
||||
Expected: Both the import and registry entry appear
|
||||
|
||||
**Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add assets/js/main.js
|
||||
git commit -m "feat(api): Register api-rapidoc component in main.js"
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 3: Update rapidoc.html to Use Component Pattern
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `layouts/partials/api/rapidoc.html`
|
||||
|
||||
**Step 1: Replace inline JavaScript with data-component attribute**
|
||||
|
||||
Replace the entire content of `layouts/partials/api/rapidoc.html` with:
|
||||
|
||||
```html
|
||||
{{/*
|
||||
RapiDoc API Documentation Renderer
|
||||
|
||||
Primary API documentation renderer using RapiDoc with "Mix your own HTML" slots.
|
||||
See: https://rapidocweb.com/examples.html
|
||||
|
||||
Required page params:
|
||||
- staticFilePath: Path to the OpenAPI specification file
|
||||
|
||||
Optional page params:
|
||||
- operationId: Specific operation to display (renders only that operation)
|
||||
- tag: Tag to filter operations by
|
||||
|
||||
RapiDoc slots available for custom content:
|
||||
- slot="header" - Custom header
|
||||
- slot="footer" - Custom footer
|
||||
- slot="overview" - Custom overview content
|
||||
- slot="auth" - Custom authentication section
|
||||
- slot="nav-logo" - Custom navigation logo
|
||||
*/}}
|
||||
|
||||
{{ $specPath := .Params.staticFilePath }}
|
||||
{{ $specPathJSON := replace $specPath ".yaml" ".json" | replace ".yml" ".json" }}
|
||||
{{ $operationId := .Params.operationId | default "" }}
|
||||
{{ $tag := .Params.tag | default "" }}
|
||||
|
||||
{{/* Machine-readable links for AI agent discovery */}}
|
||||
{{ if $specPath }}
|
||||
<link rel="alternate" type="application/x-yaml" href="{{ $specPath | absURL }}" title="OpenAPI Specification (YAML)" />
|
||||
<link rel="alternate" type="application/json" href="{{ $specPathJSON | absURL }}" title="OpenAPI Specification (JSON)" />
|
||||
{{ end }}
|
||||
|
||||
<div class="api-reference-wrapper" data-component="api-rapidoc">
|
||||
{{/* RapiDoc component with slot-based customization */}}
|
||||
<rapi-doc
|
||||
id="api-doc"
|
||||
spec-url="{{ $specPath }}"
|
||||
theme="light"
|
||||
bg-color="#ffffff"
|
||||
text-color="#2b2b2b"
|
||||
header-color="#020a47"
|
||||
primary-color="#00A3FF"
|
||||
nav-bg-color="#f7f8fa"
|
||||
nav-text-color="#2b2b2b"
|
||||
nav-hover-bg-color="#e8e8f0"
|
||||
nav-hover-text-color="#020a47"
|
||||
nav-accent-color="#020a47"
|
||||
regular-font="Proxima Nova, -apple-system, BlinkMacSystemFont, sans-serif"
|
||||
mono-font="IBM Plex Mono, Monaco, Consolas, monospace"
|
||||
font-size="large"
|
||||
render-style="view"
|
||||
layout="column"
|
||||
schema-style="table"
|
||||
default-schema-tab="model"
|
||||
response-area-height="400px"
|
||||
show-header="false"
|
||||
show-info="false"
|
||||
show-side-nav="false"
|
||||
show-components="false"
|
||||
allow-authentication="true"
|
||||
allow-try="false"
|
||||
allow-spec-url-load="false"
|
||||
allow-spec-file-load="false"
|
||||
allow-server-selection="false"
|
||||
allow-search="false"
|
||||
fill-request-fields-with-example="true"
|
||||
persist-auth="false"
|
||||
{{ if $operationId }}goto-path="op/{{ $operationId }}"{{ end }}
|
||||
{{ if $tag }}match-paths="tag/{{ $tag }}"{{ end }}
|
||||
>
|
||||
{{/* Custom overview slot - Hugo page content */}}
|
||||
{{ with .Content }}
|
||||
<div slot="overview">
|
||||
{{ . }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{/* Custom examples from frontmatter */}}
|
||||
{{ with .Params.examples }}
|
||||
<div slot="footer" class="api-custom-examples">
|
||||
<h3>Examples</h3>
|
||||
{{ range . }}
|
||||
<div class="api-example">
|
||||
<h4>{{ .title }}</h4>
|
||||
{{ with .description }}<p>{{ . | markdownify }}</p>{{ end }}
|
||||
<pre><code class="language-{{ .lang | default "bash" }}">{{ .code }}</code></pre>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</rapi-doc>
|
||||
</div>
|
||||
|
||||
{{/* Load RapiDoc from CDN */}}
|
||||
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
|
||||
|
||||
<style>
|
||||
.api-reference-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
rapi-doc {
|
||||
width: 100%;
|
||||
min-height: 600px;
|
||||
display: block;
|
||||
/* Override RapiDoc's internal font sizes to match Hugo docs */
|
||||
--font-size-small: 15px;
|
||||
--font-size-mono: 15px;
|
||||
--font-size-regular: 17px;
|
||||
/* Match Hugo theme backgrounds - light mode default */
|
||||
--bg: #ffffff;
|
||||
--bg2: #f7f8fa;
|
||||
--bg3: #eef0f3;
|
||||
/* Input field border styling - subtle with transparency */
|
||||
--border-color: rgba(0, 163, 255, 0.25);
|
||||
--light-border-color: rgba(0, 163, 255, 0.15);
|
||||
/* HTTP method colors - lighter palette for light theme */
|
||||
--blue: #00A3FF; /* $b-pool - GET */
|
||||
--green: #34BB55; /* $gr-rainforest - POST */
|
||||
--orange: #FFB94A; /* $y-pineapple - PUT (distinct from red) */
|
||||
--red: #F95F53; /* $r-curacao - DELETE */
|
||||
--purple: #9b2aff; /* $br-new-purple - PATCH */
|
||||
}
|
||||
|
||||
/* Dark mode overrides - match Hugo $grey10: #14141F */
|
||||
[data-theme="dark"] rapi-doc,
|
||||
html:has(link[title="dark-theme"]:not([disabled])) rapi-doc {
|
||||
--bg: #14141F;
|
||||
/* Subtle border colors for dark mode with transparency */
|
||||
--border-color: rgba(0, 163, 255, 0.35);
|
||||
--light-border-color: rgba(0, 163, 255, 0.2);
|
||||
--bg2: #1a1a2a;
|
||||
--bg3: #252535;
|
||||
--fg: #D4D7DD;
|
||||
--fg2: #c8ccd2;
|
||||
--fg3: #b0b4ba;
|
||||
/* HTTP method colors - darker palette for dark theme */
|
||||
--blue: #066FC5; /* $b-ocean - GET */
|
||||
--green: #009F5F; /* $gr-viridian - POST */
|
||||
--orange: #FFC800; /* $y-thunder - PUT (brighter for dark mode) */
|
||||
--red: #DC4E58; /* $r-fire - DELETE */
|
||||
--purple: #8E1FC3; /* $p-amethyst - PATCH */
|
||||
}
|
||||
|
||||
/* Custom examples section styling */
|
||||
.api-custom-examples {
|
||||
padding: 1.5rem;
|
||||
background: var(--bg2, #f7f8fa);
|
||||
border-radius: 4px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.api-custom-examples h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.api-example {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.api-example:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.api-example h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.api-example pre {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
background: var(--bg3, #eef0f3);
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**Step 2: Verify the inline script is removed**
|
||||
|
||||
Run: `grep -c "<script>" layouts/partials/api/rapidoc.html`
|
||||
Expected: `1` (only the CDN script tag, no inline JavaScript)
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add layouts/partials/api/rapidoc.html
|
||||
git commit -m "refactor(api): Replace inline JS with data-component in rapidoc.html
|
||||
|
||||
Remove ~230 lines of inline JavaScript and use the new api-rapidoc
|
||||
TypeScript component via data-component attribute instead."
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 4: Remove Scalar Renderer and Related Code
|
||||
|
||||
**Files:**
|
||||
|
||||
- Delete: `layouts/partials/api/scalar.html`
|
||||
- Delete: `assets/js/components/api-scalar.ts`
|
||||
- Modify: `layouts/partials/api/renderer.html`
|
||||
- Modify: `assets/js/main.js`
|
||||
- Modify: `config/_default/hugo.yml`
|
||||
|
||||
**Step 1: Delete scalar.html partial**
|
||||
|
||||
Run: `rm layouts/partials/api/scalar.html`
|
||||
|
||||
**Step 2: Delete api-scalar.ts component**
|
||||
|
||||
Run: `rm assets/js/components/api-scalar.ts`
|
||||
|
||||
**Step 3: Simplify renderer.html to only use RapiDoc**
|
||||
|
||||
Replace the content of `layouts/partials/api/renderer.html` with:
|
||||
|
||||
```html
|
||||
{{/*
|
||||
API Renderer
|
||||
|
||||
Renders API documentation using RapiDoc.
|
||||
|
||||
Required page params:
|
||||
- staticFilePath: Path to the OpenAPI specification file
|
||||
*/}}
|
||||
|
||||
{{ partial "api/rapidoc.html" . }}
|
||||
```
|
||||
|
||||
**Step 4: Remove ApiScalar from main.js**
|
||||
|
||||
Remove the import line:
|
||||
|
||||
```javascript
|
||||
import ApiScalar from './components/api-scalar.ts';
|
||||
```
|
||||
|
||||
Remove the registry entry:
|
||||
|
||||
```javascript
|
||||
'api-scalar': ApiScalar,
|
||||
```
|
||||
|
||||
**Step 5: Remove apiRenderer config from hugo.yml**
|
||||
|
||||
Remove these lines from `config/_default/hugo.yml`:
|
||||
|
||||
```yaml
|
||||
# API documentation renderer: "scalar" (default) or "rapidoc"
|
||||
apiRenderer: rapidoc
|
||||
```
|
||||
|
||||
**Step 6: Verify deletions**
|
||||
|
||||
Run: `ls layouts/partials/api/scalar.html assets/js/components/api-scalar.ts 2>&1`
|
||||
Expected: "No such file or directory" for both
|
||||
|
||||
Run: `grep -c "ApiScalar\|api-scalar" assets/js/main.js`
|
||||
Expected: `0`
|
||||
|
||||
**Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "refactor(api): Remove Scalar renderer and related code
|
||||
|
||||
Remove unused Scalar API documentation renderer:
|
||||
- Delete layouts/partials/api/scalar.html
|
||||
- Delete assets/js/components/api-scalar.ts
|
||||
- Simplify renderer.html to only use RapiDoc
|
||||
- Remove ApiScalar from main.js component registry
|
||||
- Remove apiRenderer config option from hugo.yml"
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 5: Remove Deprecated api-tabs Component
|
||||
|
||||
**Files:**
|
||||
|
||||
- Delete: `assets/js/components/api-tabs.ts`
|
||||
- Delete: `layouts/partials/api/tabs.html`
|
||||
- Delete: `layouts/partials/api/tab-panels.html`
|
||||
- Modify: `assets/js/main.js`
|
||||
|
||||
**Step 1: Delete api-tabs.ts**
|
||||
|
||||
Run: `rm assets/js/components/api-tabs.ts`
|
||||
|
||||
**Step 2: Delete tabs.html partial**
|
||||
|
||||
Run: `rm layouts/partials/api/tabs.html`
|
||||
|
||||
**Step 3: Delete tab-panels.html partial**
|
||||
|
||||
Run: `rm layouts/partials/api/tab-panels.html`
|
||||
|
||||
**Step 4: Remove ApiTabs from main.js**
|
||||
|
||||
Remove the import line:
|
||||
|
||||
```javascript
|
||||
import ApiTabs from './components/api-tabs.ts';
|
||||
```
|
||||
|
||||
Remove the registry entry:
|
||||
|
||||
```javascript
|
||||
'api-tabs': ApiTabs,
|
||||
```
|
||||
|
||||
**Step 5: Verify deletions**
|
||||
|
||||
Run: `ls assets/js/components/api-tabs.ts layouts/partials/api/tabs.html layouts/partials/api/tab-panels.html 2>&1`
|
||||
Expected: "No such file or directory" for all
|
||||
|
||||
Run: `grep -c "ApiTabs\|api-tabs" assets/js/main.js`
|
||||
Expected: `0`
|
||||
|
||||
**Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "refactor(api): Remove deprecated api-tabs component
|
||||
|
||||
Remove unused tabs component and partials:
|
||||
- Delete assets/js/components/api-tabs.ts
|
||||
- Delete layouts/partials/api/tabs.html
|
||||
- Delete layouts/partials/api/tab-panels.html
|
||||
- Remove ApiTabs from main.js component registry
|
||||
|
||||
The new architecture renders content directly without tabs."
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 6: Update Cypress Tests
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `cypress/e2e/content/api-reference.cy.js`
|
||||
|
||||
**Step 1: Remove tab-related tests**
|
||||
|
||||
Remove the tests that reference tabs, tab-panels, and the 3-column layout tests that expect tabs. The tests for the basic API reference pages and RapiDoc Mini should remain.
|
||||
|
||||
Specifically, remove:
|
||||
|
||||
1. The `describe('API reference 3-column layout', ...)` block that tests tabs (lines 134-275)
|
||||
2. Keep the basic API reference tests and RapiDoc Mini tests
|
||||
|
||||
**Step 2: Verify tests still work**
|
||||
|
||||
Run: `node cypress/support/run-e2e-specs.js --spec "cypress/e2e/content/api-reference.cy.js" content/influxdb3/core/api/_index.md`
|
||||
Expected: Tests pass
|
||||
|
||||
**Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add cypress/e2e/content/api-reference.cy.js
|
||||
git commit -m "test(api): Remove deprecated tab-related tests
|
||||
|
||||
Remove tests for tabs and 3-column layout that no longer exist.
|
||||
Keep basic API reference tests and RapiDoc Mini component tests."
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Task 7: Run Full Test Suite and Verify
|
||||
|
||||
**Files:**
|
||||
|
||||
- None (verification only)
|
||||
|
||||
**Step 1: Build Hugo site**
|
||||
|
||||
Run: `npx hugo --quiet`
|
||||
Expected: Build succeeds without errors
|
||||
|
||||
**Step 2: Start Hugo server**
|
||||
|
||||
Run: `npx hugo server &`
|
||||
Expected: Server starts on port 1313
|
||||
|
||||
**Step 3: Test API pages load correctly**
|
||||
|
||||
Run: `curl -s -o /dev/null -w "%{http_code}" http://localhost:1313/influxdb3/core/api/`
|
||||
Expected: `200`
|
||||
|
||||
Run: `curl -s -o /dev/null -w "%{http_code}" http://localhost:1313/influxdb3/core/api/write/post/`
|
||||
Expected: `200`
|
||||
|
||||
**Step 4: Run Cypress API tests**
|
||||
|
||||
Run: `node cypress/support/run-e2e-specs.js --spec "cypress/e2e/content/api-reference.cy.js" content/influxdb3/core/api/_index.md`
|
||||
Expected: All tests pass
|
||||
|
||||
**Step 5: Stop Hugo server**
|
||||
|
||||
Run: `pkill -f "hugo server"`
|
||||
|
||||
**Step 6: Final commit if any fixes needed**
|
||||
|
||||
```bash
|
||||
git status
|
||||
# If any files need fixing, make changes and commit
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Summary
|
||||
|
||||
This plan:
|
||||
|
||||
1. Creates `api-rapidoc.ts` - a TypeScript component extracting \~230 lines of inline JS from rapidoc.html
|
||||
2. Registers the new component in main.js
|
||||
3. Updates rapidoc.html to use `data-component` pattern instead of inline scripts
|
||||
4. Removes unused Scalar renderer code (scalar.html, api-scalar.ts, config option)
|
||||
5. Removes deprecated tabs components (api-tabs.ts, tabs.html, tab-panels.html)
|
||||
6. Updates Cypress tests to remove tab-related tests
|
||||
7. Verifies everything works with Hugo build and test suite
|
||||
|
||||
Total files changed:
|
||||
|
||||
- 1 file created: `assets/js/components/api-rapidoc.ts`
|
||||
- 5 files deleted: scalar.html, api-scalar.ts, api-tabs.ts, tabs.html, tab-panels.html
|
||||
- 4 files modified: rapidoc.html, renderer.html, main.js, hugo.yml, api-reference.cy.js
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
# docs-cli-workflow Skill Design
|
||||
|
||||
## Overview
|
||||
|
||||
A Claude Code skill that guides when to use `docs create` and `docs edit` CLI tools versus direct file editing for InfluxData documentation.
|
||||
|
||||
## Problem
|
||||
|
||||
Claude under-utilizes the `docs create` and `docs edit` CLI tools even when they would provide significant value:
|
||||
|
||||
- Better scaffolding for multi-product content
|
||||
- Context gathering (link extraction, structure analysis)
|
||||
- Education about style guidelines and shortcodes
|
||||
- Automatic file location from URLs
|
||||
|
||||
## Skill Identity
|
||||
|
||||
- **Name**: `docs-cli-workflow`
|
||||
- **Location**: `.claude/skills/docs-cli-workflow/SKILL.md`
|
||||
- **Scope**: Decision guidance only (not full workflow management)
|
||||
- **Behavior**: Suggest and wait for user confirmation
|
||||
|
||||
## Activation
|
||||
|
||||
### Trigger Keywords
|
||||
|
||||
The skill activates when user messages contain:
|
||||
|
||||
- "new page", "new doc", "create documentation", "add a page"
|
||||
- "edit this URL", "edit <https://docs>", "update this page" (with URL)
|
||||
- "document this feature", "write docs for"
|
||||
- "I have a draft", "from this draft"
|
||||
- References to docs.influxdata.com URLs
|
||||
|
||||
### Non-Triggers (Direct Editing is Fine)
|
||||
|
||||
- "fix this typo in content/..."
|
||||
- "update the frontmatter in..."
|
||||
- Explicit file paths the user already knows
|
||||
- Small edits to existing files user has open
|
||||
|
||||
## Decision Logic
|
||||
|
||||
### When to Suggest `docs create`
|
||||
|
||||
| Trigger | Why CLI is Better |
|
||||
| ---------------------------------- | --------------------------------------------------------- |
|
||||
| Content targets multiple products | CLI scaffolds shared content pattern automatically |
|
||||
| User unsure where page should live | CLI analyzes structure, suggests location |
|
||||
| Draft references existing docs | CLI extracts links, provides context to avoid duplication |
|
||||
| User unfamiliar with conventions | CLI prompt includes style guide, shortcode examples |
|
||||
| Complex new feature documentation | CLI gathers product metadata, version info |
|
||||
|
||||
### When to Suggest `docs edit`
|
||||
|
||||
| Trigger | Why CLI is Better |
|
||||
| -------------------------------------- | ------------------------------------------------------ |
|
||||
| User provides docs.influxdata.com URL | CLI finds source file(s) including shared content |
|
||||
| User doesn't know source file location | CLI maps URL → file path(s) |
|
||||
| Page uses shared content | CLI identifies both frontmatter file AND shared source |
|
||||
|
||||
### When to Skip CLI (Edit Directly)
|
||||
|
||||
| Scenario | Why Direct is Fine |
|
||||
| -------------------------------- | ------------------------------- |
|
||||
| User provides explicit file path | They already know where to edit |
|
||||
| Small typo/link fixes | Overhead not worth it |
|
||||
| User says "just edit it" | Explicit preference |
|
||||
| Frontmatter-only changes | No content generation needed |
|
||||
|
||||
## Suggestion Format
|
||||
|
||||
### For `docs create`
|
||||
|
||||
```
|
||||
I'd recommend using the docs CLI for this:
|
||||
|
||||
npx docs create <draft-path> --products <product>
|
||||
|
||||
**Why**: [1-2 sentences explaining the specific benefit for this request]
|
||||
|
||||
Options:
|
||||
1. **Use CLI** - I'll run the command and guide you through product selection
|
||||
2. **Edit directly** - Skip the CLI, I'll create/edit files manually
|
||||
|
||||
Which do you prefer?
|
||||
```
|
||||
|
||||
### For `docs edit`
|
||||
|
||||
```
|
||||
I can use the docs CLI to find the source files for this page:
|
||||
|
||||
npx docs edit <url>
|
||||
|
||||
**Why**: [1-2 sentences - e.g., "This will locate the source file and any shared content it uses"]
|
||||
|
||||
Options:
|
||||
1. **Use CLI** - I'll find and open the relevant files
|
||||
2. **I know the file** - Tell me the path and I'll edit directly
|
||||
|
||||
Which do you prefer?
|
||||
```
|
||||
|
||||
### Principles
|
||||
|
||||
- Show the actual command (educational)
|
||||
- Explain *why* for this specific case
|
||||
- Always offer the direct alternative
|
||||
- Keep it brief - 4-6 lines max
|
||||
|
||||
## Edge Cases
|
||||
|
||||
| Edge Case | Behavior |
|
||||
| ---------------------------------------- | ------------------------------------------------------ |
|
||||
| User already in a `docs create` workflow | Don't re-suggest |
|
||||
| URL points to non-existent page | Suggest `docs create --url` instead of `docs edit` |
|
||||
| User provides both URL and draft | Suggest `docs create --url <url> --from-draft <draft>` |
|
||||
| User declines CLI twice in session | Stop suggesting, note preference |
|
||||
|
||||
## Post-Confirmation Behavior
|
||||
|
||||
After user confirms they want to use the CLI:
|
||||
|
||||
1. Run the appropriate command
|
||||
2. Let the CLI handle the rest (product selection, file generation, etc.)
|
||||
3. No additional skill guidance needed
|
||||
|
||||
## Related Files
|
||||
|
||||
- `scripts/docs-cli.js` - Main CLI entry point
|
||||
- `scripts/docs-create.js` - Content scaffolding implementation
|
||||
- `scripts/docs-edit.js` - File finder implementation
|
||||
- `scripts/lib/content-scaffolding.js` - Context preparation logic
|
||||
Loading…
Reference in New Issue