This commit is contained in:
Maxime Beauchemin
2025-07-17 13:43:38 -07:00
parent 29b4c480f3
commit 92bf3b9d4e
11 changed files with 1452 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""
Export configuration metadata to JSON for documentation generation.
This script extracts configuration metadata from SupersetConfig and generates
JSON files that can be imported into the documentation site.
"""
import sys
from pathlib import Path
from typing import Any, Dict, List
# Add the superset directory to Python path
superset_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(superset_root))
from superset.config_extensions import SupersetConfig # noqa: E402
from superset.utils import json # noqa: E402
def export_config_metadata() -> List[Dict[str, Any]]:
"""Export configuration metadata as JSON."""
config = SupersetConfig()
# Get all settings metadata
settings_metadata = config.DATABASE_SETTINGS_SCHEMA
# Transform metadata for documentation
docs_metadata = []
for key, schema in settings_metadata.items():
# Skip readonly settings for user documentation
if schema.get("readonly", False):
continue
# Build environment variable name
env_var = f"SUPERSET__{key}"
# Extract nested example if available
nested_example = None
if schema.get("type") == "object" and "example" in schema:
nested_example = f"SUPERSET__{key}__example__nested_key=value"
# Format type information
type_info = str(schema.get("type", "unknown"))
if type_info == "integer":
min_val = schema.get("minimum")
max_val = schema.get("maximum")
if min_val is not None or max_val is not None:
min_str = str(min_val) if min_val is not None else "N/A"
max_str = str(max_val) if max_val is not None else "N/A"
type_info += f" ({min_str} - {max_str})"
doc_entry = {
"key": key,
"title": schema.get("title", key),
"description": schema.get("description", ""),
"type": type_info,
"category": schema.get("category", "general"),
"impact": schema.get("impact", "medium"),
"requires_restart": schema.get("requires_restart", True),
"default": schema.get("default"),
"env_var": env_var,
"nested_example": nested_example,
"documentation_url": schema.get("documentation_url"),
}
docs_metadata.append(doc_entry)
# Group by category
categories: Dict[str, List[Dict[str, Any]]] = {}
for entry in docs_metadata:
category = str(entry["category"])
if category not in categories:
categories[category] = []
categories[category].append(entry)
# Sort entries within each category
for category in categories:
categories[category].sort(key=lambda x: x["key"])
# Export as JSON
output_dir = Path(__file__).parent.parent / "src" / "resources"
output_dir.mkdir(exist_ok=True)
# Export all settings
with open(output_dir / "config_metadata.json", "w") as f:
f.write(
json.dumps(
{
"all_settings": docs_metadata,
"by_category": categories,
"categories": list(categories.keys()),
},
indent=2,
)
)
output_file = output_dir / "config_metadata.json"
print(f"Exported {len(docs_metadata)} configuration settings to {output_file}")
return docs_metadata
if __name__ == "__main__":
export_config_metadata()

40
docs/scripts/update_docs.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
# 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.
# Update documentation with latest configuration metadata
# This script should be run before building the documentation
set -e
echo "Updating configuration metadata for documentation..."
# Navigate to the docs directory
cd "$(dirname "$0")/.."
# Export configuration metadata
echo "Exporting configuration metadata..."
python scripts/export_config_metadata.py
echo "Configuration metadata updated successfully!"
echo "The following files were updated:"
echo "- src/resources/config_metadata.json"
echo ""
echo "To build the documentation with the latest metadata:"
echo " npm install"
echo " npm run build"

View File

@@ -0,0 +1,331 @@
/**
* 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.
*/
import React, { useState } from 'react';
import configMetadata from '../resources/config_metadata.json';
interface ConfigSetting {
key: string;
title: string;
description: string;
type: string;
category: string;
impact: string;
requires_restart: boolean;
default: any;
env_var: string;
nested_example: string | null;
documentation_url: string | null;
}
interface ConfigurationTableProps {
category?: string;
showEnvironmentVariables?: boolean;
}
const ImpactBadge: React.FC<{ impact: string }> = ({ impact }) => {
const colors = {
low: '#52c41a',
medium: '#faad14',
high: '#ff4d4f',
};
return (
<span
style={{
backgroundColor: colors[impact] || '#d9d9d9',
color: 'white',
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px',
fontWeight: 'bold',
}}
>
{impact.toUpperCase()}
</span>
);
};
const RestartBadge: React.FC<{ requiresRestart: boolean }> = ({
requiresRestart,
}) => {
if (!requiresRestart) return null;
return (
<span
style={{
backgroundColor: '#ff7875',
color: 'white',
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px',
fontWeight: 'bold',
marginLeft: '8px',
}}
>
RESTART
</span>
);
};
const ConfigurationTable: React.FC<ConfigurationTableProps> = ({
category,
showEnvironmentVariables = false,
}) => {
const [selectedCategory, setSelectedCategory] = useState<string>(
category || 'all',
);
// Get settings based on selected category
const getSettings = (): ConfigSetting[] => {
if (selectedCategory === 'all') {
return configMetadata.all_settings;
}
return configMetadata.by_category[selectedCategory] || [];
};
const settings = getSettings();
const formatDefault = (value: any): string => {
if (value === null || value === undefined) return 'None';
if (typeof value === 'object') {
return JSON.stringify(value, null, 2);
}
return String(value);
};
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
};
return (
<div style={{ margin: '20px 0' }}>
{/* Category selector */}
{!category && (
<div style={{ marginBottom: '20px' }}>
<label style={{ marginRight: '10px', fontWeight: 'bold' }}>
Category:
</label>
<select
value={selectedCategory}
onChange={e => setSelectedCategory(e.target.value)}
style={{ padding: '5px', marginRight: '10px' }}
>
<option value="all">All Categories</option>
{configMetadata.categories.map(cat => (
<option key={cat} value={cat}>
{cat.charAt(0).toUpperCase() + cat.slice(1)}
</option>
))}
</select>
<span style={{ fontSize: '14px', color: '#666' }}>
Showing {settings.length} configuration settings
</span>
</div>
)}
{/* Table */}
<div style={{ overflowX: 'auto' }}>
<table
style={{
width: '100%',
borderCollapse: 'collapse',
border: '1px solid #ddd',
}}
>
<thead>
<tr style={{ backgroundColor: '#f5f5f5' }}>
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Setting
</th>
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Description
</th>
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Type
</th>
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Default
</th>
{showEnvironmentVariables && (
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Environment Variable
</th>
)}
<th
style={{
padding: '12px',
border: '1px solid #ddd',
textAlign: 'left',
}}
>
Impact
</th>
</tr>
</thead>
<tbody>
{settings.map((setting: ConfigSetting) => (
<tr key={setting.key}>
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
<div>
<strong>{setting.title}</strong>
<br />
<code style={{ fontSize: '12px', color: '#666' }}>
{setting.key}
</code>
{setting.documentation_url && (
<div style={{ marginTop: '4px' }}>
<a
href={setting.documentation_url}
target="_blank"
rel="noopener noreferrer"
style={{ fontSize: '12px' }}
>
📖 Docs
</a>
</div>
)}
</div>
</td>
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
{setting.description}
</td>
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
<code>{setting.type}</code>
</td>
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
<code style={{ fontSize: '12px' }}>
{formatDefault(setting.default)}
</code>
</td>
{showEnvironmentVariables && (
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<code style={{ fontSize: '12px', marginRight: '8px' }}>
{setting.env_var}
</code>
<button
onClick={() => copyToClipboard(setting.env_var)}
style={{
background: 'none',
border: 'none',
cursor: 'pointer',
fontSize: '12px',
color: '#1890ff',
}}
title="Copy to clipboard"
>
📋
</button>
</div>
{setting.nested_example && (
<div style={{ marginTop: '4px' }}>
<code style={{ fontSize: '10px', color: '#666' }}>
{setting.nested_example}
</code>
</div>
)}
</td>
)}
<td
style={{
padding: '12px',
border: '1px solid #ddd',
verticalAlign: 'top',
}}
>
<ImpactBadge impact={setting.impact} />
<RestartBadge requiresRestart={setting.requires_restart} />
</td>
</tr>
))}
</tbody>
</table>
</div>
{settings.length === 0 && (
<div style={{ textAlign: 'center', padding: '20px', color: '#666' }}>
No configuration settings found for the selected category.
</div>
)}
</div>
);
};
export default ConfigurationTable;

View File

@@ -0,0 +1,181 @@
/**
* 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.
*/
import React, { useState } from 'react';
import configMetadata from '../resources/config_metadata.json';
interface EnvironmentVariablesExampleProps {
category?: string;
}
const EnvironmentVariablesExample: React.FC<
EnvironmentVariablesExampleProps
> = ({ category }) => {
const [showAll, setShowAll] = useState(false);
// Get settings based on category
const getSettings = () => {
if (category && configMetadata.by_category[category]) {
return configMetadata.by_category[category];
}
return configMetadata.all_settings;
};
const settings = getSettings();
const displaySettings = showAll ? settings : settings.slice(0, 5);
const formatDefaultForEnv = (value: any): string => {
if (value === null || value === undefined) return '""';
if (typeof value === 'object') {
return `'${JSON.stringify(value)}'`;
}
if (typeof value === 'string') {
return `"${value}"`;
}
return String(value);
};
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
};
const generateEnvExample = (setting: any): string => {
const example = formatDefaultForEnv(setting.default);
return `export ${setting.env_var}=${example}`;
};
const generateAllEnvVars = (): string => {
return [
'# Superset Configuration Environment Variables',
'# Generated from configuration metadata',
'',
...displaySettings.map(setting =>
[
`# ${setting.title}`,
`# ${setting.description}`,
`# Type: ${setting.type}`,
`# Impact: ${setting.impact}${
setting.requires_restart ? ' (requires restart)' : ''
}`,
generateEnvExample(setting),
'',
].join('\n'),
),
].join('\n');
};
return (
<div style={{ margin: '20px 0' }}>
<div
style={{
backgroundColor: '#f6f8fa',
border: '1px solid #e1e4e8',
borderRadius: '6px',
padding: '16px',
position: 'relative',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: '10px',
}}
>
<h4 style={{ margin: 0, color: '#24292e' }}>
Environment Variables {category && `(${category})`}
</h4>
<button
onClick={() => copyToClipboard(generateAllEnvVars())}
style={{
backgroundColor: '#0366d6',
color: 'white',
border: 'none',
padding: '6px 12px',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px',
}}
title="Copy all environment variables"
>
📋 Copy All
</button>
</div>
<pre
style={{
backgroundColor: '#f6f8fa',
border: 'none',
padding: '0',
margin: '0',
fontFamily:
'SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace',
fontSize: '12px',
lineHeight: '1.45',
overflow: 'auto',
maxHeight: '400px',
}}
>
<code>{generateAllEnvVars()}</code>
</pre>
{!showAll && settings.length > 5 && (
<div
style={{
textAlign: 'center',
marginTop: '10px',
borderTop: '1px solid #e1e4e8',
paddingTop: '10px',
}}
>
<button
onClick={() => setShowAll(true)}
style={{
backgroundColor: 'transparent',
border: '1px solid #0366d6',
color: '#0366d6',
padding: '6px 12px',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px',
}}
>
Show all {settings.length} settings
</button>
</div>
)}
</div>
<div
style={{
marginTop: '10px',
fontSize: '14px',
color: '#586069',
}}
>
<strong>Usage:</strong> Save to a <code>.env</code> file or export
directly in your shell.
{category && ` Showing ${settings.length} ${category} settings.`}
</div>
</div>
);
};
export default EnvironmentVariablesExample;

View File

@@ -0,0 +1,225 @@
{
"all_settings": [
{
"key": "ROW_LIMIT",
"title": "Row Limit",
"description": "Maximum number of rows returned from queries",
"type": "integer (1 - 1000000)",
"category": "performance",
"impact": "medium",
"requires_restart": false,
"default": 50000,
"env_var": "SUPERSET__ROW_LIMIT",
"nested_example": null,
"documentation_url": "https://superset.apache.org/docs/configuration/databases"
},
{
"key": "SAMPLES_ROW_LIMIT",
"title": "Samples Row Limit",
"description": "Default row limit when requesting samples from datasource",
"type": "integer (1 - 10000)",
"category": "performance",
"impact": "low",
"requires_restart": false,
"default": 1000,
"env_var": "SUPERSET__SAMPLES_ROW_LIMIT",
"nested_example": null,
"documentation_url": null
},
{
"key": "NATIVE_FILTER_DEFAULT_ROW_LIMIT",
"title": "Native Filter Default Row Limit",
"description": "Default row limit for native filters",
"type": "integer (1 - 10000)",
"category": "performance",
"impact": "low",
"requires_restart": false,
"default": 1000,
"env_var": "SUPERSET__NATIVE_FILTER_DEFAULT_ROW_LIMIT",
"nested_example": null,
"documentation_url": null
},
{
"key": "SQLLAB_TIMEOUT",
"title": "SQL Lab Timeout",
"description": "Timeout duration for SQL Lab synchronous queries (seconds)",
"type": "integer (1 - 3600)",
"category": "performance",
"impact": "high",
"requires_restart": false,
"default": 30,
"env_var": "SUPERSET__SQLLAB_TIMEOUT",
"nested_example": null,
"documentation_url": null
},
{
"key": "FEATURE_FLAGS",
"title": "Feature Flags",
"description": "Feature flags to enable/disable functionality",
"type": "object",
"category": "features",
"impact": "high",
"requires_restart": true,
"default": {},
"env_var": "SUPERSET__FEATURE_FLAGS",
"nested_example": null,
"documentation_url": null
},
{
"key": "THEME_DEFAULT",
"title": "Default Theme",
"description": "Default theme configuration (Ant Design format)",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_DEFAULT",
"nested_example": null,
"documentation_url": null
},
{
"key": "THEME_DARK",
"title": "Dark Theme",
"description": "Dark theme configuration (Ant Design format)",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_DARK",
"nested_example": null,
"documentation_url": null
},
{
"key": "THEME_SETTINGS",
"title": "Theme Settings",
"description": "Theme behavior and user preference settings",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_SETTINGS",
"nested_example": null,
"documentation_url": null
}
],
"by_category": {
"performance": [
{
"key": "NATIVE_FILTER_DEFAULT_ROW_LIMIT",
"title": "Native Filter Default Row Limit",
"description": "Default row limit for native filters",
"type": "integer (1 - 10000)",
"category": "performance",
"impact": "low",
"requires_restart": false,
"default": 1000,
"env_var": "SUPERSET__NATIVE_FILTER_DEFAULT_ROW_LIMIT",
"nested_example": null,
"documentation_url": null
},
{
"key": "ROW_LIMIT",
"title": "Row Limit",
"description": "Maximum number of rows returned from queries",
"type": "integer (1 - 1000000)",
"category": "performance",
"impact": "medium",
"requires_restart": false,
"default": 50000,
"env_var": "SUPERSET__ROW_LIMIT",
"nested_example": null,
"documentation_url": "https://superset.apache.org/docs/configuration/databases"
},
{
"key": "SAMPLES_ROW_LIMIT",
"title": "Samples Row Limit",
"description": "Default row limit when requesting samples from datasource",
"type": "integer (1 - 10000)",
"category": "performance",
"impact": "low",
"requires_restart": false,
"default": 1000,
"env_var": "SUPERSET__SAMPLES_ROW_LIMIT",
"nested_example": null,
"documentation_url": null
},
{
"key": "SQLLAB_TIMEOUT",
"title": "SQL Lab Timeout",
"description": "Timeout duration for SQL Lab synchronous queries (seconds)",
"type": "integer (1 - 3600)",
"category": "performance",
"impact": "high",
"requires_restart": false,
"default": 30,
"env_var": "SUPERSET__SQLLAB_TIMEOUT",
"nested_example": null,
"documentation_url": null
}
],
"features": [
{
"key": "FEATURE_FLAGS",
"title": "Feature Flags",
"description": "Feature flags to enable/disable functionality",
"type": "object",
"category": "features",
"impact": "high",
"requires_restart": true,
"default": {},
"env_var": "SUPERSET__FEATURE_FLAGS",
"nested_example": null,
"documentation_url": null
}
],
"ui": [
{
"key": "THEME_DARK",
"title": "Dark Theme",
"description": "Dark theme configuration (Ant Design format)",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_DARK",
"nested_example": null,
"documentation_url": null
},
{
"key": "THEME_DEFAULT",
"title": "Default Theme",
"description": "Default theme configuration (Ant Design format)",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_DEFAULT",
"nested_example": null,
"documentation_url": null
},
{
"key": "THEME_SETTINGS",
"title": "Theme Settings",
"description": "Theme behavior and user preference settings",
"type": "object",
"category": "ui",
"impact": "medium",
"requires_restart": false,
"default": {},
"env_var": "SUPERSET__THEME_SETTINGS",
"nested_example": null,
"documentation_url": null
}
]
},
"categories": [
"performance",
"features",
"ui"
]
}