This commit is contained in:
dingfeng.wong
2025-07-10 00:30:52 +08:00
parent 6461b7e906
commit ff17f90098
+160 -22
View File
@@ -2,8 +2,9 @@ import typer
from rich.console import Console
import json
import pyperclip
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Callable
from pathlib import Path
import re
console = Console()
@@ -14,6 +15,32 @@ def safe_get(data: Dict[str, Any], key: str, default: Any = None) -> Any:
"""Safely get a value from a dictionary."""
return data.get(key, default)
def contains_chinese(text: str) -> bool:
"""Check if text contains Chinese characters."""
if not isinstance(text, str):
return False
# Unicode ranges for Chinese characters
chinese_pattern = re.compile(r'[\u4e00-\u9fff\u3400-\u4dbf\u20000-\u2a6df\u2a700-\u2b73f\u2b740-\u2b81f\u2b820-\u2ceaf\uf900-\ufaff\u3300-\u33ff\ufe30-\ufe4f\uf900-\ufaff\u2f800-\u2fa1f]')
return bool(chinese_pattern.search(text))
def mutate_chinese_titles(data: Dict[str, Any]) -> None:
"""Recursively mutate titles containing Chinese characters."""
if not isinstance(data, dict):
return
# List of keys that might contain title text
title_keys = ['title', 'name', 'description', 'tooltip', 'legendFormat', 'text']
for key, value in data.items():
if key in title_keys and isinstance(value, str) and contains_chinese(value):
data[key] = "please_translate_me"
elif isinstance(value, dict):
mutate_chinese_titles(value)
elif isinstance(value, list):
for item in value:
if isinstance(item, dict):
mutate_chinese_titles(item)
def mutate_panel(panel: Dict[str, Any]) -> None:
"""Mutate a single panel by setting repeat and repeatDirection fields."""
# Check if type is "row" and remove repeat key if it exists
@@ -40,7 +67,7 @@ def mutate_panels_recursive(panels: List[Dict[str, Any]]) -> None:
if nested_panels and isinstance(nested_panels, list):
mutate_panels_recursive(nested_panels)
def mutate_grafana_json(data: Dict[str, Any]) -> Dict[str, Any]:
def mutate_grafana_json_repeat(data: Dict[str, Any]) -> Dict[str, Any]:
"""
Mutate Grafana JSON by setting repeat and repeatDirection fields.
@@ -61,25 +88,62 @@ def mutate_grafana_json(data: Dict[str, Any]) -> Dict[str, Any]:
return mutated_data
@grafana_app.command("mutate", short_help="Mutate Grafana JSON to set repeat fields.")
def mutate_dashboard(
input_file: Optional[Path] = typer.Option(
None, "--input-file", "-i", help="Input JSON file path. If not provided, reads from clipboard."
),
output_file: Optional[Path] = typer.Option(
None, "--output-file", "-o", help="Output JSON file path. If not provided, outputs to clipboard."
)
):
def mutate_grafana_json_chinese(data: Dict[str, Any]) -> Dict[str, Any]:
"""
Mutate Grafana JSON by setting repeat="instance" and repeatDirection="h".
Mutate Grafana JSON by replacing Chinese text in titles with 'please_translate_me'.
This command processes Grafana dashboard JSON and modifies panels to:
- Set repeat field to "instance"
- Set repeatDirection field to "h"
- Set maxPerRow to 12
- Remove repeat field from row-type panels
Args:
data: The Grafana dashboard JSON data
Returns:
The mutated JSON data
"""
console.print("[blue]Processing Grafana dashboard JSON...[/blue]")
# Make a copy to avoid mutating the original
mutated_data = json.loads(json.dumps(data))
# Apply Chinese title mutation recursively
mutate_chinese_titles(mutated_data)
return mutated_data
def mutate_grafana_json_all(data: Dict[str, Any]) -> Dict[str, Any]:
"""
Apply both mutations: repeat fields and Chinese title translation.
Args:
data: The Grafana dashboard JSON data
Returns:
The mutated JSON data
"""
# First apply repeat field mutation
mutated_data = mutate_grafana_json_repeat(data)
console.print("[green]✓ Applied repeat field mutation[/green]")
# Then apply Chinese title translation
mutated_data = mutate_grafana_json_chinese(mutated_data)
console.print("[green]✓ Applied Chinese title translation[/green]")
return mutated_data
def process_grafana_json(
mutation_func: Callable[[Dict[str, Any]], Dict[str, Any]],
input_file: Optional[Path],
output_file: Optional[Path],
process_message: str,
success_message: str
) -> None:
"""
Common function to process Grafana JSON with input/output handling.
Args:
mutation_func: Function to apply mutations to the JSON data
input_file: Optional input file path
output_file: Optional output file path
process_message: Message to display when starting processing
success_message: Message to display when mutation succeeds
"""
console.print(f"[blue]{process_message}[/blue]")
# Read input
try:
@@ -107,10 +171,10 @@ def mutate_dashboard(
console.print(f"[red]Error parsing JSON: {e}[/red]")
raise typer.Exit(code=1)
# Mutate the data
# Apply mutation
try:
mutated_data = mutate_grafana_json(data)
console.print("[green]Successfully mutated Grafana JSON![/green]")
mutated_data = mutation_func(data)
console.print(f"[green]{success_message}[/green]")
except Exception as e:
console.print(f"[red]Error mutating JSON: {e}[/red]")
raise typer.Exit(code=1)
@@ -129,4 +193,78 @@ def mutate_dashboard(
console.print("[green]Output copied to clipboard![/green]")
except Exception as e:
console.print(f"[red]Error writing output: {e}[/red]")
raise typer.Exit(code=1)
raise typer.Exit(code=1)
@grafana_app.command("mutate", short_help="Mutate Grafana JSON to set repeat fields.")
def mutate_dashboard(
input_file: Optional[Path] = typer.Option(
None, "--input-file", "-i", help="Input JSON file path. If not provided, reads from clipboard."
),
output_file: Optional[Path] = typer.Option(
None, "--output-file", "-o", help="Output JSON file path. If not provided, outputs to clipboard."
)
):
"""
Mutate Grafana JSON by setting repeat="instance" and repeatDirection="h".
This command processes Grafana dashboard JSON and modifies panels to:
- Set repeat field to "instance"
- Set repeatDirection field to "h"
- Set maxPerRow to 12
- Remove repeat field from row-type panels
"""
process_grafana_json(
mutation_func=mutate_grafana_json_repeat,
input_file=input_file,
output_file=output_file,
process_message="Processing Grafana dashboard JSON...",
success_message="Successfully mutated Grafana JSON!"
)
@grafana_app.command("translate", short_help="Replace Chinese text in titles with 'please_translate_me'.")
def translate_dashboard(
input_file: Optional[Path] = typer.Option(
None, "--input-file", "-i", help="Input JSON file path. If not provided, reads from clipboard."
),
output_file: Optional[Path] = typer.Option(
None, "--output-file", "-o", help="Output JSON file path. If not provided, outputs to clipboard."
)
):
"""
Replace Chinese text in titles with 'please_translate_me'.
This command processes Grafana dashboard JSON and replaces any Chinese characters
in title-related fields (title, name, description, tooltip, legendFormat, text)
with the placeholder text 'please_translate_me'.
"""
process_grafana_json(
mutation_func=mutate_grafana_json_chinese,
input_file=input_file,
output_file=output_file,
process_message="Processing Grafana dashboard JSON for Chinese title translation...",
success_message="Successfully replaced Chinese text in titles!"
)
@grafana_app.command("mutate-all", short_help="Apply both repeat field mutation and Chinese title translation.")
def mutate_all_dashboard(
input_file: Optional[Path] = typer.Option(
None, "--input-file", "-i", help="Input JSON file path. If not provided, reads from clipboard."
),
output_file: Optional[Path] = typer.Option(
None, "--output-file", "-o", help="Output JSON file path. If not provided, outputs to clipboard."
)
):
"""
Apply both mutations: set repeat fields and replace Chinese text in titles.
This command processes Grafana dashboard JSON and applies both:
1. Repeat field mutation (repeat="instance", repeatDirection="h", maxPerRow=12)
2. Chinese title translation (replaces Chinese characters with 'please_translate_me')
"""
process_grafana_json(
mutation_func=mutate_grafana_json_all,
input_file=input_file,
output_file=output_file,
process_message="Processing Grafana dashboard JSON with all mutations...",
success_message="Successfully applied all mutations!"
)