diff --git a/.github/workflows/publish-nightly.yml b/.github/workflows/publish-nightly.yml new file mode 100644 index 0000000..acb09ba --- /dev/null +++ b/.github/workflows/publish-nightly.yml @@ -0,0 +1,87 @@ +name: Publish Nightly Extension + +permissions: + contents: read + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: publish-nightly + cancel-in-progress: true + +jobs: + publish-nightly: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run vscode:prepublish + + - name: Compute nightly version + id: nightly_version + run: | + NIGHTLY_VERSION=$(node -e "const [maj,min] = require('./package.json').version.split('.').map(Number); const nightlyMinor = min % 2 === 0 ? min + 1 : min; process.stdout.write(`${maj}.${nightlyMinor}.${process.env.GITHUB_RUN_NUMBER}`)") + echo "VERSION=$NIGHTLY_VERSION" >> $GITHUB_OUTPUT + echo "Using nightly version: $NIGHTLY_VERSION" + + - name: Prepare nightly manifests + env: + NIGHTLY_VERSION: ${{ steps.nightly_version.outputs.VERSION }} + OPENVSX_NIGHTLY_NAME: postgres-explorer-nightly + run: node ./scripts/prepare-nightly-manifests.js + + - name: Package VS Code Marketplace nightly + id: package_marketplace + run: | + cp package.json package.json.bak + cp .nightly/package.marketplace.json package.json + VSIX_FILE=$(node -e "const pkg=require('./package.json'); process.stdout.write(`${pkg.name}-${pkg.version}.vsix`)") + npx @vscode/vsce package --pre-release + mv package.json.bak package.json + echo "VSIX_FILE=$VSIX_FILE" >> $GITHUB_OUTPUT + + - name: Publish VS Code Marketplace nightly (pre-release) + run: | + npx @vscode/vsce publish \ + --pre-release \ + --packagePath ${{ steps.package_marketplace.outputs.VSIX_FILE }} \ + -p ${{ secrets.VSCE_PAT }} + + - name: Package Open VSX nightly companion + id: package_openvsx + run: | + cp package.json package.json.bak + cp .nightly/package.openvsx.json package.json + VSIX_FILE=$(node -e "const pkg=require('./package.json'); process.stdout.write(`${pkg.name}-${pkg.version}.vsix`)") + npx @vscode/vsce package + mv package.json.bak package.json + echo "VSIX_FILE=$VSIX_FILE" >> $GITHUB_OUTPUT + + - name: Publish Open VSX nightly companion + run: | + npx ovsx publish \ + ${{ steps.package_openvsx.outputs.VSIX_FILE }} \ + -p ${{ secrets.OVSX_PAT }} + + - name: Upload nightly artifacts + uses: actions/upload-artifact@v4 + with: + name: nightly-vsix + path: "*.vsix" + retention-days: 30 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 31087f3..0bdfb0d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -36,7 +36,8 @@ jobs: echo "Package.json version: $PKG_VERSION" if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then - echo "::warning::Tag version ($TAG_VERSION) doesn't match package.json version ($PKG_VERSION)" + echo "::error::Tag version ($TAG_VERSION) doesn't match package.json version ($PKG_VERSION)" + exit 1 fi # Set VSIX filename diff --git a/.gitignore b/.gitignore index 7883255..d65f5b7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ test_* mock_ai_server.js *.pgpass src/test/unit/PgPassSupport.test.ts +.kiro/ +.nightly/ +CLAUDE.md +.claude/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f21347d..e20677c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,64 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [0.9.5] - 2026-04-09 + +### Added +- **Image support in SQL Assistant**: Paste images directly from clipboard or upload via the new image button (🖼) in the chat input. Images render as fixed 56×56px thumbnails in a dedicated preview strip above the textarea. +- **Image lightbox**: Click any image thumbnail (in the input strip or in message history) to open a full-size overlay preview. +- **Vision AI support**: Images are now properly sent to AI providers that support vision — OpenAI/custom as `image_url` parts, Anthropic as `base64` image blocks, Gemini as `inline_data` parts, and VS Code LM via `LanguageModelImagePart`. +- **File preview from chat**: Clicking an attached file chip (in the input area or in message history) opens the file as a preview tab in the VS Code editor. Works for files attached via the file picker, "Send to Chat", and "Analyze Data" buttons. +- **GitHub Models account sign-in**: Added first-class GitHub Models provider support using VS Code GitHub authentication sessions, including model listing and connection checks from AI Settings. + +### Changed +- **GitHub auth UX**: GitHub provider connection now uses the standard VS Code GitHub sign-in flow in AI Settings, with provider state reflected in the UI. +- **Nightly release channel**: Nightly builds are now available as pre-release updates, including a dedicated Open VSX nightly companion package for early access testing. + +### Fixed +- **Image CSP**: Added `img-src data: blob:` to the webview Content Security Policy so image thumbnails actually render (previously blocked by `default-src 'none'`). +- **File path missing on attach**: Files picked via the attachment button now include their filesystem path, enabling click-to-preview. +- **Open VSX GitHub auth fallback**: Removed invalid OAuth scope requests for GitHub session auth to prevent users from being redirected to PAT-only fallback prompts. + +--- + +## [0.9.2] - 2026-04-07 + +### Added +- **Local AI model support**: New **Ollama** and **LM Studio** providers connect to locally-running models at their default endpoints (`http://localhost:11434` and `http://localhost:1234`). No API key required. +- **Nightly build pipeline**: Automated GitHub Actions workflow publishes pre-release builds to VS Code Marketplace and Open VSX on every push to `main`. Nightly versions use odd minor numbers (e.g., `0.9.1.{run}`). +- **AI response timing**: Chat responses now display elapsed time alongside token usage for quick performance feedback. +- **Code snippet execution**: Suggestion bubbles in chat can now run code snippets directly via a new `runSnippet()` action. + +### Changed +- **Connection edit flow**: Editing a connection now opens `ConnectionFormPanel` directly instead of dispatching a command, making the flow more reliable. +- **Connection card styling**: Environment-specific accent colors (green for DEV, orange for STAGING, red for PROD) applied consistently across connection cards. +- **Chat input focus**: `sendSuggestion()` now properly focuses the input and positions the cursor after inserting a suggestion. +- **Publish workflow**: Version mismatch between the git tag and `package.json` now fails the build instead of emitting a warning. + +### Fixed +- **Inline code rendering**: Fixed markdown rendering of inline code in chat responses (resolves display issues with meta-notation like `(u, o)`). +- **SVG icon sizing**: Code block action buttons now have explicit `width`/`height` attributes, preventing layout inconsistencies across themes. + +### Removed +- **Tree filter commands**: `postgres-explorer.filterTree` and `postgres-explorer.clearFilter` removed from activation — these experimental commands were unused. + +--- + +## [0.9.0] - 2026-04-06 + +### Added +- **Anthropic model discovery**: AI Settings now lists Anthropic models from the official `/v1/models` API instead of a fixed local list. +- **Guided chat responses**: Assistant replies can now include numbered follow-up questions, optional next-step suggestion bubbles, and contextual quote-style factoids or jokes when they genuinely fit. + +### Changed +- **AI key lookup**: Direct AI provider keys now resolve from `SecretStorage` first, fixing false “API key required” errors when the key is already saved. +- **Chat identity and styling**: Assistant messages are labeled **PG Studio Bot**, with improved assistant bubble contrast and quote styling for richer responses. +- **Composer UX**: The chat input and suggestion bubbles were tightened for readability, capped to a compact height, and styled to avoid carrying stale next-step actions between chats. + +### Fixed +- **Follow-up selection**: Typing a number now resolves to the corresponding numbered follow-up question from the previous assistant message, instead of being treated as a fresh prompt. +- **Next-step carry-over**: Next-step bubbles are hidden when a new follow-up is sent or when switching chats, so actions remain specific to the active conversation. + ## [0.8.8] - 2026-03-21 ### Added diff --git a/LICENSE b/LICENSE index 20c1565..dd4a1c4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2025 Richie Varghese +Copyright (c) 2026 Richie Varghese Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MARKETPLACE.md b/MARKETPLACE.md index 33674b5..095f0bc 100644 --- a/MARKETPLACE.md +++ b/MARKETPLACE.md @@ -43,7 +43,7 @@ | 🔍 **EXPLAIN CodeLens** | One-click EXPLAIN/ANALYZE with results in notebooks | | 🛡️ **Auto-LIMIT** | Automatic query protection with configurable row limits (default 1000) | | 🌍 **Foreign Data Wrappers** | Manage foreign servers, user mappings, and tables | -| 🤖 **AI-Powered** | GitHub Copilot, OpenAI, Anthropic, and Google Gemini integration | +| 🤖 **AI-Powered** | GitHub Copilot, GitHub Models, OpenAI, Anthropic, and Google Gemini integration | | ⌨️ **Developer Tools** | IntelliSense, keyboard shortcuts, PSQL terminal access | | 📤 **Export Data** | Export query results to CSV, JSON, or Excel formats | @@ -160,6 +160,7 @@ PgStudio provides a **Safe Execution Model** for AI interactions. **Supported AI Providers:** - GitHub Copilot (VS Code LM) +- GitHub Models (GitHub account sign-in) - OpenAI - Anthropic Claude - Google Gemini @@ -229,16 +230,16 @@ code --install-extension ric-v.postgres-explorer ## 📚 Resources -- 📖 [Full Documentation](https://dev-asterix.github.io/yape/) -- 🐛 [Report Issues](https://github.com/dev-asterix/yape/issues) -- 💡 [Request Features](https://github.com/dev-asterix/yape/issues/new?template=feature_request.md) -- ⭐ [Star on GitHub](https://github.com/dev-asterix/yape) +- 📖 [Full Documentation](https://pgstudio.astrx.dev/) +- 🐛 [Report Issues](https://github.com/dev-asterix/PgStudio/issues) +- 💡 [Request Features](https://github.com/dev-asterix/PgStudio/issues/new?template=feature_request.md) +- ⭐ [Star on GitHub](https://github.com/dev-asterix/PgStudio) --- ## 📝 License -This extension is licensed under the [MIT License](https://github.com/dev-asterix/yape/blob/main/LICENSE). +This extension is licensed under the [MIT License](https://github.com/dev-asterix/PgStudio/blob/main/LICENSE). --- diff --git a/Makefile b/Makefile index 61adf4c..a6c640a 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ -.PHONY: all clean install build package publish publish-ovsx publish-vsx git-tag test test-unit test-integration test-renderer test-all coverage docker-up docker-down +.PHONY: all clean install build package package-nightly publish publish-nightly publish-ovsx publish-vsx git-tag test test-unit test-integration test-renderer test-all coverage docker-up docker-down # Variables NODE_BIN := node NPM_BIN := npm VSCE_CMD := npx -y @vscode/vsce@2.24.0 OVSX_CMD := npx -y ovsx +OPENVSX_NIGHTLY_NAME ?= postgres-explorer-nightly +# Evaluate once per make invocation to keep package/publish nightly version consistent. +NIGHTLY_RUN_NUMBER := $(shell date +%s) # Get version and name from package.json using node EXTENSION_NAME := $(shell $(NODE_BIN) -p "require('./package.json').name") @@ -38,6 +41,25 @@ package: build echo "Restored original README.md"; \ exit $$EXIT_CODE +# Package nightly VSIX artifacts for Marketplace (pre-release) and Open VSX companion +package-nightly: build + @echo "Computing nightly version..." + @NIGHTLY_VERSION=$$($(NODE_BIN) -e "const [maj,min]=require('./package.json').version.split('.').map(Number); const nightlyMinor=min%2===0?min+1:min; const run='$(NIGHTLY_RUN_NUMBER)'; process.stdout.write(maj + '.' + nightlyMinor + '.' + run)"); \ + echo "Using nightly version: $$NIGHTLY_VERSION"; \ + NIGHTLY_VERSION=$$NIGHTLY_VERSION OPENVSX_NIGHTLY_NAME=$(OPENVSX_NIGHTLY_NAME) $(NODE_BIN) ./scripts/prepare-nightly-manifests.js + @echo "Packaging VS Code Marketplace nightly (pre-release)..." + @cp package.json package.json.bak + @cp .nightly/package.marketplace.json package.json + @$(VSCE_CMD) package --pre-release + @mv package.json.bak package.json + @echo "Packaging Open VSX nightly companion..." + @cp package.json package.json.bak + @cp .nightly/package.openvsx.json package.json + @$(VSCE_CMD) package + @mv package.json.bak package.json + @echo "Nightly packages created:" + @ls -1 *.vsix + # Publish the extension to VS Code Marketplace and Open VSX Registry publish: package @echo "Publishing $(VSIX_FILE) to VS Code Marketplace..." @@ -50,6 +72,20 @@ publish: package $(OVSX_CMD) publish $(VSIX_FILE) -p $(shell cat ./pat-open-vsx) @echo "Successfully published to Open VSX Registry." +# Publish nightly artifacts to both VS Code Marketplace and Open VSX +publish-nightly: package-nightly + @echo "Publishing nightly pre-release to VS Code Marketplace..." + test -f ./pat || (echo "Error: pat file not found. Please create a file named 'pat' containing your Personal Access Token." && exit 1) + @NIGHTLY_VERSION=$$($(NODE_BIN) -e "const [maj,min]=require('./package.json').version.split('.').map(Number); const nightlyMinor=min%2===0?min+1:min; const run='$(NIGHTLY_RUN_NUMBER)'; process.stdout.write(maj + '.' + nightlyMinor + '.' + run)"); \ + MARKET_VSIX="$(EXTENSION_NAME)-$$NIGHTLY_VERSION.vsix"; \ + $(VSCE_CMD) publish --pre-release --packagePath $$MARKET_VSIX -p $$(cat ./pat) + @echo "Publishing nightly companion to Open VSX..." + test -f ./pat-open-vsx || (echo "Error: pat-open-vsx file not found. Please create a file named 'pat-open-vsx' containing your Open VSX Access Token." && exit 1) + @NIGHTLY_VERSION=$$($(NODE_BIN) -e "const [maj,min]=require('./package.json').version.split('.').map(Number); const nightlyMinor=min%2===0?min+1:min; const run='$(NIGHTLY_RUN_NUMBER)'; process.stdout.write(maj + '.' + nightlyMinor + '.' + run)"); \ + OPENVSX_VSIX="$(OPENVSX_NIGHTLY_NAME)-$$NIGHTLY_VERSION.vsix"; \ + $(OVSX_CMD) publish $$OPENVSX_VSIX -p $$(cat ./pat-open-vsx) + @echo "Successfully published nightly builds to both registries." + # Publish the extension to VS Code Marketplace only publish-vsx: package @echo "Publishing $(VSIX_FILE) to VS Code Marketplace..." @@ -138,7 +174,9 @@ help: @echo " install : Install dependencies" @echo " build : Build the extension" @echo " package : Create VSIX package" + @echo " package-nightly : Create nightly VSIX packages (Marketplace pre-release + Open VSX companion)" @echo " publish : Publish to BOTH VS Code Marketplace and Open VSX" + @echo " publish-nightly : Publish nightly builds to BOTH VS Code Marketplace and Open VSX" @echo " publish-vsx : Publish to VS Code Marketplace only" @echo " publish-ovsx : Publish to Open VSX Registry only" @echo " git-tag : Interactive version bump, commit, tag, and push" diff --git a/README.md b/README.md index 9228735..cdf1103 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,9 @@ - 🔍 **EXPLAIN CodeLens** — One-click query analysis directly in notebooks - 🛡️ **Auto-LIMIT** — Intelligent query protection (configurable, default 1000 rows) - 🌍 **Foreign Data Wrappers** — Manage foreign servers, user mappings & tables -- 🤖 **AI-Powered** — Generate, Optimize, Explain & Analyze (OpenAI, Anthropic, Gemini) +- 🤖 **AI-Powered** — Generate, Optimize, Explain & Analyze with guided follow-ups and next-step suggestions (GitHub Models, OpenAI, Anthropic, Gemini, VS Code LM) +- 🖼️ **Vision AI** — Paste or upload images directly in the SQL Assistant; sent to vision-capable AI providers +- 📎 **File Preview** — Click attached file chips to open them as preview tabs in the editor - 📤 **Export Data** — Export results to CSV, JSON, or Excel --- @@ -130,7 +132,7 @@ Then: **PostgreSQL icon** → **Add Connection** → Enter details → **Connect - `SECURITY.md` - Security policy and vulnerability reporting guidance - `CHANGELOG.md` - Release notes and what changed across versions -**v0.8.8 (latest) —** Sidebar puts **Connections** and **SQL Assistant** first; **Saved Queries** and **Query History** start collapsed for fresh view state; **What’s New** is command-palette only. Notebook inline edits use **parameterized SQL inside transactions**. **Table Designer** adds **create-mode column reorder** and improved **SQL preview** styling. Details: `CHANGELOG.md`. +**v0.9.5 (latest) —** SQL Assistant now supports image paste/upload with thumbnail previews, vision AI (OpenAI, Anthropic, Gemini, VS Code LM), click-to-preview for attached files, and GitHub Models sign-in via standard VS Code GitHub auth. Details: `CHANGELOG.md`. --- @@ -202,6 +204,12 @@ Organize, manage, and reuse your most important queries with intelligent tagging PgStudio integrates advanced AI capabilities directly into your workflow, but keeps **YOU** in control. +### 🔐 GitHub Models via GitHub Sign-In +Use GitHub Models without manually managing a PAT in normal VS Code authentication flows. +- **Native Sign-In**: Connect with your GitHub account from AI Settings. +- **Model Catalog Access**: List and select available GitHub-hosted models. +- **Session-Based Auth**: Uses VS Code GitHub authentication sessions instead of storing provider tokens. + ### 🪄 Generate Query (Natural Language → SQL) Describe what you need in plain English (e.g., "Show me top 10 users by order count"), and PgStudio will generate the SQL for you using your schema context. - **Command Palette**: `AI: Generate Query` @@ -401,6 +409,31 @@ npx vsce publish npx ovsx publish ``` +### Stable And Nightly Channels + +- Stable releases are published from version tags (`v*`) via `.github/workflows/publish.yml`. +- Nightly releases are published on every merge to `main` via `.github/workflows/publish-nightly.yml`. + +VS Code Marketplace channel behavior: + +- Stable extension ID: `ric-v.postgres-explorer` +- Nightly is published as a **pre-release** of the same extension ID. +- Users can opt in/out directly from the extension page with: + - `Switch to Pre-Release Version` + - `Switch to Release Version` + +Open VSX channel behavior: + +- Stable extension ID: `ric-v.postgres-explorer` +- Nightly companion extension ID: `ric-v.postgres-explorer-nightly` +- To opt out of nightly on Open VSX-based editors, uninstall the nightly companion extension and install stable. + +Nightly versioning policy: + +- Nightly builds use an odd minor stream and CI run number as patch. +- Example format: `0.9.` +- This keeps nightly versions monotonically increasing for reliable updates. + --- ## 📝 License diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index b67d28f..42dec7b 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -36,7 +36,7 @@ graph TB subgraph "External Systems" PG[(PostgreSQL Database)] - AI[AI Services
OpenAI/Anthropic/Gemini] + AI[AI Services
GitHub Models/OpenAI/Anthropic/Gemini] end EXT --> CMD diff --git a/docs/index.html b/docs/index.html index 5b2712f..fd60d70 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,6 +7,21 @@ PgStudio - Professional Database Management for VS Code + + + + + + + + + + + + + @@ -37,7 +69,7 @@ Features Workflow AI - GitHub + GitHub Install @@ -54,7 +86,7 @@ @@ -284,7 +316,7 @@

Advanced Operations

Developer Tools

Built for speed with integrated workflow tools.

    -
  • GitHub Copilot integration
  • +
  • GitHub Copilot & GitHub Models integration
  • IntelliSense completions
  • Keyboard shortcuts
  • PSQL terminal access
  • @@ -335,7 +367,7 @@

    Advanced Visualizations

    ✨ AI-Powered

    Intelligent SQL Assistance

    -

    Leverage multiple AI providers to write, optimize, and debug faster

    +

    Leverage multiple AI providers, including GitHub Models, to write, optimize, and debug faster

    @@ -374,6 +406,16 @@

    Schema Understanding

    Send to Chat

    One-click button to send query results directly to AI chat for follow-up analysis

    +
    +
    🔐
    +

    GitHub Models Sign-In

    +

    Connect with your GitHub account in AI Settings using the standard VS Code authentication flow

    +
    +
    +
    🖼️
    +

    Vision AI

    +

    Paste or upload images directly in the chat — sent to vision-capable models (OpenAI, Anthropic, Gemini)

    +
    🛠️

    Custom Instructions

    @@ -479,13 +521,13 @@

    AI Assistant in Action

    + + diff --git a/templates/dashboard/scripts.js b/templates/dashboard/scripts.js index a45aedc..597bab3 100644 --- a/templates/dashboard/scripts.js +++ b/templates/dashboard/scripts.js @@ -53,8 +53,16 @@ let rollbackHistory = new Array(maxHistory).fill(0); let cacheHitHistory = new Array(maxHistory).fill(100); let longRunningHistory = new Array(maxHistory).fill(0); -// Initial State Placeholder - Will be injected -const initialStats = null; // __STATS_JSON__ +const statsElement = document.getElementById('dashboard-stats'); +let initialStats = null; + +if (statsElement && statsElement.textContent) { + try { + initialStats = JSON.parse(statsElement.textContent); + } catch (error) { + console.error('Dashboard: Failed to parse initial stats', error); + } +} // Track PIDs for lock visualization let blockingPids = new Set(); @@ -1118,4 +1126,6 @@ document.querySelectorAll('.tab').forEach(t => { // Init initializeDashboard(initialStats); -updateDashboard(initialStats); // Populate initial charts +if (initialStats) { + updateDashboard(initialStats); // Populate initial charts +} diff --git a/templates/dashboard/styles.css b/templates/dashboard/styles.css index 80854d9..3ae0509 100644 --- a/templates/dashboard/styles.css +++ b/templates/dashboard/styles.css @@ -5,40 +5,48 @@ --border-color: var(--vscode-widget-border); --muted-color: var(--vscode-descriptionForeground); --accent-color: var(--vscode-textLink-foreground); - --success-color: #4ade80; - --warning-color: #facc15; - --danger-color: #f87171; + --success-color: var(--vscode-testing-iconPassed, #4ade80); + --warning-color: var(--vscode-editorWarning-foreground, #facc15); + --danger-color: var(--vscode-errorForeground, #f87171); --font-family: var(--vscode-font-family); --card-radius: 6px; --card-border: 1px solid var(--border-color); + /* 4px spacing tokens */ + --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-6: 24px; --sp-8: 32px; } body { background-color: var(--bg-color); color: var(--fg-color); font-family: var(--font-family); + font-size: 13px; margin: 0; - padding: 24px; + padding: var(--sp-6); display: flex; flex-direction: column; - gap: 32px; + gap: var(--sp-8); } -/* --- Typography --- */ -h1, -h2, -h3 { - margin: 0; - font-weight: 500; -} +/* --- Typography scale --- */ +h1, h2, h3 { margin: 0; font-weight: 500; } +/* Section headers: 12px/500 */ +.section-label, .label { - font-size: 0.75rem; + font-size: 12px; + font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted-color); } +/* Meta/labels: 11px/400 muted */ +.meta, th { + font-size: 11px; + font-weight: 400; + color: var(--muted-color); +} + .value { font-size: 1.5rem; font-weight: 600; @@ -53,14 +61,14 @@ h3 { .grid-strip { display: grid; grid-template-columns: repeat(5, 1fr); - gap: 16px; + gap: var(--sp-4); } .card { background: var(--card-bg); border: var(--card-border); border-radius: var(--card-radius); - padding: 16px; + padding: var(--sp-4); display: flex; flex-direction: column; justify-content: space-between; @@ -82,17 +90,9 @@ h3 { margin-right: 6px; } -.status-ok { - background-color: var(--success-color); -} - -.status-warn { - background-color: var(--warning-color); -} - -.status-crit { - background-color: var(--danger-color); -} +.status-ok { background-color: var(--success-color); } +.status-warn { background-color: var(--warning-color); } +.status-crit { background-color: var(--danger-color); } /* --- Specific Sections --- */ .header { @@ -103,32 +103,30 @@ h3 { .header-info { display: flex; - gap: 24px; + gap: var(--sp-6); color: var(--muted-color); - font-size: 0.9rem; + font-size: 12px; } /* --- Tabs --- */ .tabs-nav { display: flex; border-bottom: 2px solid var(--border-color); - margin-bottom: 20px; + margin-bottom: var(--sp-4); } .tab { - padding: 8px 16px; + padding: var(--sp-2) var(--sp-4); cursor: pointer; opacity: 0.6; + font-size: 12px; font-weight: 500; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all 0.2s; } -.tab:hover { - opacity: 1; - color: var(--fg-color); -} +.tab:hover { opacity: 1; color: var(--fg-color); } .tab.active { opacity: 1; @@ -136,25 +134,20 @@ h3 { color: var(--accent-color); } -.tab-content { - display: none; -} - -.tab-content.active { - display: block; -} +.tab-content { display: none; } +.tab-content.active { display: block; } /* --- Charts Area --- */ .charts-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 24px; + gap: var(--sp-6); } .chart-box { border: var(--card-border); border-radius: var(--card-radius); - padding: 16px; + padding: var(--sp-4); height: 200px; } @@ -169,52 +162,114 @@ h3 { table { width: 100%; border-collapse: collapse; - font-size: 0.9rem; + font-size: 13px; } th { text-align: left; - padding: 12px 16px; + padding: var(--sp-2) var(--sp-4); background: rgba(128, 128, 128, 0.05); font-weight: 500; + font-size: 11px; color: var(--muted-color); - font-size: 0.8rem; white-space: nowrap; } td { - padding: 12px 16px; + padding: var(--sp-2) var(--sp-4); border-top: 1px solid var(--border-color); + font-size: 13px; +} + +/* Hover-reveal row actions */ +tr { position: relative; } +tr .row-actions { + position: absolute; + right: var(--sp-2); + top: 50%; + transform: translateY(-50%); + display: flex; + gap: var(--sp-1); + opacity: 0; + pointer-events: none; + transition: opacity 0.12s ease; +} +tr:hover .row-actions { + opacity: 1; + pointer-events: auto; +} + +tr.row-crit { background: rgba(248, 113, 113, 0.15); } +tr.row-warn { background: rgba(250, 204, 21, 0.1); } + +/* --- Skeleton loading shimmer --- */ +@keyframes skeleton-pulse { + 0% { opacity: 0.45; } + 50% { opacity: 0.9; } + 100% { opacity: 0.45; } +} +.skeleton-cell { + height: 12px; + background: var(--border-color); + border-radius: 2px; + animation: skeleton-pulse 1.6s ease-in-out infinite; + display: inline-block; } -tr.row-crit { - background: rgba(248, 113, 113, 0.15); +/* --- Empty state --- */ +.empty-state { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--sp-2); + padding: var(--sp-6) var(--sp-4); + color: var(--muted-color); + font-size: 12px; + text-align: center; +} +.empty-state .empty-cta { + margin-top: var(--sp-2); + padding: var(--sp-1) var(--sp-3); + font-size: 12px; + font-weight: 500; + background: var(--vscode-button-background); + color: var(--vscode-button-foreground); + border: none; + border-radius: 3px; + cursor: pointer; } +.empty-state .empty-cta:hover { background: var(--vscode-button-hoverBackground); } -tr.row-warn { - background: rgba(250, 204, 21, 0.1); +/* --- Destructive button --- */ +.btn-danger { + background: transparent; + color: var(--danger-color); + border: 1px solid var(--danger-color); + border-radius: 3px; + padding: var(--sp-1) var(--sp-3); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: background 0.15s ease; +} +.btn-danger:hover:not(:disabled) { + background: color-mix(in srgb, var(--danger-color) 12%, transparent); } /* --- Lock Tree Visualizer --- */ .lock-node { border: 1px solid var(--border-color); - margin: 8px 0; - padding: 12px; + margin: var(--sp-2) 0; + padding: var(--sp-3); border-radius: 4px; } .lock-children { - margin-left: 24px; + margin-left: var(--sp-6); border-left: 2px solid var(--border-color); - padding-left: 12px; + padding-left: var(--sp-3); } /* --- Detail View --- */ -#detail-view { - display: none; - margin-top: 24px; -} - -#main-view { - display: block; -} \ No newline at end of file +#detail-view { display: none; margin-top: var(--sp-6); } +#main-view { display: block; } \ No newline at end of file