diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 7e2e27e6..9236e08c 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -14,8 +14,8 @@ concurrency: env: NODE_OPTIONS: "--max-old-space-size=4096" - GO_VERSION: "1.24" - NODE_VERSION: "20" + GO_VERSION: "1.26" + NODE_VERSION: "24" PNPM_VERSION: "10" jobs: @@ -89,27 +89,46 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 shell: bash - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package + - name: Build frontend shell: bash - run: pnpm run build - working-directory: packages/omniviewdev-runtime + run: task common:build:frontend - name: Build Omniview shell: bash + env: + CGO_ENABLED: "1" + CGO_CFLAGS: "-mmacosx-version-min=10.15" + CGO_LDFLAGS: "-mmacosx-version-min=10.15" + MACOSX_DEPLOYMENT_TARGET: "10.15" run: | - wails build -platform darwin/universal \ - -webview2 download \ - -ldflags "\ + go build -tags production -trimpath -buildvcs=false \ + -ldflags "-w -s \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ needs.check-changes.outputs.nightly_version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=true \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview . + + - name: Create macOS .app bundle + run: | + task common:generate:icons + mkdir -p bin/Omniview.app/Contents/MacOS + mkdir -p bin/Omniview.app/Contents/Resources + cp build/darwin/icons.icns bin/Omniview.app/Contents/Resources/ + cp bin/Omniview bin/Omniview.app/Contents/MacOS/ + cp build/darwin/Info.plist bin/Omniview.app/Contents/ - name: Import Code-Signing Certificates uses: Apple-Actions/import-codesign-certs@v3 @@ -129,9 +148,9 @@ jobs: --options runtime \ --entitlements build/darwin/entitlements.plist \ --sign "$APPLE_SIGN_ID" \ - build/bin/Omniview.app + bin/Omniview.app - ditto -c -k --keepParent --rsrc build/bin/Omniview.app archive.zip + ditto -c -k --keepParent --rsrc bin/Omniview.app archive.zip xcrun notarytool submit archive.zip \ --apple-id "$NOTARY_USER" \ @@ -139,7 +158,7 @@ jobs: --team-id "$TEAM_ID" \ --wait - xcrun stapler staple build/bin/Omniview.app + xcrun stapler staple bin/Omniview.app - name: Checkout create-dmg uses: actions/checkout@v4 @@ -153,10 +172,9 @@ jobs: working-directory: ./build run: | VERSION="${{ needs.check-changes.outputs.nightly_version }}" - ./create-dmg/create-dmg \ + ../build/create-dmg/create-dmg \ --no-internet-enable \ --volname "Omniview Nightly" \ - --volicon "bin/Omniview.app/Contents/Resources/iconfile.icns" \ --text-size 12 \ --window-pos 400 400 \ --window-size 660 450 \ @@ -164,14 +182,14 @@ jobs: --icon "Omniview.app" 180 180 \ --hide-extension "Omniview.app" \ --app-drop-link 480 180 \ - "bin/Omniview_${VERSION}_darwin_universal.dmg" \ - "bin" + "../bin/Omniview_${VERSION}_darwin_universal.dmg" \ + "../bin" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: nightly-macos-dmg - path: build/bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_darwin_universal.dmg + path: bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_darwin_universal.dmg if-no-files-found: error retention-days: 1 @@ -188,10 +206,11 @@ jobs: with: submodules: recursive - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev + - name: Install Linux dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config + version: 1.0 - name: Setup Node uses: actions/setup-node@v4 @@ -213,35 +232,39 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package - run: pnpm run build - working-directory: packages/omniviewdev-runtime + - name: Build frontend + run: task common:build:frontend - name: Build Omniview run: | - wails build -platform linux/amd64 \ - -tags webkit2_41 \ - -webview2 download \ - -ldflags "\ + go build -tags "production,webkit2_41" -trimpath -buildvcs=false \ + -ldflags "-w -s \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ needs.check-changes.outputs.nightly_version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=true \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview . - name: Rename executable - working-directory: ./build/bin + working-directory: ./bin run: mv Omniview "Omniview_${{ needs.check-changes.outputs.nightly_version }}_linux_amd64" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: nightly-linux-binary - path: build/bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_linux_amd64 + path: bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_linux_amd64 if-no-files-found: error retention-days: 1 @@ -278,37 +301,42 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 shell: bash - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package + - name: Build frontend shell: bash - run: pnpm run build - working-directory: packages/omniviewdev-runtime + run: task common:build:frontend - name: Build Omniview shell: bash run: | - wails build -platform windows/amd64 \ - -webview2 download \ - -ldflags "\ + go build -tags production -trimpath -buildvcs=false \ + -ldflags "-w -s -H windowsgui \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ needs.check-changes.outputs.nightly_version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=true \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview.exe . - name: Rename executable - working-directory: ./build/bin + working-directory: ./bin run: Rename-Item -Path "Omniview.exe" -NewName "Omniview_${{ needs.check-changes.outputs.nightly_version }}_windows_amd64.exe" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: nightly-windows-binary - path: build/bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_windows_amd64.exe + path: bin/Omniview_${{ needs.check-changes.outputs.nightly_version }}_windows_amd64.exe if-no-files-found: error retention-days: 1 diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 1a5bb253..c60778b1 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -10,8 +10,8 @@ concurrency: env: GO_VERSION: "1.26" - NODE_VERSION: "20.18.1" - PNPM_VERSION: "9.15.0" + NODE_VERSION: "24" + PNPM_VERSION: "10" jobs: go-checks: @@ -20,22 +20,34 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Linux dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config + version: 1.0 + - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: true + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Build - run: make go-build + run: task check:go-build - name: Vet - run: make go-vet + run: task check:go-vet - name: Test - run: make go-test + run: task check:go-test - name: Format check - run: make fmt-check + run: task check:fmt-check continue-on-error: true - name: Lint @@ -53,16 +65,28 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Linux dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config + version: 1.0 + - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: true - - name: Install wails - run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.11.0 + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install wails3 + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - name: Check bindings are up to date - run: make bindings-check + run: task check:bindings-check ui-checks: name: UI checks @@ -78,6 +102,12 @@ jobs: with: version: ${{ env.PNPM_VERSION }} + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Get pnpm store directory id: pnpm-cache shell: bash @@ -90,15 +120,15 @@ jobs: restore-keys: ${{ runner.os }}-pnpm-store- - name: Install dependencies - run: make ui-install + run: task check:ui-install - name: Build - run: make ui-build + run: task check:ui-build - name: Lint - run: make ui-lint + run: task check:ui-lint continue-on-error: true - name: Typecheck - run: make ui-typecheck + run: task check:ui-typecheck continue-on-error: true diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 8b4d215c..b2f2aa74 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -11,14 +11,17 @@ concurrency: env: NODE_OPTIONS: "--max-old-space-size=4096" GO_VERSION: "1.26" - NODE_VERSION: "20" + NODE_VERSION: "24" PNPM_VERSION: "10" jobs: # ───────────────────────────────────────────────────────────────────────────── - # E2E Tests — Playwright against wails dev + # E2E Tests — Playwright against server mode + # Disabled: Wails v3 alpha.74 server mode is broken (BrowserWindow missing + # AttachModal method). Re-enable when upstream fixes this. # ───────────────────────────────────────────────────────────────────────────── e2e-tests: + if: false # TODO: re-enable when Wails v3 server mode is fixed runs-on: ubuntu-latest timeout-minutes: 20 steps: @@ -27,10 +30,11 @@ jobs: with: submodules: recursive - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev xvfb + - name: Install Linux dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config xvfb + version: 1.0 - name: Setup Node uses: actions/setup-node@v4 @@ -52,29 +56,35 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails - run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.11.0 + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - name: Build workspace packages - run: make packages + run: task packages - name: Install Playwright browsers working-directory: e2e run: pnpm exec playwright install --with-deps chromium - - name: Start wails dev + - name: Build and start server mode run: | - xvfb-run wails dev -loglevel Error -tags webkit2_41 -nosyncgomod -m -noreload -skipbindings & - echo "Waiting for Wails dev server..." - for i in $(seq 1 150); do - if curl -sf http://localhost:34115 > /dev/null 2>&1; then - echo "Wails dev server is ready (${i}s)" - exit 0 + task common:build:frontend + go build -tags server -o bin/Omniview-server . + bin/Omniview-server & + echo "Waiting for server to be ready..." + for i in $(seq 1 60); do + if curl -sf http://localhost:34115/health > /dev/null 2>&1; then + echo "Server ready" + break fi sleep 2 done - echo "Timed out waiting for Wails dev server" - exit 1 - name: Run Playwright tests working-directory: e2e @@ -101,15 +111,18 @@ jobs: - os: macos-latest platform: darwin/universal artifact-name: pr-build-macos - extra-flags: "" + build-tags: "production" + extra-ldflags: "" - os: ubuntu-latest platform: linux/amd64 artifact-name: pr-build-linux - extra-flags: "-tags webkit2_41" + build-tags: "production,webkit2_41" + extra-ldflags: "" - os: windows-latest platform: windows/amd64 artifact-name: pr-build-windows - extra-flags: "" + build-tags: "production" + extra-ldflags: "-H windowsgui" runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: @@ -118,11 +131,12 @@ jobs: with: submodules: recursive - - name: Install system dependencies (Linux) + - name: Install Linux dependencies if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config + version: 1.0 - name: Setup Node uses: actions/setup-node@v4 @@ -144,48 +158,73 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 shell: bash - run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.11.0 + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - name: Build workspace packages shell: bash - run: make packages + run: task packages + + - name: Build frontend + shell: bash + run: task common:build:frontend - name: Build Omniview shell: bash + env: + CGO_ENABLED: "1" + CGO_CFLAGS: ${{ runner.os == 'macOS' && '-mmacosx-version-min=10.15' || '' }} + CGO_LDFLAGS: ${{ runner.os == 'macOS' && '-mmacosx-version-min=10.15' || '' }} + MACOSX_DEPLOYMENT_TARGET: ${{ runner.os == 'macOS' && '10.15' || '' }} run: | - wails build -platform ${{ matrix.platform }} \ - ${{ matrix.extra-flags }} \ - -webview2 download \ - -ldflags "\ + go build -tags "${{ matrix.build-tags }}" -trimpath -buildvcs=false \ + -ldflags "-w -s ${{ matrix.extra-ldflags }} \ -X github.com/omniviewdev/omniview/internal/version.Version=0.0.0-pr.${{ github.event.pull_request.number }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ - -X github.com/omniviewdev/omniview/internal/version.Development=true" + -X github.com/omniviewdev/omniview/internal/version.Development=true" \ + -o bin/Omniview . + + - name: Create macOS .app bundle + if: runner.os == 'macOS' + run: | + task common:generate:icons + mkdir -p bin/Omniview.app/Contents/MacOS + mkdir -p bin/Omniview.app/Contents/Resources + cp build/darwin/icons.icns bin/Omniview.app/Contents/Resources/ + cp bin/Omniview bin/Omniview.app/Contents/MacOS/ + cp build/darwin/Info.plist bin/Omniview.app/Contents/ + codesign --force --deep --sign - bin/Omniview.app - name: Prepare artifact (macOS) if: runner.os == 'macOS' run: | - cd build/bin + cd bin zip -r Omniview-pr${{ github.event.pull_request.number }}-macos.zip Omniview.app - name: Prepare artifact (Linux) if: runner.os == 'Linux' - working-directory: build/bin + working-directory: bin run: mv Omniview "Omniview-pr${{ github.event.pull_request.number }}-linux-amd64" - name: Prepare artifact (Windows) if: runner.os == 'Windows' - working-directory: build/bin - run: Rename-Item -Path "Omniview.exe" -NewName "Omniview-pr${{ github.event.pull_request.number }}-windows-amd64.exe" + working-directory: bin + run: Rename-Item -Path "Omniview" -NewName "Omniview-pr${{ github.event.pull_request.number }}-windows-amd64.exe" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.artifact-name }} path: | - build/bin/*.zip - build/bin/Omniview-pr* + bin/*.zip + bin/Omniview-pr* if-no-files-found: error retention-days: 5 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d85a5d58..84d66a80 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,7 +15,7 @@ concurrency: env: NODE_OPTIONS: "--max-old-space-size=4096" GO_VERSION: "1.26" - NODE_VERSION: "20" + NODE_VERSION: "24" PNPM_VERSION: "10" jobs: @@ -57,28 +57,47 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 shell: bash - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package + - name: Build frontend shell: bash - run: pnpm run build - working-directory: packages/omniviewdev-runtime + run: task common:build:frontend - name: Build Omniview shell: bash + env: + CGO_ENABLED: "1" + CGO_CFLAGS: "-mmacosx-version-min=10.15" + CGO_LDFLAGS: "-mmacosx-version-min=10.15" + MACOSX_DEPLOYMENT_TARGET: "10.15" run: | - wails build -platform darwin/universal \ - -webview2 download \ - -ldflags "\ + go build -tags production -trimpath -buildvcs=false \ + -ldflags "-w -s \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ steps.version.outputs.version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=false \ -X github.com/omniviewdev/registry.OmniviewPublicKeyHex=${{ secrets.REGISTRY_PUBLIC_KEY_HEX }} \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview . + + - name: Create macOS .app bundle + run: | + task common:generate:icons + mkdir -p bin/Omniview.app/Contents/MacOS + mkdir -p bin/Omniview.app/Contents/Resources + cp build/darwin/icons.icns bin/Omniview.app/Contents/Resources/ + cp bin/Omniview bin/Omniview.app/Contents/MacOS/ + cp build/darwin/Info.plist bin/Omniview.app/Contents/ - name: Import Code-Signing Certificates uses: Apple-Actions/import-codesign-certs@v3 @@ -98,9 +117,9 @@ jobs: --options runtime \ --entitlements build/darwin/entitlements.plist \ --sign "$APPLE_SIGN_ID" \ - build/bin/Omniview.app + bin/Omniview.app - ditto -c -k --keepParent --rsrc build/bin/Omniview.app archive.zip + ditto -c -k --keepParent --rsrc bin/Omniview.app archive.zip xcrun notarytool submit archive.zip \ --apple-id "$NOTARY_USER" \ @@ -108,8 +127,7 @@ jobs: --team-id "$TEAM_ID" \ --wait - xcrun stapler staple build/bin/Omniview.app - spctl --assess --type execute --verbose build/bin/Omniview.app + xcrun stapler staple bin/Omniview.app - name: Checkout create-dmg uses: actions/checkout@v4 @@ -122,10 +140,9 @@ jobs: shell: bash working-directory: ./build run: | - ./create-dmg/create-dmg \ + ../build/create-dmg/create-dmg \ --no-internet-enable \ --volname "Omniview" \ - --volicon "bin/Omniview.app/Contents/Resources/iconfile.icns" \ --text-size 12 \ --window-pos 400 400 \ --window-size 660 450 \ @@ -133,14 +150,14 @@ jobs: --icon "Omniview.app" 180 180 \ --hide-extension "Omniview.app" \ --app-drop-link 480 180 \ - "bin/Omniview_${{ steps.version.outputs.version }}_darwin_universal.dmg" \ - "bin" + "../bin/Omniview_${{ steps.version.outputs.version }}_darwin_universal.dmg" \ + "../bin" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: macos-dmg - path: build/bin/Omniview_${{ steps.version.outputs.version }}_darwin_universal.dmg + path: bin/Omniview_${{ steps.version.outputs.version }}_darwin_universal.dmg if-no-files-found: error retention-days: 1 @@ -162,10 +179,11 @@ jobs: with: submodules: recursive - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev + - name: Install Linux dependencies + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: libgtk-3-dev libwebkit2gtk-4.1-dev libwayland-dev build-essential pkg-config + version: 1.0 - name: Setup Node uses: actions/setup-node@v4 @@ -187,36 +205,40 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package - run: pnpm run build - working-directory: packages/omniviewdev-runtime + - name: Build frontend + run: task common:build:frontend - name: Build Omniview run: | - wails build -platform linux/amd64 \ - -tags webkit2_41 \ - -webview2 download \ - -ldflags "\ + go build -tags "production,webkit2_41" -trimpath -buildvcs=false \ + -ldflags "-w -s \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ steps.version.outputs.version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=false \ -X github.com/omniviewdev/registry.OmniviewPublicKeyHex=${{ secrets.REGISTRY_PUBLIC_KEY_HEX }} \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview . - name: Rename executable - working-directory: ./build/bin + working-directory: ./bin run: mv Omniview "Omniview_${{ steps.version.outputs.version }}_linux_amd64" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: linux-binary - path: build/bin/Omniview_${{ steps.version.outputs.version }}_linux_amd64 + path: bin/Omniview_${{ steps.version.outputs.version }}_linux_amd64 if-no-files-found: error retention-days: 1 @@ -258,38 +280,43 @@ jobs: cache: true cache-dependency-path: "go.sum" - - name: Install Wails + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Wails v3 shell: bash - run: go install github.com/wailsapp/wails/v2/cmd/wails@latest + run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest - - name: Build runtime package + - name: Build frontend shell: bash - run: pnpm run build - working-directory: packages/omniviewdev-runtime + run: task common:build:frontend - name: Build Omniview shell: bash run: | - wails build -platform windows/amd64 \ - -webview2 download \ - -ldflags "\ + go build -tags production -trimpath -buildvcs=false \ + -ldflags "-w -s -H windowsgui \ -X github.com/omniviewdev/omniview/internal/version.Version=${{ steps.version.outputs.version }} \ -X github.com/omniviewdev/omniview/internal/version.GitCommit=${{ github.sha }} \ -X github.com/omniviewdev/omniview/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ) \ -X github.com/omniviewdev/omniview/internal/version.Development=false \ -X github.com/omniviewdev/registry.OmniviewPublicKeyHex=${{ secrets.REGISTRY_PUBLIC_KEY_HEX }} \ -X github.com/omniviewdev/omniview/internal/telemetry.buildOTLPEndpoint=${{ secrets.TELEMETRY_OTLP_ENDPOINT }} \ - -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" + -X github.com/omniviewdev/omniview/internal/telemetry.buildPyroscopeEndpoint=${{ secrets.TELEMETRY_PYROSCOPE_ENDPOINT }}" \ + -o bin/Omniview.exe . - name: Rename executable - working-directory: ./build/bin + working-directory: ./bin run: Rename-Item -Path "Omniview.exe" -NewName "Omniview_${{ steps.version.outputs.version }}_windows_amd64.exe" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: windows-binary - path: build/bin/Omniview_${{ steps.version.outputs.version }}_windows_amd64.exe + path: bin/Omniview_${{ steps.version.outputs.version }}_windows_amd64.exe if-no-files-found: error retention-days: 1 diff --git a/.gitignore b/.gitignore index ced5644b..ab7e0a41 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,7 @@ benchmarks/ # E2E tests e2e/test-results/ e2e/playwright-report/ + +# Task runner +.task +omniview diff --git a/.tool-versions b/.tool-versions index 15cd0865..e4861ad1 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ -pnpm 9.15.0 -nodejs 20.18.1 -golang 1.23.8 +pnpm 10.26.0 +nodejs 24.14.0 +golang 1.26.1 diff --git a/Makefile b/Makefile deleted file mode 100644 index d8a42453..00000000 --- a/Makefile +++ /dev/null @@ -1,162 +0,0 @@ - -.PHONY: docs prepare sync packages dev dev-plugin runtime build e2e e2e-ui e2e-report -.PHONY: check go-build go-vet go-test go-lint bindings bindings-check -.PHONY: ui-install ui-build ui-lint ui-typecheck fmt fmt-check - -# ────────────────────────────────────────────── -# CI / Verification targets -# ────────────────────────────────────────────── - -# Run all checks in sequence, fail fast on first error. -# Note: dist/.gitkeep satisfies the go:embed directive so Go checks work without a frontend build. -check: go-build go-vet go-test go-lint fmt-check bindings-check ui-install ui-build ui-lint ui-typecheck - -# Go checks -go-build: - GOWORK=off go build ./... - -go-vet: - GOWORK=off go vet ./... - -go-test: - GOWORK=off go test ./... - -go-lint: - @if command -v golangci-lint >/dev/null 2>&1; then \ - GOWORK=off golangci-lint run; \ - else \ - echo "golangci-lint not installed, skipping"; \ - fi - -# Go formatting -fmt: - goimports -w . - gofmt -w . - -fmt-check: - @FAILED=0; \ - if ! command -v goimports >/dev/null 2>&1; then \ - echo "goimports not found. Install with: go install golang.org/x/tools/cmd/goimports@latest"; \ - exit 1; \ - fi; \ - UNIMPORTED=$$(goimports -l .); \ - if [ -n "$$UNIMPORTED" ]; then \ - echo "The following Go files have incorrect imports (run goimports):"; \ - echo "$$UNIMPORTED"; \ - FAILED=1; \ - fi; \ - UNFORMATTED=$$(gofmt -l .); \ - if [ -n "$$UNFORMATTED" ]; then \ - echo "The following Go files are not formatted (run gofmt):"; \ - echo "$$UNFORMATTED"; \ - FAILED=1; \ - fi; \ - if [ "$$FAILED" -eq 1 ]; then exit 1; fi - -# Wails bindings -bindings: - GOWORK=off wails generate module - -bindings-check: - @set -e; \ - TMPDIR=$$(mktemp -d); \ - cleanup() { \ - if [ -d "$$TMPDIR/wailsjs-before" ]; then \ - rm -rf packages/omniviewdev-runtime/src/wailsjs; \ - cp -R "$$TMPDIR/wailsjs-before" packages/omniviewdev-runtime/src/wailsjs; \ - fi; \ - rm -rf "$$TMPDIR"; \ - }; \ - trap cleanup EXIT; \ - cp -R packages/omniviewdev-runtime/src/wailsjs "$$TMPDIR/wailsjs-before"; \ - GOWORK=off wails generate module; \ - if ! diff -r packages/omniviewdev-runtime/src/wailsjs "$$TMPDIR/wailsjs-before" >/dev/null 2>&1; then \ - echo "Wails bindings are stale. Run 'make bindings' and commit the result."; \ - exit 1; \ - fi - -# Frontend checks -ui-install: - pnpm install --frozen-lockfile - -ui-build: - $(MAKE) packages - pnpm build - -ui-lint: - pnpm lint - -ui-typecheck: - pnpm exec tsc -p tsconfig.app.json --noEmit - -# ────────────────────────────────────────────── -# Development targets -# ────────────────────────────────────────────── - -prepare: - go install github.com/wailsapp/wails/v2/cmd/wails@v2.11.0 - -sync: - go work sync - -# Build all workspace packages in dependency order -packages: - pnpm --filter @omniviewdev/providers run build - pnpm --filter @omniviewdev/vite-plugin run build - pnpm --filter @omniviewdev/ui run build - pnpm --filter @omniviewdev/runtime run build - -dev: - pnpm install - $(MAKE) packages - wails dev -loglevel Error - -dev-plugin: - wails dev -noreload -loglevel Error - -runtime: - cd packages/omniviewdev-runtime && pnpm run build - -build: - pnpm install - $(MAKE) packages - rm -f archive.zip - wails build -clean - -.PHONY: sign -sign: - # 1. Sign the .app - codesign --deep --force \ - --options runtime \ - --entitlements build/darwin/entitlements.plist \ - --sign "Developer ID Application: Joshua Pare (696AD8J8ZT)" \ - build/bin/Omniview.app - - # 2. Zip the .app - ditto -c -k --keepParent --rsrc build/bin/Omniview.app archive.zip - - # 3. Submit for notarization - xcrun notarytool submit archive.zip \ - --apple-id "$(NOTARIZE_APPLE_ID)" \ - --password "$(NOTARIZE_PASSWORD)" \ - --team-id "$(NOTARIZE_TEAM_ID)" \ - --wait - - # 4. Staple the ticket to the .app - xcrun stapler staple build/bin/Omniview.app - - # 5. (Optional) Verify everything - spctl --assess --type execute --verbose build/bin/Omniview.app - -.PHONY: build-debug -build-debug: - wails build -clean -debug - -e2e: - cd e2e && pnpm install && pnpm exec playwright install chromium && pnpm exec playwright test - -e2e-ui: - cd e2e && pnpm exec playwright test --ui - -e2e-report: - cd e2e && pnpm exec playwright show-report diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 00000000..b251da00 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,195 @@ +version: '3' + +includes: + common: ./build/Taskfile.yml + windows: ./build/windows/Taskfile.yml + darwin: ./build/darwin/Taskfile.yml + linux: ./build/linux/Taskfile.yml + +vars: + APP_NAME: "Omniview" + BIN_DIR: "bin" + VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}' + +tasks: + build: + summary: Builds the application + cmds: + - task: "{{OS}}:build" + + package: + summary: Packages a production build of the application + cmds: + - task: "{{OS}}:package" + + run: + summary: Runs the application + cmds: + - task: "{{OS}}:run" + + dev: + summary: Runs the application in development mode + cmds: + - wails3 dev -config ./build/config.yml -port {{.VITE_PORT}} + + # Server mode (headless HTTP server) is not yet supported on macOS in + # Wails v3 alpha.74 due to build tag conflicts. For E2E testing, + # Playwright connects to the Vite dev server (port 9245) started by `task dev`. + # TODO: Enable server mode when Wails v3 adds !server to darwin files. + # build:server: + # deps: + # - task: common:build:frontend + # cmds: + # - go build -tags server -o {{.BIN_DIR}}/{{.APP_NAME}}-server + # run:server: + # deps: + # - task: build:server + # cmds: + # - ./{{.BIN_DIR}}/{{.APP_NAME}}-server + + # ────────────────────────────────────────────── + # CI / Verification targets + # ────────────────────────────────────────────── + + check: + summary: Run all CI checks in sequence + cmds: + - task: check:go-build + - task: check:go-vet + - task: check:go-test + - task: check:go-lint + - task: check:fmt-check + - task: check:bindings-check + - task: check:ui-install + - task: check:ui-build + - task: check:ui-lint + - task: check:ui-typecheck + + check:go-build: + cmds: + - GOWORK=off go build ./... + + check:go-vet: + cmds: + - GOWORK=off go vet ./... + + check:go-test: + cmds: + - GOWORK=off go test ./... + + check:go-lint: + cmds: + - cmd: | + if command -v golangci-lint >/dev/null 2>&1; then + GOWORK=off golangci-lint run + else + echo "golangci-lint not installed, skipping" + fi + + check:fmt: + aliases: [fmt] + cmds: + - goimports -w . + - gofmt -w . + + check:fmt-check: + cmds: + - cmd: | + FAILED=0 + if ! command -v goimports >/dev/null 2>&1; then + echo "goimports not found. Install with: go install golang.org/x/tools/cmd/goimports@latest" + exit 1 + fi + UNIMPORTED=$(goimports -l .) + if [ -n "$UNIMPORTED" ]; then + echo "The following Go files have incorrect imports (run goimports):" + echo "$UNIMPORTED" + FAILED=1 + fi + UNFORMATTED=$(gofmt -l .) + if [ -n "$UNFORMATTED" ]; then + echo "The following Go files are not formatted (run gofmt):" + echo "$UNFORMATTED" + FAILED=1 + fi + if [ "$FAILED" -eq 1 ]; then exit 1; fi + + check:bindings: + aliases: [bindings] + cmds: + - task: common:generate:bindings + + check:bindings-check: + cmds: + - cmd: | + set -e + BINDINGS_DIR=packages/omniviewdev-runtime/src/bindings + TMPDIR=$(mktemp -d) + cleanup() { + if [ -d "$TMPDIR/bindings-before" ]; then + rm -rf "$BINDINGS_DIR" + cp -R "$TMPDIR/bindings-before" "$BINDINGS_DIR" + fi + rm -rf "$TMPDIR" + } + trap cleanup EXIT + if [ -d "$BINDINGS_DIR" ]; then + cp -R "$BINDINGS_DIR" "$TMPDIR/bindings-before" + fi + GOWORK=off wails3 generate bindings -d "$BINDINGS_DIR" -clean=true -ts + if [ -d "$TMPDIR/bindings-before" ]; then + if ! diff -r "$BINDINGS_DIR" "$TMPDIR/bindings-before" >/dev/null 2>&1; then + echo "Wails bindings are stale. Run 'task check:bindings' and commit the result." + exit 1 + fi + fi + + check:ui-install: + cmds: + - pnpm install --frozen-lockfile + + check:ui-build: + cmds: + - task: packages + - pnpm build + + check:ui-lint: + cmds: + - pnpm lint + + check:ui-typecheck: + cmds: + - pnpm exec tsc -p tsconfig.app.json --noEmit + + # ────────────────────────────────────────────── + # Workspace packages + # ────────────────────────────────────────────── + + packages: + summary: Build all workspace packages in dependency order + cmds: + - pnpm --filter @omniviewdev/providers run build + - pnpm --filter @omniviewdev/vite-plugin run build + - pnpm --filter @omniviewdev/ui run build + - pnpm --filter @omniviewdev/runtime run build + + # ────────────────────────────────────────────── + # E2E tests + # ────────────────────────────────────────────── + + e2e: + dir: e2e + cmds: + - pnpm install + - pnpm exec playwright install chromium + - pnpm exec playwright test + + e2e-ui: + dir: e2e + cmds: + - pnpm exec playwright test --ui + + e2e-report: + dir: e2e + cmds: + - pnpm exec playwright show-report diff --git a/app.go b/app.go index ad68d14b..d5e3dcf7 100644 --- a/app.go +++ b/app.go @@ -5,28 +5,30 @@ import ( "os" "runtime" - wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" ) -// Shutdownable is an interface that can be implemented by any struct that needs to -// perform an action at application termination. -type Shutdownable interface { - // Shutdown is called at application termination. - Shutdown(ctx context.Context) +// AppService is the main application service for Wails v3. +// It is registered as a Wails service and exposes methods to the frontend. +type AppService struct{} + +// NewAppService creates a new AppService. +func NewAppService() *AppService { + return &AppService{} } -// App struct. -type App struct { - ctx context.Context +// ServiceStartup is called during application startup. +func (a *AppService) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + return nil } -// NewApp creates a new App application struct. -func NewApp() *App { - return &App{} +// ServiceShutdown is called during application shutdown. +func (a *AppService) ServiceShutdown() error { + return nil } // GetOperatingSystem returns the operating system type this application is running on. -func (a *App) GetOperatingSystem() string { +func (a *AppService) GetOperatingSystem() string { switch runtime.GOOS { case "darwin": return "macos" @@ -37,12 +39,7 @@ func (a *App) GetOperatingSystem() string { } } -// FileFilter defines a filter for dialog boxes -type FileFilter struct { - DisplayName string `json:"displayName"` // Filter information EG: "Image Files (*.jpg, *.png)" - Pattern string `json:"pattern"` // semicolon separated list of extensions, EG: "*.jpg;*.png" -} - +// FileDialogOptions defines options for file dialogs exposed to the frontend. type FileDialogOptions struct { DefaultDirectory string `json:"defaultDirectory"` DefaultFilename string `json:"defaultFilename"` @@ -54,67 +51,62 @@ type FileDialogOptions struct { TreatPackagesAsDirectories bool `json:"treatPackagesAsDirectories"` } -func (a *App) OpenFileSelectionDialog(opts FileDialogOptions) ([]string, error) { - wailsopts := wailsruntime.OpenDialogOptions{ - DefaultDirectory: opts.DefaultDirectory, - DefaultFilename: opts.DefaultFilename, - Title: opts.Title, - ShowHiddenFiles: opts.ShowHiddenFiles, - CanCreateDirectories: opts.CanCreateDirectories, - ResolvesAliases: opts.ResolvesAliases, - TreatPackagesAsDirectories: opts.TreatPackagesAsDirectories, - } - filters := make([]wailsruntime.FileFilter, len(opts.Filters)) - for i, filter := range opts.Filters { - filters[i] = wailsruntime.FileFilter{ - DisplayName: filter.DisplayName, - Pattern: filter.Pattern, - } - } - wailsopts.Filters = filters - return wailsruntime.OpenMultipleFilesDialog(a.ctx, wailsopts) +// FileFilter defines a filter for dialog boxes. +type FileFilter struct { + DisplayName string `json:"displayName"` // Filter information EG: "Image Files (*.jpg, *.png)" + Pattern string `json:"pattern"` // semicolon separated list of extensions, EG: "*.jpg;*.png" } -// SaveFileDialog opens a native save file dialog and returns the selected path. -func (a *App) SaveFileDialog(opts FileDialogOptions) (string, error) { - wailsopts := wailsruntime.SaveDialogOptions{ - DefaultDirectory: opts.DefaultDirectory, - DefaultFilename: opts.DefaultFilename, - Title: opts.Title, - ShowHiddenFiles: opts.ShowHiddenFiles, - CanCreateDirectories: opts.CanCreateDirectories, - TreatPackagesAsDirectories: opts.TreatPackagesAsDirectories, +// OpenFileSelectionDialog opens a native file selection dialog using the v3 Dialog API. +func (a *AppService) OpenFileSelectionDialog(opts FileDialogOptions) ([]string, error) { + app := application.Get() + dialog := app.Dialog.OpenFile() + + if opts.Title != "" { + dialog.SetTitle(opts.Title) } - filters := make([]wailsruntime.FileFilter, len(opts.Filters)) - for i, filter := range opts.Filters { - filters[i] = wailsruntime.FileFilter{ - DisplayName: filter.DisplayName, - Pattern: filter.Pattern, - } + if opts.DefaultDirectory != "" { + dialog.SetDirectory(opts.DefaultDirectory) } - wailsopts.Filters = filters - return wailsruntime.SaveFileDialog(a.ctx, wailsopts) -} + dialog.CanChooseFiles(true) + dialog.CanCreateDirectories(opts.CanCreateDirectories) + dialog.ShowHiddenFiles(opts.ShowHiddenFiles) + dialog.ResolvesAliases(opts.ResolvesAliases) + dialog.TreatsFilePackagesAsDirectories(opts.TreatPackagesAsDirectories) -// WriteFileContent writes string content to the given file path. -func (a *App) WriteFileContent(path string, content string) error { - return os.WriteFile(path, []byte(content), 0644) -} + for _, f := range opts.Filters { + dialog.AddFilter(f.DisplayName, f.Pattern) + } -// startup is called at application startup. -func (a *App) startup(ctx context.Context) { - // Perform your setup here - a.ctx = ctx + return dialog.PromptForMultipleSelection() } -// domReady is called after front-end resources have been loaded. -func (a App) domReady(_ context.Context) { - // Add your action here +// SaveFileDialog opens a native save file dialog using the v3 Dialog API. +func (a *AppService) SaveFileDialog(opts FileDialogOptions) (string, error) { + app := application.Get() + dialog := app.Dialog.SaveFile() + + if opts.Title != "" { + dialog.SetMessage(opts.Title) + } + if opts.DefaultDirectory != "" { + dialog.SetDirectory(opts.DefaultDirectory) + } + if opts.DefaultFilename != "" { + dialog.SetFilename(opts.DefaultFilename) + } + dialog.CanCreateDirectories(opts.CanCreateDirectories) + dialog.ShowHiddenFiles(opts.ShowHiddenFiles) + dialog.TreatsFilePackagesAsDirectories(opts.TreatPackagesAsDirectories) + + for _, f := range opts.Filters { + dialog.AddFilter(f.DisplayName, f.Pattern) + } + + return dialog.PromptForSingleSelection() } -// beforeClose is called when the application is about to quit, -// either by clicking the window close button or calling runtime.Quit. -// Returning true will cause the application to continue, false will continue shutdown as normal. -func (a *App) beforeClose(_ context.Context) (prevent bool) { - return false +// WriteFileContent writes string content to the given file path. +func (a *AppService) WriteFileContent(path string, content string) error { + return os.WriteFile(path, []byte(content), 0644) } diff --git a/backend/diagnostics/logger.go b/backend/diagnostics/logger.go index 0997e7a6..2f713a1e 100644 --- a/backend/diagnostics/logger.go +++ b/backend/diagnostics/logger.go @@ -12,7 +12,7 @@ import ( "sync" "github.com/nxadm/tail" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" @@ -24,11 +24,21 @@ const ( type BackendLogger struct { Sugared *zap.SugaredLogger + app *application.App logDir string watchers map[string]*tail.Tail watchLock sync.Mutex } +func (b *BackendLogger) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + b.app = application.Get() + return nil +} + +func (b *BackendLogger) ServiceShutdown() error { + return nil +} + // NewBackendLogger creates (and binds) a Zap SugaredLogger writing to `.log`. func NewBackendLogger(name string, dev bool) (*BackendLogger, error) { // determine level @@ -214,7 +224,9 @@ func (b *BackendLogger) StartTail(ctx context.Context, name string) error { go func() { for line := range t.Lines { - runtime.EventsEmit(ctx, fmt.Sprintf(LOG_UPDATE_FMT, name), line.Text) + if b.app != nil { + b.app.Event.Emit(fmt.Sprintf(LOG_UPDATE_FMT, name), line.Text) + } } }() return nil diff --git a/backend/menus/app_v3.go b/backend/menus/app_v3.go new file mode 100644 index 00000000..bf2bd67d --- /dev/null +++ b/backend/menus/app_v3.go @@ -0,0 +1,85 @@ +package menus + +import ( + "runtime" + + "github.com/wailsapp/wails/v3/pkg/application" +) + +// Menu event constants. +const ( + EventTerminalCreate = "menu/view/terminal/create" + EventBottomDrawerMinimize = "menu/view/bottomdrawer/minimize" + EventBottomDrawerFullscreen = "menu/view/bottomdrawer/fullscreen" + EventSidebarMinimize = "menu/view/sidebar/minimize" + EventContextTabClose = "menu/context/drawer-tab/close" + EventContextTabCloseOthers = "menu/context/drawer-tab/close-others" +) + +func init() { + application.RegisterEvent[application.Void](EventTerminalCreate) + application.RegisterEvent[application.Void](EventBottomDrawerMinimize) + application.RegisterEvent[application.Void](EventBottomDrawerFullscreen) + application.RegisterEvent[application.Void](EventSidebarMinimize) + application.RegisterEvent[string](EventContextTabClose) + application.RegisterEvent[string](EventContextTabCloseOthers) +} + +// SetupAppMenu creates and sets the application menu for Wails v3. +// It mirrors the v2 menu structure from GetMenus/CreateViewMenu but uses +// the v3 menu builder API. +func SetupAppMenu(app *application.App, window *application.WebviewWindow) { + menu := app.NewMenu() + + // macOS-specific role menus + if runtime.GOOS == "darwin" { + menu.AddRole(application.AppMenu) + menu.AddRole(application.EditMenu) + menu.AddRole(application.WindowMenu) + } + + // View submenu — custom items matching the v2 View menu + viewMenu := menu.AddSubmenu("View") + + viewMenu.Add("Reload"). + SetAccelerator("CmdOrCtrl+R"). + OnClick(func(ctx *application.Context) { + window.Reload() + }) + + viewMenu.Add("Force Reload"). + SetAccelerator("CmdOrCtrl+Shift+F"). + OnClick(func(ctx *application.Context) { + window.ForceReload() + }) + + viewMenu.AddSeparator() + + viewMenu.Add("New Terminal Session"). + SetAccelerator("CmdOrCtrl+Shift+T"). + OnClick(func(ctx *application.Context) { + app.Event.Emit(EventTerminalCreate) + }) + + viewMenu.Add("Minimize Bottom Menu"). + SetAccelerator("CmdOrCtrl+Shift+B"). + OnClick(func(ctx *application.Context) { + app.Event.Emit(EventBottomDrawerMinimize) + }) + + viewMenu.Add("Maximize Bottom Menu"). + SetAccelerator("CmdOrCtrl+Alt+B"). + OnClick(func(ctx *application.Context) { + app.Event.Emit(EventBottomDrawerFullscreen) + }) + + viewMenu.AddSeparator() + + viewMenu.Add("Close Sidebar"). + SetAccelerator("CmdOrCtrl+Shift+S"). + OnClick(func(ctx *application.Context) { + app.Event.Emit(EventSidebarMinimize) + }) + + app.Menu.Set(menu) +} diff --git a/backend/menus/context_v3.go b/backend/menus/context_v3.go new file mode 100644 index 00000000..a2bff647 --- /dev/null +++ b/backend/menus/context_v3.go @@ -0,0 +1,32 @@ +package menus + +import ( + "github.com/wailsapp/wails/v3/pkg/application" +) + +// SetupContextMenus registers all application context menus. +// Context menus are attached to HTML elements via the CSS property +// --custom-contextmenu, e.g.: +// +//
+func SetupContextMenus(app *application.App) { + setupDrawerTabContextMenu(app) +} + +// setupDrawerTabContextMenu creates the right-click menu for drawer tabs +// (bottom panel tabs such as terminal sessions). +func setupDrawerTabContextMenu(app *application.App) { + ctxMenu := app.ContextMenu.New() + + ctxMenu.Add("Close Tab").OnClick(func(ctx *application.Context) { + tabID := ctx.ContextMenuData() + app.Event.Emit(EventContextTabClose, tabID) + }) + + ctxMenu.Add("Close Other Tabs").OnClick(func(ctx *application.Context) { + tabID := ctx.ContextMenuData() + app.Event.Emit(EventContextTabCloseOthers, tabID) + }) + + app.ContextMenu.Add("drawer-tab", ctxMenu) +} diff --git a/backend/menus/keybindings_v3.go b/backend/menus/keybindings_v3.go new file mode 100644 index 00000000..8e231635 --- /dev/null +++ b/backend/menus/keybindings_v3.go @@ -0,0 +1,16 @@ +package menus + +import ( + "github.com/wailsapp/wails/v3/pkg/application" +) + +// SetupKeyBindings registers standalone keyboard shortcuts that are decoupled +// from menu items. In v3, keybindings can exist independently of the menu bar. +func SetupKeyBindings(app *application.App) { + // Terminal creation shortcut — also in the View menu, but registered as a + // standalone keybinding so it fires even if the menu is not visible + // (e.g. on Windows/Linux when the window has no menu bar). + app.KeyBinding.Add("CmdOrCtrl+Shift+T", func(window application.Window) { + window.EmitEvent("menu/view/terminal/create") + }) +} diff --git a/backend/menus/menus.go b/backend/menus/menus.go deleted file mode 100644 index 376e4eea..00000000 --- a/backend/menus/menus.go +++ /dev/null @@ -1,27 +0,0 @@ -package menus - -import ( - "context" - "runtime" - - "github.com/wailsapp/wails/v2/pkg/menu" -) - -// GetMenus get's the upper menus for the application -func GetMenus(ctx context.Context) *menu.Menu { - AppMenu := menu.NewMenu() - if runtime.GOOS == "darwin" { - AppMenu.Append(menu.AppMenu()) - - // Edit - AppMenu.Append(menu.EditMenu()) - - // WindowMenu - AppMenu.Append(menu.WindowMenu()) - } - - // View - CreateViewMenu(ctx, AppMenu) - - return AppMenu -} diff --git a/backend/menus/view.go b/backend/menus/view.go deleted file mode 100644 index 585c4e4b..00000000 --- a/backend/menus/view.go +++ /dev/null @@ -1,66 +0,0 @@ -package menus - -import ( - "context" - - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/menu/keys" - wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime" -) - -// CreateViewMenu appends the View menu -func CreateViewMenu(ctx context.Context, appMenu *menu.Menu) { - ViewMenu := appMenu.AddSubmenu("View") - ViewMenu.AddText( - "Reload", - keys.CmdOrCtrl("r"), - func(_ *menu.CallbackData) { - wailsruntime.WindowReload(ctx) - }, - ) - ViewMenu.AddText( - "Force Reload", - keys.Combo("f", keys.CmdOrCtrlKey, keys.ShiftKey), - func(_ *menu.CallbackData) { - wailsruntime.WindowReloadApp(ctx) - }, - ) - - //=========================================================== - // Bottom Menu actions - //=========================================================== - ViewMenu.AddSeparator() - ViewMenu.AddText( - "New Terminal Session", - keys.Combo("t", keys.CmdOrCtrlKey, keys.ShiftKey), - func(_ *menu.CallbackData) { - wailsruntime.EventsEmit(ctx, "menu/view/terminal/create") - }, - ) - ViewMenu.AddText( - "Minimize Bottom Menu", - keys.Combo("b", keys.CmdOrCtrlKey, keys.ShiftKey), - func(_ *menu.CallbackData) { - wailsruntime.EventsEmit(ctx, "menu/view/bottomdrawer/minimize") - }, - ) - ViewMenu.AddText( - "Maximize Bottom Menu", - keys.Combo("b", keys.CmdOrCtrlKey, keys.OptionOrAltKey), - func(_ *menu.CallbackData) { - wailsruntime.EventsEmit(ctx, "menu/view/bottomdrawer/fullscreen") - }, - ) - - //=========================================================== - // Sidebar Menu actions - //=========================================================== - ViewMenu.AddSeparator() - ViewMenu.AddText( - "Close Sidebar", - keys.Combo("s", keys.CmdOrCtrlKey, keys.ShiftKey), - func(_ *menu.CallbackData) { - wailsruntime.EventsEmit(ctx, "menu/view/sidebar/minimize") - }, - ) -} diff --git a/backend/pkg/plugin/data/client.go b/backend/pkg/plugin/data/client.go deleted file mode 100644 index 3fad4c33..00000000 --- a/backend/pkg/plugin/data/client.go +++ /dev/null @@ -1,29 +0,0 @@ -package data - -// Client is the Wails-facing client for the plugin data store. -type Client struct { - controller Controller -} - -// NewClient creates a new data store client. -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -func (c *Client) Get(pluginID, key string) (any, error) { - return c.controller.Get(pluginID, key) -} - -func (c *Client) Set(pluginID, key string, value any) error { - return c.controller.Set(pluginID, key, value) -} - -func (c *Client) Delete(pluginID, key string) error { - return c.controller.Delete(pluginID, key) -} - -func (c *Client) Keys(pluginID string) ([]string, error) { - return c.controller.Keys(pluginID) -} diff --git a/backend/pkg/plugin/data/controller.go b/backend/pkg/plugin/data/controller.go index 71fd446a..839bd746 100644 --- a/backend/pkg/plugin/data/controller.go +++ b/backend/pkg/plugin/data/controller.go @@ -9,12 +9,15 @@ import ( "path/filepath" "strings" + "github.com/wailsapp/wails/v3/pkg/application" logging "github.com/omniviewdev/plugin-sdk/log" ) // Controller provides a JSON key-value store for plugins to persist arbitrary data. // Each key is stored as a separate JSON file under ~/.omniview/plugins/{pluginID}/data/. type Controller interface { + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + ServiceShutdown() error Get(pluginID, key string) (any, error) Set(pluginID, key string, value any) error Delete(pluginID, key string) error @@ -34,6 +37,14 @@ func NewController(logger logging.Logger) Controller { } } +func (c *controller) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + return nil +} + +func (c *controller) ServiceShutdown() error { + return nil +} + // dataDir returns the data directory for a plugin, creating it if necessary. func (c *controller) dataDir(pluginID string) (string, error) { homeDir, err := os.UserHomeDir() diff --git a/backend/pkg/plugin/devserver/manager.go b/backend/pkg/plugin/devserver/manager.go index b61dd44e..88791717 100644 --- a/backend/pkg/plugin/devserver/manager.go +++ b/backend/pkg/plugin/devserver/manager.go @@ -5,7 +5,7 @@ import ( "fmt" "sync" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" logging "github.com/omniviewdev/plugin-sdk/log" "github.com/omniviewdev/omniview/backend/pkg/apperror" @@ -26,6 +26,7 @@ type PluginReloader interface { // DevServerManager manages dev server instances for plugins in development mode. // It is exposed as a Wails binding. All public methods are callable from the frontend. type DevServerManager struct { + app *application.App ctx context.Context logger logging.Logger mu sync.RWMutex @@ -55,9 +56,10 @@ func NewDevServerManager( } } -// Initialize is called during Wails startup (OnStartup callback). It stores the -// Wails context needed for runtime.EventsEmit, and starts the external plugin watcher. -func (m *DevServerManager) Initialize(ctx context.Context) { +// ServiceStartup is called during Wails v3 service startup. It stores the +// application reference and starts the external plugin watcher. +func (m *DevServerManager) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + m.app = application.Get() m.ctx = ctx // Kill any stale Vite dev server processes left over from a previous @@ -82,11 +84,11 @@ func (m *DevServerManager) Initialize(ctx context.Context) { } m.logger.Infow(ctx, "DevServerManager initialized") + return nil } -// Shutdown stops all running dev server instances and the external watcher. -// Called from Wails OnShutdown. -func (m *DevServerManager) Shutdown() { +// ServiceShutdown stops all running dev server instances and the external watcher. +func (m *DevServerManager) ServiceShutdown() error { m.logger.Infow(context.Background(), "DevServerManager shutting down") // Stop the external watcher first. @@ -115,6 +117,7 @@ func (m *DevServerManager) Shutdown() { m.ports.SavePIDs() m.logger.Infow(context.Background(), "DevServerManager shutdown complete") + return nil } // ============================================================================ @@ -424,22 +427,22 @@ func (m *DevServerManager) resolveBuildOpts() BuildOpts { } func (m *DevServerManager) emitStatus(pluginID string, state DevServerState) { - if m.ctx == nil { + if m.app == nil { return } - runtime.EventsEmit(m.ctx, EventDevServerStatus, state) + m.app.Event.Emit(EventDevServerStatus, state) } func (m *DevServerManager) emitLogs(pluginID string, entries []LogEntry) { - if m.ctx == nil || len(entries) == 0 { + if m.app == nil || len(entries) == 0 { return } - runtime.EventsEmit(m.ctx, EventDevServerLog, entries) + m.app.Event.Emit(EventDevServerLog, entries) } func (m *DevServerManager) emitErrors(pluginID string, errors []BuildError) { - if m.ctx == nil || len(errors) == 0 { + if m.app == nil || len(errors) == 0 { return } - runtime.EventsEmit(m.ctx, EventDevServerError, pluginID, errors) + m.app.Event.Emit(EventDevServerError, DevServerErrorPayload{PluginID: pluginID, Errors: errors}) } diff --git a/backend/pkg/plugin/devserver/manager_test.go b/backend/pkg/plugin/devserver/manager_test.go index 8747c013..7877497d 100644 --- a/backend/pkg/plugin/devserver/manager_test.go +++ b/backend/pkg/plugin/devserver/manager_test.go @@ -257,10 +257,10 @@ func TestManager_GetDevServerLogs_WithInstance(t *testing.T) { assert.Equal(t, "build complete", logs[0].Message) } -func TestManager_Shutdown_NoInstances(t *testing.T) { +func TestManager_ServiceShutdown_NoInstances(t *testing.T) { mgr := newTestManager(t) // Should not panic when there are no instances or watcher. - mgr.Shutdown() + _ = mgr.ServiceShutdown() } func TestManager_HandleExternalConnect(t *testing.T) { @@ -358,7 +358,7 @@ func TestManager_StartDevServer_EmptyDevPath(t *testing.T) { assert.Contains(t, appErr.Title, "Missing dev path") } -func TestManager_Shutdown_WithInstances(t *testing.T) { +func TestManager_ServiceShutdown_WithInstances(t *testing.T) { mgr := newTestManager(t) // Create instances with no-op callbacks. These have nil vite/goWatcher @@ -384,7 +384,7 @@ func TestManager_Shutdown_WithInstances(t *testing.T) { mgr.mu.Unlock() // Shutdown should stop all instances and not panic. - mgr.Shutdown() + _ = mgr.ServiceShutdown() // After shutdown, instances should be removed. mgr.mu.RLock() @@ -392,7 +392,7 @@ func TestManager_Shutdown_WithInstances(t *testing.T) { mgr.mu.RUnlock() } -func TestManager_Shutdown_WithExternalWatcher(t *testing.T) { +func TestManager_ServiceShutdown_WithExternalWatcher(t *testing.T) { mgr := newTestManager(t) // Set up a minimal external watcher with a real fsnotify watcher @@ -410,7 +410,7 @@ func TestManager_Shutdown_WithExternalWatcher(t *testing.T) { } // Shutdown should call Stop on the external watcher, disconnecting all. - mgr.Shutdown() + _ = mgr.ServiceShutdown() assert.False(t, ew.IsExternallyManaged("ext-plug")) } diff --git a/backend/pkg/plugin/devserver/types.go b/backend/pkg/plugin/devserver/types.go index 2bedb6e1..98ff7345 100644 --- a/backend/pkg/plugin/devserver/types.go +++ b/backend/pkg/plugin/devserver/types.go @@ -2,8 +2,16 @@ package devserver import ( "time" + + "github.com/wailsapp/wails/v3/pkg/application" ) +func init() { + application.RegisterEvent[DevServerState](EventDevServerStatus) + application.RegisterEvent[[]LogEntry](EventDevServerLog) + application.RegisterEvent[DevServerErrorPayload](EventDevServerError) +} + // ============================================================================ // Event constants // ============================================================================ @@ -83,6 +91,13 @@ type LogEntry struct { PluginID string `json:"pluginID"` } +// DevServerErrorPayload wraps a plugin ID and its build errors into a single +// event payload so it can be registered with RegisterEvent[T]. +type DevServerErrorPayload struct { + PluginID string `json:"pluginID"` + Errors []BuildError `json:"errors"` +} + // BuildError is a structured build error parsed from Go compiler output. type BuildError struct { File string `json:"file"` diff --git a/backend/pkg/plugin/events.go b/backend/pkg/plugin/events.go index d0493d90..e5624546 100644 --- a/backend/pkg/plugin/events.go +++ b/backend/pkg/plugin/events.go @@ -1,14 +1,37 @@ package plugin import ( - "context" "time" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle" + "github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog" + "github.com/omniviewdev/omniview/backend/pkg/plugin/resource" ) +func init() { + application.RegisterEvent[StateChangePayload](EventStateChange) + application.RegisterEvent[application.Void](EventInstallStarted) + application.RegisterEvent[application.Void](EventInstallFinished) + application.RegisterEvent[application.Void](EventInstallError) + application.RegisterEvent[application.Void](EventDevInstallStart) + application.RegisterEvent[application.Void](EventDevInstallError) + application.RegisterEvent[application.Void](EventDevInstallComplete) + application.RegisterEvent[application.Void](EventReloadStart) + application.RegisterEvent[application.Void](EventReloadError) + application.RegisterEvent[application.Void](EventReloadComplete) + application.RegisterEvent[UpdatePayload](EventUpdateStarted) + application.RegisterEvent[UpdateErrorPayload](EventUpdateError) + application.RegisterEvent[UpdatePayload](EventUpdateComplete) + application.RegisterEvent[application.Void](EventInitComplete) + application.RegisterEvent[application.Void](EventCrashRecoveryFailed) + application.RegisterEvent[application.Void](EventRecovered) + application.RegisterEvent[application.Void](EventStateWriteError) + application.RegisterEvent[DeprecatedProtocolPayload](EventDeprecatedProtocol) + application.RegisterEvent[pluginlog.LogEntry](EventProcessLog) +} + // Plugin event constants. const ( // Lifecycle state changes. @@ -46,6 +69,9 @@ const ( // Protocol version. EventDeprecatedProtocol = "plugin/deprecated_protocol" + + // Process logging. + EventProcessLog = "plugin/process/log" ) // StateChangePayload is sent with EventStateChange. @@ -57,6 +83,18 @@ type StateChangePayload struct { Timestamp time.Time `json:"timestamp"` } +// UpdatePayload is sent with EventUpdateStarted and EventUpdateComplete. +type UpdatePayload struct { + PluginID string `json:"pluginID"` + Version string `json:"version"` +} + +// UpdateErrorPayload is sent with EventUpdateError. +type UpdateErrorPayload struct { + PluginID string `json:"pluginID"` + Error string `json:"error"` +} + // DeprecatedProtocolPayload is sent with EventDeprecatedProtocol. type DeprecatedProtocolPayload struct { PluginID string `json:"pluginID"` @@ -64,22 +102,12 @@ type DeprecatedProtocolPayload struct { CurrentVersion int `json:"currentVersion"` } -// eventEmitFn is the function used to emit events. It defaults to -// wails/v2/pkg/runtime.EventsEmit but can be replaced in tests to avoid -// the log.Fatal that Wails issues for non-Wails contexts. -var eventEmitFn = runtime.EventsEmit - -// emitEvent is a convenience wrapper around Wails event emission. -func emitEvent(ctx context.Context, event string, data ...interface{}) { - if ctx == nil { +// emitStateChange emits a state change event to the frontend. +func emitStateChange(emitter resource.EventEmitter, pluginID string, t lifecycle.Transition) { + if emitter == nil { return } - eventEmitFn(ctx, event, data...) -} - -// emitStateChange emits a state change event to the frontend. -func emitStateChange(ctx context.Context, pluginID string, t lifecycle.Transition) { - emitEvent(ctx, EventStateChange, StateChangePayload{ + emitter.Emit(EventStateChange, StateChangePayload{ PluginID: pluginID, From: t.From, To: t.To, diff --git a/backend/pkg/plugin/events_test.go b/backend/pkg/plugin/events_test.go index afbbf537..b003981c 100644 --- a/backend/pkg/plugin/events_test.go +++ b/backend/pkg/plugin/events_test.go @@ -9,15 +9,7 @@ import ( "github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle" ) -func TestEmitEvent_NilContext_NoPanic(t *testing.T) { - assert.NotPanics(t, func() { - emitEvent(nil, "plugin/test", map[string]interface{}{ - "key": "value", - }) - }) -} - -func TestEmitStateChange_NilContext_NoPanic(t *testing.T) { +func TestEmitStateChange_NilEmitter_NoPanic(t *testing.T) { assert.NotPanics(t, func() { emitStateChange(nil, "test-plugin", lifecycle.Transition{ From: lifecycle.PhaseStarting, diff --git a/backend/pkg/plugin/exec/client.go b/backend/pkg/plugin/exec/client.go deleted file mode 100644 index be850a39..00000000 --- a/backend/pkg/plugin/exec/client.go +++ /dev/null @@ -1,93 +0,0 @@ -package exec - -import ( - sdkexec "github.com/omniviewdev/plugin-sdk/pkg/v1/exec" -) - -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -func (c *Client) GetPluginHandlers(plugin string) map[string]sdkexec.Handler { - return c.controller.GetPluginHandlers(plugin) -} - -func (c *Client) GetHandlers() map[string]map[string]sdkexec.Handler { - return c.controller.GetHandlers() -} - -func (c *Client) GetHandler(plugin, resource string) *sdkexec.Handler { - return c.controller.GetHandler(plugin, resource) -} - -func (c *Client) ListPlugins() ([]string, error) { - return c.controller.ListPlugins() -} - -func (c *Client) GetSession(sessionID string) (*sdkexec.Session, error) { - return c.controller.GetSession(sessionID) -} - -func (c *Client) ListSessions() ([]*sdkexec.Session, error) { - return c.controller.ListSessions() -} - -type AttachSessionResult struct { - Session *sdkexec.Session `json:"session"` - Buffer string `json:"buffer"` -} - -func (c *Client) AttachSession(sessionID string) (AttachSessionResult, error) { - session, buffer, err := c.controller.AttachSession(sessionID) - if err != nil { - return AttachSessionResult{}, err - } - return AttachSessionResult{ - Session: session, - Buffer: string(buffer), - }, nil -} - -func (c *Client) DetachSession(sessionID string) (*sdkexec.Session, error) { - return c.controller.DetachSession(sessionID) -} - -func (c *Client) CreateSession( - plugin, connection string, - opts sdkexec.SessionOptions, -) (*sdkexec.Session, error) { - return c.controller.CreateSession(plugin, connection, opts) -} - -type CreateTerminalOptions struct { - Labels map[string]string `json:"labels"` - Command []string `json:"command"` -} - -func (c *Client) CreateTerminal(opts CreateTerminalOptions) (*sdkexec.Session, error) { - sessionopts := sdkexec.SessionOptions{ - Command: opts.Command, - TTY: true, - Labels: opts.Labels, - } - - return c.controller.CreateSession("local", "local", sessionopts) -} - -func (c *Client) CloseSession(sessionID string) error { - return c.controller.CloseSession(sessionID) -} - -func (c *Client) WriteSession(sessionID string, input string) error { - return c.controller.WriteSession(sessionID, []byte(input)) -} - -func (c *Client) ResizeSession(sessionID string, rows, cols uint16) error { - return c.controller.ResizeSession(sessionID, rows, cols) -} diff --git a/backend/pkg/plugin/exec/controller.go b/backend/pkg/plugin/exec/controller.go index 30b3ddac..6628111f 100644 --- a/backend/pkg/plugin/exec/controller.go +++ b/backend/pkg/plugin/exec/controller.go @@ -5,7 +5,7 @@ import ( "fmt" "sync" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -26,11 +26,13 @@ var tracer = otel.Tracer("omniview.exec") type Controller interface { internaltypes.Controller - Run(ctx context.Context) + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + ServiceShutdown() error GetPluginHandlers(plugin string) map[string]exec.Handler GetHandlers() map[string]map[string]exec.Handler GetHandler(plugin, resource string) *exec.Handler CreateSession(plugin, connectionID string, opts exec.SessionOptions) (*exec.Session, error) + CreateTerminal(opts exec.SessionOptions) (*exec.Session, error) ListSessions() ([]*exec.Session, error) GetSession(sessionID string) (*exec.Session, error) AttachSession(sessionID string) (*exec.Session, []byte, error) @@ -69,7 +71,8 @@ func NewController( var _ Controller = &controller{} type controller struct { - // wails context + // wails v3 application reference + app *application.App ctx context.Context logger logging.Logger settingsProvider pkgsettings.Provider @@ -89,10 +92,16 @@ type controller struct { terminalManager *terminal.Manager } -func (c *controller) Run(ctx context.Context) { +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() c.ctx = ctx go c.runMux() // plugin mux go c.runLocalMux() // local terminal should be muxed separately to avoid latency + return nil +} + +func (c *controller) ServiceShutdown() error { + return nil } // safeSend sends to ch, recovering from a closed-channel panic that can occur @@ -136,8 +145,8 @@ func (c *controller) runLocalMux() { } case output := <-outMux: // dispatch to ui - if c.ctx == nil { - c.logger.Errorw(context.Background(), "context is nil, cannot dispatch output") + if c.app == nil { + c.logger.Errorw(context.Background(), "app is nil, cannot dispatch output") } var eventkey string @@ -148,9 +157,9 @@ func (c *controller) runLocalMux() { case exec.StreamSignalError: eventkey = "core/exec/signal/" + output.Signal.String() + "/" + output.SessionID if output.Error != nil { - runtime.EventsEmit(c.ctx, eventkey, output.Error) + c.app.Event.Emit(eventkey, output.Error) } else { - runtime.EventsEmit(c.ctx, eventkey, map[string]interface{}{ + c.app.Event.Emit(eventkey, map[string]interface{}{ "title": "Session error", "message": string(output.Data), "suggestion": "The session encountered an error.", @@ -170,7 +179,7 @@ func (c *controller) runLocalMux() { eventkey = "core/exec/signal/" + output.Signal.String() + "/" + output.SessionID } - runtime.EventsEmit(c.ctx, eventkey, output.Data) + c.app.Event.Emit(eventkey, output.Data) case resize := <-resizeMux: if err := manager.ResizeSession(resize.SessionID, resize.Rows, resize.Cols); err != nil { c.logger.Errorw(context.Background(), "error resizing session", "error", err) @@ -199,8 +208,8 @@ func (c *controller) runMux() { } case output := <-c.outputMux: // dispatch to ui - if c.ctx == nil { - c.logger.Errorw(context.Background(), "context is nil, cannot dispatch output") + if c.app == nil { + c.logger.Errorw(context.Background(), "app is nil, cannot dispatch output") } var eventkey string @@ -211,9 +220,9 @@ func (c *controller) runMux() { case exec.StreamSignalError: eventkey = "core/exec/signal/" + output.Signal.String() + "/" + output.SessionID if output.Error != nil { - runtime.EventsEmit(c.ctx, eventkey, output.Error) + c.app.Event.Emit(eventkey, output.Error) } else { - runtime.EventsEmit(c.ctx, eventkey, map[string]interface{}{ + c.app.Event.Emit(eventkey, map[string]interface{}{ "title": "Session error", "message": string(output.Data), "suggestion": "The session encountered an error.", @@ -233,7 +242,7 @@ func (c *controller) runMux() { eventkey = "core/exec/signal/" + output.Signal.String() + "/" + output.SessionID } - runtime.EventsEmit(c.ctx, eventkey, output.Data) + c.app.Event.Emit(eventkey, output.Data) } } } @@ -495,6 +504,14 @@ func (c *controller) GetHandler( return &h } +// CreateTerminal creates a local terminal session with TTY enabled. +// This is a convenience wrapper for CreateSession("local", "local", opts) +// with TTY forced on. +func (c *controller) CreateTerminal(opts exec.SessionOptions) (*exec.Session, error) { + opts.TTY = true + return c.CreateSession("local", "local", opts) +} + func (c *controller) CreateSession( plugin string, connectionID string, diff --git a/backend/pkg/plugin/health.go b/backend/pkg/plugin/health.go index 89ea4604..0bbae90d 100644 --- a/backend/pkg/plugin/health.go +++ b/backend/pkg/plugin/health.go @@ -182,7 +182,7 @@ func (hc *HealthChecker) HandleCrashWithBackoff(pluginID string) { } } hc.mu.Unlock() - emitEvent(hc.pm.ctx, EventCrashRecoveryFailed, map[string]interface{}{ + hc.pm.emitter.Emit(EventCrashRecoveryFailed, map[string]interface{}{ "pluginID": pluginID, "error": "crash budget exhausted — too many crashes in a short time", }) @@ -248,7 +248,7 @@ func (hc *HealthChecker) HandleCrashWithBackoff(pluginID string) { } hc.mu.Unlock() - emitEvent(hc.pm.ctx, EventCrashRecoveryFailed, map[string]interface{}{ + hc.pm.emitter.Emit(EventCrashRecoveryFailed, map[string]interface{}{ "pluginID": pluginID, "error": "max crash recovery attempts reached", }) @@ -296,7 +296,7 @@ func (hc *HealthChecker) HandleCrashWithBackoff(pluginID string) { delete(hc.recoveryStates, pluginID) hc.mu.Unlock() - emitEvent(hc.pm.ctx, EventRecovered, map[string]interface{}{"pluginID": pluginID}) + hc.pm.emitter.Emit(EventRecovered, map[string]interface{}{"pluginID": pluginID}) return } } diff --git a/backend/pkg/plugin/health_test.go b/backend/pkg/plugin/health_test.go index 57a996ba..775c6f7c 100644 --- a/backend/pkg/plugin/health_test.go +++ b/backend/pkg/plugin/health_test.go @@ -12,10 +12,10 @@ import ( plugintypes "github.com/omniviewdev/omniview/backend/pkg/plugin/types" ) -func init() { - // Replace the Wails event emitter with a no-op for tests. - eventEmitFn = func(_ context.Context, _ string, _ ...interface{}) {} -} +// testNoopEmitter is a no-op EventEmitter for tests. +type testNoopEmitter struct{} + +func (testNoopEmitter) Emit(string, ...any) {} func newTestHealthChecker(t *testing.T) (*HealthChecker, *pluginManager) { t.Helper() @@ -23,6 +23,7 @@ func newTestHealthChecker(t *testing.T) (*HealthChecker, *pluginManager) { logger: testLogger(t), records: make(map[string]*plugintypes.PluginRecord), ctx: context.Background(), + emitter: testNoopEmitter{}, } hc := NewHealthChecker(testLogger(t), pm) return hc, pm @@ -353,6 +354,7 @@ func TestHandleCrashWithBackoff_NilContext(t *testing.T) { pm := &pluginManager{ logger: testLogger(t), records: make(map[string]*plugintypes.PluginRecord), + emitter: testNoopEmitter{}, // ctx intentionally nil } hc := NewHealthChecker(testLogger(t), pm) diff --git a/backend/pkg/plugin/installer.go b/backend/pkg/plugin/installer.go index 5c03811c..fb0baca7 100644 --- a/backend/pkg/plugin/installer.go +++ b/backend/pkg/plugin/installer.go @@ -12,7 +12,7 @@ import ( "runtime/debug" "sync" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "golang.org/x/sync/errgroup" "github.com/omniviewdev/omniview/backend/pkg/apperror" @@ -35,14 +35,17 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er "stack", string(debug.Stack()), ) if metadata != nil { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) } metadata = nil err = apperror.Internal(fmt.Errorf("panic: %v", r), "Install in dev mode failed") } }() - path, err := runtime.OpenDirectoryDialog(pm.ctx, runtime.OpenDialogOptions{}) + path, err := application.Get().Dialog.OpenFile(). + CanChooseDirectories(true). + CanChooseFiles(false). + PromptForSingleSelection() if err != nil { l.Errorw(pm.ctx, err.Error()) return nil, err @@ -59,7 +62,7 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er } l.Infow(pm.ctx, "parsed plugin metadata", "pluginID", metadata.ID) - emitEvent(pm.ctx, EventDevInstallStart, metadata) + pm.emitter.Emit(EventDevInstallStart, metadata) // Unload existing instance if it exists. pm.recordsMu.RLock() @@ -77,14 +80,14 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er ExcludeBackend: true, ExcludeUI: true, }); err != nil { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginInstallFailed, 500, "Failed to copy plugin metadata") } // Ensure the bin directory exists for the GoWatcher to transfer into. installLocation := getPluginLocation(metadata.ID) if err = os.MkdirAll(filepath.Join(installLocation, "bin"), 0755); err != nil { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginInstallFailed, 500, "Failed to create plugin bin directory") } @@ -93,7 +96,7 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er l.Infow(pm.ctx, "starting dev server (triggers initial build)", "pluginID", metadata.ID) state, startErr := pm.devServerMgr.StartDevServerForPath(metadata.ID, path) if startErr != nil { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) return nil, apperror.Wrap(startErr, apperror.TypePluginBuildFailed, 500, "Dev server failed to start"). WithActions(apperror.OpenSettingsAction("developer")) } @@ -113,14 +116,14 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er pm.records[metadata.ID] = record pm.recordsMu.Unlock() - emitEvent(pm.ctx, EventDevInstallComplete, metadata) + pm.emitter.Emit(EventDevInstallComplete, metadata) if err = pm.writePluginStateJSON(); err != nil { l.Warnw(pm.ctx, "failed to persist plugin state after build-failed stub", "pluginID", metadata.ID, "error", err) } return metadata, nil } } else { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) return nil, apperror.New(apperror.TypeSettingsMissingConfig, 422, "No dev server manager configured", "The dev server manager is not available. Ensure developer settings are configured."). WithActions(apperror.OpenSettingsAction("developer")) @@ -130,15 +133,15 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er l.Infow(pm.ctx, "loading plugin (starting binary + gRPC connect)", "pluginID", metadata.ID) _, err = pm.LoadPlugin(metadata.ID, &LoadPluginOptions{DevMode: true, DevModePath: path}) if err != nil { - emitEvent(pm.ctx, EventDevInstallError, metadata) + pm.emitter.Emit(EventDevInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginLoadFailed, 500, "Failed to load plugin") } - emitEvent(pm.ctx, EventDevInstallComplete, metadata) + pm.emitter.Emit(EventDevInstallComplete, metadata) if err = pm.writePluginStateJSON(); err != nil { l.Errorw(pm.ctx, "failed to persist plugin state after dev install", "pluginID", metadata.ID, "error", err) - emitEvent(pm.ctx, EventStateWriteError, map[string]interface{}{ + pm.emitter.Emit(EventStateWriteError, map[string]interface{}{ "pluginID": metadata.ID, "detail": err.Error(), }) @@ -149,7 +152,8 @@ func (pm *pluginManager) InstallInDevMode() (metadata *config.PluginMeta, err er // InstallFromPathPrompt installs a plugin from a file selected via dialog. func (pm *pluginManager) InstallFromPathPrompt() (*config.PluginMeta, error) { - path, err := runtime.OpenFileDialog(pm.ctx, runtime.OpenDialogOptions{}) + path, err := application.Get().Dialog.OpenFile(). + PromptForSingleSelection() if err != nil { return nil, err } @@ -165,20 +169,20 @@ func (pm *pluginManager) InstallPluginVersion( pluginID string, version string, ) (*config.PluginMeta, error) { - emitEvent(pm.ctx, EventUpdateStarted, pluginID, version) + pm.emitter.Emit(EventUpdateStarted, UpdatePayload{PluginID: pluginID, Version: version}) pm.syncRegistryURL() tmpPath, err := pm.registryClient.DownloadPlugin(context.Background(), pluginID, version) if err != nil { pm.logger.Errorw(pm.ctx, "failed to download and prepare", "error", err) - emitEvent(pm.ctx, EventUpdateError, pluginID, err.Error()) + pm.emitter.Emit(EventUpdateError, UpdateErrorPayload{PluginID: pluginID, Error: err.Error()}) return nil, err } pm.logger.Debugw(pm.ctx, "installing plugin from downloaded tmp path", "path", tmpPath) meta, err := pm.InstallPluginFromPath(tmpPath) if err != nil { - emitEvent(pm.ctx, EventUpdateError, pluginID, err.Error()) + pm.emitter.Emit(EventUpdateError, UpdateErrorPayload{PluginID: pluginID, Error: err.Error()}) return nil, err } @@ -195,7 +199,7 @@ func (pm *pluginManager) InstallPluginVersion( pm.logger.Errorw(pm.ctx, "failed to persist state after version override", "error", writeErr) } - emitEvent(pm.ctx, EventUpdateComplete, pluginID, version) + pm.emitter.Emit(EventUpdateComplete, UpdatePayload{PluginID: pluginID, Version: version}) return meta, nil } @@ -223,7 +227,7 @@ func (pm *pluginManager) InstallPluginFromPath(path string) (*config.PluginMeta, return nil, apperror.Wrap(err, apperror.TypePluginInstallFailed, 500, "Failed to parse plugin metadata") } - emitEvent(pm.ctx, EventInstallStarted, metadata) + pm.emitter.Emit(EventInstallStarted, metadata) location := getPluginLocation(metadata.ID) @@ -231,13 +235,13 @@ func (pm *pluginManager) InstallPluginFromPath(path string) (*config.PluginMeta, // installation if the archive is corrupt or extraction fails. tmpDir, mkErr := os.MkdirTemp(getPluginDir(), metadata.ID+"-install-") if mkErr != nil { - emitEvent(pm.ctx, EventInstallError, metadata) + pm.emitter.Emit(EventInstallError, metadata) return nil, apperror.Wrap(mkErr, apperror.TypePluginInstallFailed, 500, "Failed to create temp directory") } defer os.RemoveAll(tmpDir) // clean up temp dir in all cases if err = unpackPluginArchive(path, tmpDir); err != nil { - emitEvent(pm.ctx, EventInstallError, metadata) + pm.emitter.Emit(EventInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginInstallFailed, 500, "Failed to unpack plugin package") } @@ -246,25 +250,25 @@ func (pm *pluginManager) InstallPluginFromPath(path string) (*config.PluginMeta, os.RemoveAll(location) if err = os.Rename(tmpDir, location); err != nil { - emitEvent(pm.ctx, EventInstallError, metadata) + pm.emitter.Emit(EventInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginInstallFailed, 500, "Failed to install plugin files") } _, err = pm.LoadPlugin(metadata.ID, nil) if err != nil { - emitEvent(pm.ctx, EventInstallError, metadata) + pm.emitter.Emit(EventInstallError, metadata) return nil, apperror.Wrap(err, apperror.TypePluginLoadFailed, 500, "Failed to load plugin after install") } if err = pm.writePluginStateJSON(); err != nil { pm.logger.Errorw(pm.ctx, "failed to persist plugin state after install", "pluginID", metadata.ID, "error", err) - emitEvent(pm.ctx, EventStateWriteError, map[string]interface{}{ + pm.emitter.Emit(EventStateWriteError, map[string]interface{}{ "pluginID": metadata.ID, "detail": err.Error(), }) } - emitEvent(pm.ctx, EventInstallFinished, metadata) + pm.emitter.Emit(EventInstallFinished, metadata) return metadata, nil } diff --git a/backend/pkg/plugin/loader.go b/backend/pkg/plugin/loader.go index 9ad5d83b..f32d6d71 100644 --- a/backend/pkg/plugin/loader.go +++ b/backend/pkg/plugin/loader.go @@ -384,7 +384,7 @@ func (pm *pluginManager) startPlugin(record *plugintypes.PluginRecord, backend p pm.logger.Warnw(ctx, "plugin uses deprecated SDK protocol version", "pluginID", pluginID, "version", version, "current", plugintypes.CurrentProtocolVersion) - emitEvent(pm.ctx, EventDeprecatedProtocol, DeprecatedProtocolPayload{ + pm.emitter.Emit(EventDeprecatedProtocol, DeprecatedProtocolPayload{ PluginID: pluginID, Version: version, CurrentVersion: plugintypes.CurrentProtocolVersion, diff --git a/backend/pkg/plugin/loader_test.go b/backend/pkg/plugin/loader_test.go index 0dc7b77c..9c0bfe21 100644 --- a/backend/pkg/plugin/loader_test.go +++ b/backend/pkg/plugin/loader_test.go @@ -33,6 +33,7 @@ func newTestManager(t *testing.T) *pluginManager { managers: make(map[string]plugintypes.PluginManager), pidTracker: NewPluginPIDTracker(), pluginOpsLocks: make(map[string]*sync.Mutex), + emitter: testNoopEmitter{}, } } @@ -370,6 +371,7 @@ func TestDevPlugin_SurvivesRestart(t *testing.T) { managers: make(map[string]plugintypes.PluginManager), pidTracker: NewPluginPIDTracker(), pluginOpsLocks: make(map[string]*sync.Mutex), + emitter: testNoopEmitter{}, } // Use the same plugin dir as pm1. pm2.backendFactory = func(meta config.PluginMeta, location string) (plugintypes.PluginBackend, error) { @@ -633,27 +635,37 @@ func (b *mockBackend) Kill() {} func (b *mockBackend) Exited() bool { return false } func (b *mockBackend) NegotiatedVersion() int { return b.version } +// testRecordingEmitter captures emitted events for test assertions. +type testRecordingEmitter struct { + mu sync.Mutex + events []testEmittedEvent +} + +type testEmittedEvent struct { + event string + data []any +} + +func (e *testRecordingEmitter) Emit(event string, data ...any) { + e.mu.Lock() + e.events = append(e.events, testEmittedEvent{event: event, data: data}) + e.mu.Unlock() +} + +func (e *testRecordingEmitter) getEvents() []testEmittedEvent { + e.mu.Lock() + defer e.mu.Unlock() + cp := make([]testEmittedEvent, len(e.events)) + copy(cp, e.events) + return cp +} + func TestStartPlugin_DeprecatedProtocol_EmitsEvent(t *testing.T) { pm := newTestManager(t) pm.ctx = context.Background() - // Capture emitted events. - var mu sync.Mutex - var emitted []struct { - event string - data []interface{} - } - eventEmitFn = func(_ context.Context, event string, data ...interface{}) { - mu.Lock() - emitted = append(emitted, struct { - event string - data []interface{} - }{event, data}) - mu.Unlock() - } - t.Cleanup(func() { - eventEmitFn = func(_ context.Context, _ string, _ ...interface{}) {} - }) + rec := &testRecordingEmitter{} + pm.emitter = rec record := &plugintypes.PluginRecord{ ID: "old-plugin", @@ -671,8 +683,7 @@ func TestStartPlugin_DeprecatedProtocol_EmitsEvent(t *testing.T) { require.NoError(t, err) // Verify deprecation event was emitted. - mu.Lock() - defer mu.Unlock() + emitted := rec.getEvents() var found bool for _, e := range emitted { @@ -694,16 +705,8 @@ func TestStartPlugin_CurrentProtocol_NoDeprecationEvent(t *testing.T) { pm := newTestManager(t) pm.ctx = context.Background() - var mu sync.Mutex - var emitted []string - eventEmitFn = func(_ context.Context, event string, _ ...interface{}) { - mu.Lock() - emitted = append(emitted, event) - mu.Unlock() - } - t.Cleanup(func() { - eventEmitFn = func(_ context.Context, _ string, _ ...interface{}) {} - }) + rec := &testRecordingEmitter{} + pm.emitter = rec record := &plugintypes.PluginRecord{ ID: "current-plugin", @@ -719,10 +722,9 @@ func TestStartPlugin_CurrentProtocol_NoDeprecationEvent(t *testing.T) { err := pm.startPlugin(record, backend) require.NoError(t, err) - mu.Lock() - defer mu.Unlock() + emitted := rec.getEvents() for _, e := range emitted { - assert.NotEqual(t, EventDeprecatedProtocol, e, "should not emit deprecation for current version") + assert.NotEqual(t, EventDeprecatedProtocol, e.event, "should not emit deprecation for current version") } } diff --git a/backend/pkg/plugin/logs/client.go b/backend/pkg/plugin/logs/client.go deleted file mode 100644 index c959946e..00000000 --- a/backend/pkg/plugin/logs/client.go +++ /dev/null @@ -1,53 +0,0 @@ -package logs - -import ( - sdklogs "github.com/omniviewdev/plugin-sdk/pkg/v1/logs" -) - -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -func (c *Client) GetSupportedResources(pluginID string) []sdklogs.Handler { - return c.controller.GetSupportedResources(pluginID) -} - -func (c *Client) CreateSession( - plugin, connectionID string, - opts sdklogs.CreateSessionOptions, -) (*sdklogs.LogSession, error) { - return c.controller.CreateSession(plugin, connectionID, opts) -} - -func (c *Client) GetSession(sessionID string) (*sdklogs.LogSession, error) { - return c.controller.GetSession(sessionID) -} - -func (c *Client) ListSessions() ([]*sdklogs.LogSession, error) { - return c.controller.ListSessions() -} - -func (c *Client) CloseSession(sessionID string) error { - return c.controller.CloseSession(sessionID) -} - -func (c *Client) PauseSession(sessionID string) error { - return c.controller.SendCommand(sessionID, sdklogs.StreamCommandPause) -} - -func (c *Client) ResumeSession(sessionID string) error { - return c.controller.SendCommand(sessionID, sdklogs.StreamCommandResume) -} - -func (c *Client) UpdateSessionOptions( - sessionID string, - opts sdklogs.LogSessionOptions, -) (*sdklogs.LogSession, error) { - return c.controller.UpdateSessionOptions(sessionID, opts) -} diff --git a/backend/pkg/plugin/logs/controller.go b/backend/pkg/plugin/logs/controller.go index a2ad0024..529ff1b9 100644 --- a/backend/pkg/plugin/logs/controller.go +++ b/backend/pkg/plugin/logs/controller.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -35,7 +35,8 @@ const ( // Controller manages log sessions across all plugins. type Controller interface { internaltypes.Controller - Run(ctx context.Context) + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + ServiceShutdown() error GetSupportedResources(pluginID string) []logs.Handler CreateSession(plugin, connectionID string, opts logs.CreateSessionOptions) (*logs.LogSession, error) GetSession(sessionID string) (*logs.LogSession, error) @@ -53,6 +54,7 @@ type sessionIndex struct { var _ Controller = (*controller)(nil) type controller struct { + app *application.App ctx context.Context logger logging.Logger settingsProvider pkgsettings.Provider @@ -93,9 +95,15 @@ func NewController( } } -func (c *controller) Run(ctx context.Context) { +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() c.ctx = ctx go c.runMux() + return nil +} + +func (c *controller) ServiceShutdown() error { + return nil } func (c *controller) runMux() { @@ -120,7 +128,7 @@ func (c *controller) handleOutput(output logs.StreamOutput) { c.logger.Errorw(context.Background(), "failed to marshal log event", "error", err) return } - runtime.EventsEmit(c.ctx, eventKey, string(data)) + c.app.Event.Emit(eventKey, string(data)) } } @@ -166,7 +174,7 @@ func (c *controller) flushBatchLocked(sessionID string, batch *logBatch) { if err != nil { c.logger.Errorw(context.Background(), "failed to marshal log batch", "error", err) } else { - runtime.EventsEmit(c.ctx, eventKey, string(data)) + c.app.Event.Emit(eventKey, string(data)) } batch.lines = batch.lines[:0] diff --git a/backend/pkg/plugin/logs/controller_apperror_test.go b/backend/pkg/plugin/logs/controller_apperror_test.go index 3edd3f11..db20ae48 100644 --- a/backend/pkg/plugin/logs/controller_apperror_test.go +++ b/backend/pkg/plugin/logs/controller_apperror_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/wailsapp/wails/v3/pkg/application" logging "github.com/omniviewdev/plugin-sdk/log" "github.com/omniviewdev/omniview/backend/pkg/apperror" @@ -17,7 +18,7 @@ import ( // No plugins are registered, so every lookup must fail with a structured error. func newTestController() Controller { ctrl := NewController(logging.NewNop(), nil, nil) - ctrl.Run(context.Background()) + _ = ctrl.ServiceStartup(context.Background(), application.ServiceOptions{}) return ctrl } diff --git a/backend/pkg/plugin/manager.go b/backend/pkg/plugin/manager.go index 4cdc967c..059032ad 100644 --- a/backend/pkg/plugin/manager.go +++ b/backend/pkg/plugin/manager.go @@ -9,8 +9,6 @@ import ( "sync" "time" - "github.com/wailsapp/wails/v2/pkg/runtime" - "github.com/omniviewdev/omniview/backend/pkg/plugin/devserver" pluginexec "github.com/omniviewdev/omniview/backend/pkg/plugin/exec" "github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle" @@ -125,6 +123,7 @@ func NewManager( settingsProvider: settingsProvider, registryClient: registryClient, telemetryConfigFn: telemetryConfigFn, + emitter: resource.NoopEmitter{}, pidTracker: NewPluginPIDTracker(), pluginOpsLocks: make(map[string]*sync.Mutex), } @@ -153,6 +152,7 @@ type pluginManager struct { healthChecker *HealthChecker pluginLogMgr *pluginlog.Manager backendFactory func(meta config.PluginMeta, location string) (plugintypes.PluginBackend, error) + emitter resource.EventEmitter telemetryConfigFn func() TelemetryEnvConfig // returns current telemetry config for env injection // pluginOpsMu serializes load/reload/unload operations per plugin to @@ -228,7 +228,7 @@ func (pm *pluginManager) HandlePluginCrash(pluginID string) { // "crash_recovery_failed" when it gives up. inCrashCycle := pm.healthChecker != nil && pm.healthChecker.IsInCrashCycle(pluginID) if !inCrashCycle { - emitEvent(pm.ctx, "plugin/crash", map[string]interface{}{ + pm.emitter.Emit("plugin/crash", map[string]interface{}{ "pluginID": pluginID, "error": crashError, }) @@ -261,21 +261,21 @@ func (pm *pluginManager) HandlePluginCrash(pluginID string) { } if _, err := pm.ReloadPlugin(pluginID); err != nil { pm.logger.Errorw(pm.ctx, "plugin crash recovery failed", "pluginID", pluginID, "error", err) - emitEvent(pm.ctx, EventCrashRecoveryFailed, map[string]interface{}{ + pm.emitter.Emit(EventCrashRecoveryFailed, map[string]interface{}{ "pluginID": pluginID, "error": err.Error(), }) return } pm.logger.Infow(pm.ctx, "plugin recovered after crash", "pluginID", pluginID) - emitEvent(pm.ctx, EventRecovered, map[string]interface{}{"pluginID": pluginID}) + pm.emitter.Emit(EventRecovered, map[string]interface{}{"pluginID": pluginID}) } // registerStateObserver adds an observer to a plugin's state machine that // emits Wails events on every state transition. func (pm *pluginManager) registerStateObserver(sm *lifecycle.PluginStateMachine) { sm.AddObserver(func(pluginID string, t lifecycle.Transition) { - emitStateChange(pm.ctx, pluginID, t) + emitStateChange(pm.emitter, pluginID, t) }) } @@ -325,7 +325,7 @@ func (pm *pluginManager) Initialize(ctx context.Context) error { // Wire real-time emission via Wails events for the plugin log manager. if pm.pluginLogMgr != nil { pm.pluginLogMgr.OnEmit(func(entry pluginlog.LogEntry) { - runtime.EventsEmit(ctx, "plugin/process/log", entry) + pm.emitter.Emit(EventProcessLog, entry) }) } @@ -492,7 +492,7 @@ func (pm *pluginManager) Initialize(ctx context.Context) error { pm.logger.Errorw(pm.ctx, "failed to merge and persist plugin state", "error", err) } - runtime.EventsEmit(pm.ctx, EventInitComplete) + pm.emitter.Emit(EventInitComplete) return nil } diff --git a/backend/pkg/plugin/manager_test.go b/backend/pkg/plugin/manager_test.go index 97191107..16f9cf5b 100644 --- a/backend/pkg/plugin/manager_test.go +++ b/backend/pkg/plugin/manager_test.go @@ -130,6 +130,7 @@ func TestHandlePluginCrash_WithHealthChecker(t *testing.T) { logger: testLogger(t), records: make(map[string]*plugintypes.PluginRecord), ctx: context.Background(), + emitter: testNoopEmitter{}, } pm.records["crash-test"] = &plugintypes.PluginRecord{ @@ -158,6 +159,7 @@ func TestHandlePluginCrash_SetsPhaseRecovering(t *testing.T) { logger: testLogger(t), records: make(map[string]*plugintypes.PluginRecord), ctx: context.Background(), + emitter: testNoopEmitter{}, } sm := lifecycle.NewPluginStateMachine("phase-plugin", lifecycle.PhaseRunning) @@ -189,6 +191,7 @@ func TestHandlePluginCrash_FallbackContextAware(t *testing.T) { logger: testLogger(t), records: make(map[string]*plugintypes.PluginRecord), ctx: ctx, + emitter: testNoopEmitter{}, // No healthChecker — forces fallback path. } @@ -215,7 +218,7 @@ func TestHandlePluginCrash_FallbackContextAware(t *testing.T) { } func TestRegisterStateObserver(t *testing.T) { - pm := &pluginManager{logger: testLogger(t)} + pm := &pluginManager{logger: testLogger(t), emitter: testNoopEmitter{}} sm := lifecycle.NewPluginStateMachine("test", lifecycle.PhaseStarting) var observed bool diff --git a/backend/pkg/plugin/metric/client.go b/backend/pkg/plugin/metric/client.go deleted file mode 100644 index d1e36be6..00000000 --- a/backend/pkg/plugin/metric/client.go +++ /dev/null @@ -1,58 +0,0 @@ -package metric - -import ( - "time" - - sdkmetric "github.com/omniviewdev/plugin-sdk/pkg/v1/metric" -) - -// Client is the Wails-bound client exposing metric methods to the frontend. -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -func (c *Client) GetProviders() []MetricProviderSummary { - return c.controller.GetProviders() -} - -func (c *Client) GetProvidersForResource(resourceKey string) []MetricProviderSummary { - return c.controller.GetProvidersForResource(resourceKey) -} - -func (c *Client) Query( - pluginID, connectionID string, - req sdkmetric.QueryRequest, -) (*sdkmetric.QueryResponse, error) { - return c.controller.Query(pluginID, connectionID, req) -} - -func (c *Client) QueryAll( - connectionID, resourceKey, resourceID, namespace string, - resourceData map[string]interface{}, - metricIDs []string, - shape sdkmetric.MetricShape, - startTime, endTime time.Time, - step time.Duration, -) (map[string]*sdkmetric.QueryResponse, error) { - return c.controller.QueryAll( - connectionID, resourceKey, resourceID, namespace, - resourceData, metricIDs, shape, startTime, endTime, step, - ) -} - -func (c *Client) Subscribe( - pluginID, connectionID string, - req SubscribeRequest, -) (string, error) { - return c.controller.Subscribe(pluginID, connectionID, req) -} - -func (c *Client) Unsubscribe(subscriptionID string) error { - return c.controller.Unsubscribe(subscriptionID) -} diff --git a/backend/pkg/plugin/metric/controller.go b/backend/pkg/plugin/metric/controller.go index e41a2e75..e9c67005 100644 --- a/backend/pkg/plugin/metric/controller.go +++ b/backend/pkg/plugin/metric/controller.go @@ -8,7 +8,7 @@ import ( "time" "github.com/google/uuid" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -41,7 +41,8 @@ type MetricProviderSummary struct { // Controller manages metric providers across all plugins. type Controller interface { internaltypes.Controller - Run(ctx context.Context) + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + ServiceShutdown() error // Discovery GetProviders() []MetricProviderSummary @@ -78,6 +79,7 @@ type subscriptionIndex struct { var _ Controller = (*controller)(nil) type controller struct { + app *application.App ctx context.Context logger logging.Logger settingsProvider pkgsettings.Provider @@ -109,8 +111,14 @@ func NewController( } } -func (c *controller) Run(ctx context.Context) { +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() c.ctx = ctx + return nil +} + +func (c *controller) ServiceShutdown() error { + return nil } // ================================ Controller Lifecycle ================================ // @@ -270,10 +278,10 @@ func (c *controller) handleStreamOutput(output metric.StreamOutput) { if output.Error != "" { eventKey := "core/metrics/error/" + output.SubscriptionID - runtime.EventsEmit(c.ctx, eventKey, string(data)) + c.app.Event.Emit(eventKey, string(data)) } else { eventKey := "core/metrics/data/" + output.SubscriptionID - runtime.EventsEmit(c.ctx, eventKey, string(data)) + c.app.Event.Emit(eventKey, string(data)) } } diff --git a/backend/pkg/plugin/networker/client.go b/backend/pkg/plugin/networker/client.go deleted file mode 100644 index 6f87da13..00000000 --- a/backend/pkg/plugin/networker/client.go +++ /dev/null @@ -1,56 +0,0 @@ -package networker - -import ( - sdknetworker "github.com/omniviewdev/plugin-sdk/pkg/v1/networker" -) - -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -func (c *Client) GetSupportedPortForwardTargets(plugin string) ([]string, error) { - return c.controller.GetSupportedPortForwardTargets(plugin) -} - -func (c *Client) GetPortForwardSession( - sessionID string, -) (*sdknetworker.PortForwardSession, error) { - return c.controller.GetPortForwardSession(sessionID) -} - -func (c *Client) ListPortForwardSessions( - pluginID, connectionID string, -) ([]*sdknetworker.PortForwardSession, error) { - return c.controller.ListPortForwardSessions(pluginID, connectionID) -} - -func (c *Client) ListAllPortForwardSessions() ([]*sdknetworker.PortForwardSession, error) { - return c.controller.ListAllPortForwardSessions() -} - -func (c *Client) FindPortForwardSessions( - pluginID, connectionID string, - request sdknetworker.FindPortForwardSessionRequest, -) ([]*sdknetworker.PortForwardSession, error) { - return c.controller.FindPortForwardSessions(pluginID, connectionID, request) -} - -// StartResourcePortForwardingSession starts a port forwarding session. -func (c *Client) StartResourcePortForwardingSession( - pluginID, connectionID string, - opts sdknetworker.PortForwardSessionOptions, -) (*sdknetworker.PortForwardSession, error) { - return c.controller.StartResourcePortForwardingSession(pluginID, connectionID, opts) -} - -// ClosePortForwardSession closes a port forward session. -func (c *Client) ClosePortForwardSession(sessionID string, -) (*sdknetworker.PortForwardSession, error) { - return c.controller.ClosePortForwardSession(sessionID) -} diff --git a/backend/pkg/plugin/networker/controller.go b/backend/pkg/plugin/networker/controller.go index ec88b95a..4343c855 100644 --- a/backend/pkg/plugin/networker/controller.go +++ b/backend/pkg/plugin/networker/controller.go @@ -14,7 +14,8 @@ import ( "github.com/omniviewdev/omniview/backend/pkg/plugin/resource" "github.com/omniviewdev/omniview/backend/pkg/plugin/telemetryutil" internaltypes "github.com/omniviewdev/omniview/backend/pkg/plugin/types" - "github.com/wailsapp/wails/v2/pkg/runtime" + + "github.com/wailsapp/wails/v3/pkg/application" "github.com/omniviewdev/plugin-sdk/pkg/config" "github.com/omniviewdev/plugin-sdk/pkg/v1/networker" @@ -30,11 +31,18 @@ const ( PortForwardSessionClosed = "core/networker/portforward/closed" ) +func init() { + application.RegisterEvent[*networker.PortForwardSession](PortForwardSessionCreated) + application.RegisterEvent[*networker.PortForwardSession](PortForwardSessionClosed) +} + type Controller interface { internaltypes.Controller - // Run stores the Wails application context for event emission. - Run(ctx context.Context) + // ServiceStartup initialises the controller during application startup. + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + // ServiceShutdown cleans up resources during application shutdown. + ServiceShutdown() error // GetSupportedPortForwardTargets returns the supported targets for port forwarding GetSupportedPortForwardTargets(pluginID string) ([]string, error) @@ -88,6 +96,7 @@ func NewController( var _ Controller = &controller{} type controller struct { + app *application.App ctx context.Context logger logging.Logger settingsProvider pkgsettings.Provider @@ -99,9 +108,16 @@ type controller struct { stops map[string]chan struct{} } -// Run stores the Wails application context for event emission. -func (c *controller) Run(ctx context.Context) { +// ServiceStartup initialises the controller during application startup. +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() c.ctx = ctx + return nil +} + +// ServiceShutdown cleans up resources during application shutdown. +func (c *controller) ServiceShutdown() error { + return nil } // ====================================== Controller Implementation ====================================== // @@ -505,8 +521,8 @@ func (c *controller) StartResourcePortForwardingSession( } c.mu.Unlock() - if c.ctx != nil { - runtime.EventsEmit(c.ctx, PortForwardSessionCreated, session) + if c.app != nil { + c.app.Event.Emit(PortForwardSessionCreated, session) } return session, nil @@ -554,8 +570,8 @@ func (c *controller) ClosePortForwardSession( delete(c.sessionIndex, sessionID) c.mu.Unlock() - if c.ctx != nil { - runtime.EventsEmit(c.ctx, PortForwardSessionClosed, session) + if c.app != nil { + c.app.Event.Emit(PortForwardSessionClosed, session) } return session, nil diff --git a/backend/pkg/plugin/resource/client.go b/backend/pkg/plugin/resource/client.go deleted file mode 100644 index 8654e738..00000000 --- a/backend/pkg/plugin/resource/client.go +++ /dev/null @@ -1,265 +0,0 @@ -package resource - -import ( - "encoding/json" - - resource "github.com/omniviewdev/plugin-sdk/pkg/v1/resource" - "github.com/omniviewdev/plugin-sdk/pkg/types" -) - -// NOTE: Client intentionally does NOT implement Service. It is the Wails-bound -// frontend API layer that converts between SDK types (json.RawMessage) and -// frontend-friendly types (interface{} → "any" in TypeScript). - -// Client is a thin Wails-bound wrapper around the Controller. -// It converts SDK types (json.RawMessage) to frontend-friendly types (interface{}) -// so that Wails generates "any" in TypeScript instead of "number[]". -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{controller: controller} -} - -// Client no longer satisfies Service — it uses frontend-facing types -// (interface{} instead of json.RawMessage) so Wails generates correct TS. - -func (c *Client) ListPlugins() ([]string, error) { - return c.controller.ListPlugins() -} - -// CRUD — converts between SDK types and frontend-facing types - -func (c *Client) Get(pluginID, connectionID, key string, input resource.GetInput) (*ClientResult, error) { - result, err := c.controller.Get(pluginID, connectionID, key, input) - if err != nil { - return nil, err - } - return toClientResult(result), nil -} - -func (c *Client) List(pluginID, connectionID, key string, input resource.ListInput) (*ClientListResult, error) { - result, err := c.controller.List(pluginID, connectionID, key, input) - if err != nil { - return nil, err - } - return toClientListResult(result), nil -} - -func (c *Client) Find(pluginID, connectionID, key string, input resource.FindInput) (*ClientListResult, error) { - result, err := c.controller.Find(pluginID, connectionID, key, input) - if err != nil { - return nil, err - } - return findToClientListResult(result), nil -} - -func (c *Client) Create(pluginID, connectionID, key string, input ClientCreateInput) (*ClientResult, error) { - sdkInput, err := toSDKCreateInput(input) - if err != nil { - return nil, err - } - result, err := c.controller.Create(pluginID, connectionID, key, sdkInput) - if err != nil { - return nil, err - } - return createToClientResult(result), nil -} - -func (c *Client) Update(pluginID, connectionID, key string, input ClientUpdateInput) (*ClientResult, error) { - sdkInput, err := toSDKUpdateInput(input) - if err != nil { - return nil, err - } - result, err := c.controller.Update(pluginID, connectionID, key, sdkInput) - if err != nil { - return nil, err - } - return updateToClientResult(result), nil -} - -func (c *Client) Delete(pluginID, connectionID, key string, input resource.DeleteInput) (*ClientResult, error) { - result, err := c.controller.Delete(pluginID, connectionID, key, input) - if err != nil { - return nil, err - } - return deleteToClientResult(result), nil -} - -// Connection lifecycle - -func (c *Client) StartConnection(pluginID, connectionID string) (types.ConnectionStatus, error) { - return c.controller.StartConnection(pluginID, connectionID) -} - -func (c *Client) StopConnection(pluginID, connectionID string) (types.Connection, error) { - return c.controller.StopConnection(pluginID, connectionID) -} - -func (c *Client) CheckConnection(pluginID, connectionID string) (types.ConnectionStatus, error) { - return c.controller.CheckConnection(pluginID, connectionID) -} - -func (c *Client) LoadConnections(pluginID string) ([]types.Connection, error) { - return c.controller.LoadConnections(pluginID) -} - -func (c *Client) ListConnections(pluginID string) ([]types.Connection, error) { - return c.controller.ListConnections(pluginID) -} - -func (c *Client) ListAllConnections() (map[string][]types.Connection, error) { - return c.controller.ListAllConnections() -} - -func (c *Client) GetAllConnectionStates() (map[string][]ConnectionState, error) { - return c.controller.GetAllConnectionStates() -} - -func (c *Client) GetConnection(pluginID, connectionID string) (types.Connection, error) { - return c.controller.GetConnection(pluginID, connectionID) -} - -func (c *Client) GetConnectionNamespaces(pluginID, connectionID string) ([]string, error) { - return c.controller.GetConnectionNamespaces(pluginID, connectionID) -} - -func (c *Client) AddConnection(pluginID string, connection types.Connection) error { - return c.controller.AddConnection(pluginID, connection) -} - -func (c *Client) UpdateConnection(pluginID string, connection types.Connection) (types.Connection, error) { - return c.controller.UpdateConnection(pluginID, connection) -} - -func (c *Client) RemoveConnection(pluginID, connectionID string) error { - return c.controller.RemoveConnection(pluginID, connectionID) -} - -// Watch lifecycle - -func (c *Client) StartConnectionWatch(pluginID, connectionID string) error { - return c.controller.StartConnectionWatch(pluginID, connectionID) -} - -func (c *Client) StopConnectionWatch(pluginID, connectionID string) error { - return c.controller.StopConnectionWatch(pluginID, connectionID) -} - -func (c *Client) GetWatchState(pluginID, connectionID string) (*resource.WatchConnectionSummary, error) { - return c.controller.GetWatchState(pluginID, connectionID) -} - -func (c *Client) EnsureResourceWatch(pluginID, connectionID, resourceKey string) error { - return c.controller.EnsureResourceWatch(pluginID, connectionID, resourceKey) -} - -func (c *Client) StopResourceWatch(pluginID, connectionID, resourceKey string) error { - return c.controller.StopResourceWatch(pluginID, connectionID, resourceKey) -} - -func (c *Client) RestartResourceWatch(pluginID, connectionID, resourceKey string) error { - return c.controller.RestartResourceWatch(pluginID, connectionID, resourceKey) -} - -func (c *Client) IsResourceWatchRunning(pluginID, connectionID, resourceKey string) (bool, error) { - return c.controller.IsResourceWatchRunning(pluginID, connectionID, resourceKey) -} - -// Subscriptions - -func (c *Client) SubscribeResource(pluginID, connectionID, resourceKey string) error { - return c.controller.SubscribeResource(pluginID, connectionID, resourceKey) -} - -func (c *Client) UnsubscribeResource(pluginID, connectionID, resourceKey string) error { - return c.controller.UnsubscribeResource(pluginID, connectionID, resourceKey) -} - -// Type metadata - -func (c *Client) GetResourceGroups(pluginID, connectionID string) map[string]resource.ResourceGroup { - return c.controller.GetResourceGroups(pluginID, connectionID) -} - -func (c *Client) GetResourceGroup(pluginID, groupID string) (resource.ResourceGroup, error) { - return c.controller.GetResourceGroup(pluginID, groupID) -} - -func (c *Client) GetResourceTypes(pluginID, connectionID string) map[string]resource.ResourceMeta { - return c.controller.GetResourceTypes(pluginID, connectionID) -} - -func (c *Client) GetResourceType(pluginID, typeID string) (*resource.ResourceMeta, error) { - return c.controller.GetResourceType(pluginID, typeID) -} - -func (c *Client) HasResourceType(pluginID, typeID string) bool { - return c.controller.HasResourceType(pluginID, typeID) -} - -func (c *Client) GetResourceDefinition(pluginID, typeID string) (resource.ResourceDefinition, error) { - return c.controller.GetResourceDefinition(pluginID, typeID) -} - -func (c *Client) GetResourceCapabilities(pluginID, key string) (*resource.ResourceCapabilities, error) { - return c.controller.GetResourceCapabilities(pluginID, key) -} - -func (c *Client) GetFilterFields(pluginID, connectionID, key string) ([]resource.FilterField, error) { - return c.controller.GetFilterFields(pluginID, connectionID, key) -} - -func (c *Client) GetResourceSchema(pluginID, connectionID, key string) (interface{}, error) { - raw, err := c.controller.GetResourceSchema(pluginID, connectionID, key) - if err != nil { - return nil, err - } - return interface{}(raw), nil -} - -// Actions - -func (c *Client) GetActions(pluginID, connectionID, key string) ([]resource.ActionDescriptor, error) { - return c.controller.GetActions(pluginID, connectionID, key) -} - -func (c *Client) ExecuteAction(pluginID, connectionID, key, actionID string, input resource.ActionInput) (*resource.ActionResult, error) { - return c.controller.ExecuteAction(pluginID, connectionID, key, actionID, input) -} - -func (c *Client) StreamAction(pluginID, connectionID, key, actionID string, input resource.ActionInput) (string, error) { - return c.controller.StreamAction(pluginID, connectionID, key, actionID, input) -} - -// Editor schemas - -func (c *Client) GetEditorSchemas(pluginID, connectionID string) ([]resource.EditorSchema, error) { - return c.controller.GetEditorSchemas(pluginID, connectionID) -} - -// Relationships - -func (c *Client) GetRelationships(pluginID, key string) ([]resource.RelationshipDescriptor, error) { - return c.controller.GetRelationships(pluginID, key) -} - -func (c *Client) ResolveRelationships(pluginID, connectionID, key, id, namespace string) ([]resource.ResolvedRelationship, error) { - return c.controller.ResolveRelationships(pluginID, connectionID, key, id, namespace) -} - -// Health - -func (c *Client) GetHealth(pluginID, connectionID, key string, data interface{}) (*resource.ResourceHealth, error) { - raw, err := json.Marshal(data) - if err != nil { - return nil, err - } - return c.controller.GetHealth(pluginID, connectionID, key, json.RawMessage(raw)) -} - -func (c *Client) GetResourceEvents(pluginID, connectionID, key, id, namespace string, limit int32) ([]resource.ResourceEvent, error) { - return c.controller.GetResourceEvents(pluginID, connectionID, key, id, namespace, limit) -} - diff --git a/backend/pkg/plugin/resource/controller.go b/backend/pkg/plugin/resource/controller.go index 80b15704..93c1a4e2 100644 --- a/backend/pkg/plugin/resource/controller.go +++ b/backend/pkg/plugin/resource/controller.go @@ -14,6 +14,7 @@ import ( "time" logging "github.com/omniviewdev/plugin-sdk/log" + "github.com/wailsapp/wails/v3/pkg/application" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -35,6 +36,25 @@ import ( const PluginName = "resource" +// Event constants for resource controller events. +const ( + EventConnectionStatus = "connection/status" + EventWatchState = "watch/STATE" +) + +// ConnectionStatusPayload is emitted when a connection's status changes. +type ConnectionStatusPayload struct { + PluginID string `json:"pluginID"` + ConnectionID string `json:"connectionID"` + Status string `json:"status"` + Name string `json:"name"` +} + +func init() { + application.RegisterEvent[ConnectionStatusPayload](EventConnectionStatus) + application.RegisterEvent[resource.WatchStateEvent](EventWatchState) +} + var tracer = otel.Tracer("omniview.resource") @@ -56,6 +76,7 @@ type pluginState struct { // controller manages resource plugins on the engine side. type controller struct { + app *application.App logger logging.Logger settingsProvider pkgsettings.Provider emitter EventEmitter @@ -120,14 +141,26 @@ func (c *controller) Graph() *graph.RelationshipGraph { // ============================================================================ // Run starts the controller's background tasks. +// Satisfies the ConnectedController interface; prefer ServiceStartup for Wails v3. func (c *controller) Run(ctx context.Context) { - c.emitter = newWailsEmitter(ctx) + if c.emitter == nil { + c.emitter = NoopEmitter{} + } + c.dispatcher.Start() +} + +// ServiceStartup is called by the Wails v3 runtime when the application starts. +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() + c.emitter = newAppEmitter(c.app) c.dispatcher.Start() + return nil } -// Shutdown stops background tasks. Must be called on application exit. -func (c *controller) Shutdown() { +// ServiceShutdown is called by the Wails v3 runtime when the application shuts down. +func (c *controller) ServiceShutdown() error { c.dispatcher.Stop() + return nil } // dispenseProvider creates a ResourceProvider from a PluginBackend using version negotiation. @@ -551,11 +584,11 @@ func (c *controller) StartConnection(pluginID, connectionID string) (types.Conne if conn.Connection != nil && conn.Connection.Name != "" { connName = conn.Connection.Name } - c.emitter.Emit("connection/status", map[string]interface{}{ - "pluginID": pluginID, - "connectionID": connectionID, - "status": string(conn.Status), - "name": connName, + c.emitter.Emit(EventConnectionStatus, ConnectionStatusPayload{ + PluginID: pluginID, + ConnectionID: connectionID, + Status: string(conn.Status), + Name: connName, }) return conn, nil @@ -583,11 +616,11 @@ func (c *controller) StopConnection(pluginID, connectionID string) (types.Connec c.connections[pluginID] = mergeConnections(c.connections[pluginID], []types.Connection{conn}) c.connsMu.Unlock() - c.emitter.Emit("connection/status", map[string]interface{}{ - "pluginID": pluginID, - "connectionID": connectionID, - "status": "DISCONNECTED", - "name": conn.Name, + c.emitter.Emit(EventConnectionStatus, ConnectionStatusPayload{ + PluginID: pluginID, + ConnectionID: connectionID, + Status: "DISCONNECTED", + Name: conn.Name, }) return conn, nil diff --git a/backend/pkg/plugin/resource/controller_actions_test.go b/backend/pkg/plugin/resource/controller_actions_test.go index aa9784b4..5ab86e23 100644 --- a/backend/pkg/plugin/resource/controller_actions_test.go +++ b/backend/pkg/plugin/resource/controller_actions_test.go @@ -144,11 +144,11 @@ func TestStreamAction_EmitsEvents(t *testing.T) { assert.Len(t, events, 2) // Verify event types in order. - ev0, ok := events[0].Data.(resource.ActionEvent) + ev0, ok := events[0].Data[0].(resource.ActionEvent) require.True(t, ok) assert.Equal(t, "progress", ev0.Type) - ev1, ok := events[1].Data.(resource.ActionEvent) + ev1, ok := events[1].Data[0].(resource.ActionEvent) require.True(t, ok) assert.Equal(t, "complete", ev1.Type) } @@ -168,7 +168,7 @@ func TestStreamAction_EmitsError(t *testing.T) { // Wait for the error event. ev := emitter.WaitForEvent(t, "action/stream/"+opID, 2*time.Second) - actionEv, ok := ev.Data.(resource.ActionEvent) + actionEv, ok := ev.Data[0].(resource.ActionEvent) require.True(t, ok) assert.Equal(t, "error", actionEv.Type) assert.Contains(t, actionEv.Data["message"], "stream broke") diff --git a/backend/pkg/plugin/resource/controller_connections_test.go b/backend/pkg/plugin/resource/controller_connections_test.go index 73c37048..c9eb1e62 100644 --- a/backend/pkg/plugin/resource/controller_connections_test.go +++ b/backend/pkg/plugin/resource/controller_connections_test.go @@ -273,10 +273,10 @@ func TestStartConnection_EmitsStatusEvent(t *testing.T) { events := emitter.EventsWithKey("connection/status") require.NotEmpty(t, events) - data, ok := events[0].Data.(map[string]interface{}) + payload, ok := events[0].Data[0].(ConnectionStatusPayload) require.True(t, ok) - assert.Equal(t, "p1", data["pluginID"]) - assert.Equal(t, "conn-1", data["connectionID"]) + assert.Equal(t, "p1", payload.PluginID) + assert.Equal(t, "conn-1", payload.ConnectionID) } func TestStartConnection_FailedConnection(t *testing.T) { @@ -323,9 +323,9 @@ func TestStopConnection_EmitsDisconnected(t *testing.T) { events := emitter.EventsWithKey("connection/status") require.NotEmpty(t, events) - data, ok := events[0].Data.(map[string]interface{}) + payload, ok := events[0].Data[0].(ConnectionStatusPayload) require.True(t, ok) - assert.Equal(t, "DISCONNECTED", data["status"]) + assert.Equal(t, "DISCONNECTED", payload.Status) } // ============================================================================ diff --git a/backend/pkg/plugin/resource/controller_crash_test.go b/backend/pkg/plugin/resource/controller_crash_test.go index 50118f7d..617c1ebe 100644 --- a/backend/pkg/plugin/resource/controller_crash_test.go +++ b/backend/pkg/plugin/resource/controller_crash_test.go @@ -83,16 +83,12 @@ func newCrashTestController() *controller { ctrl := &controller{ logger: logging.NewNop(), plugins: make(map[string]*pluginState), - emitter: &noopEmitter{}, + emitter: NoopEmitter{}, subs: newSubscriptionManager(), } return ctrl } -// noopEmitter is a no-op EventEmitter for crash tests. -type noopEmitter struct{} - -func (e *noopEmitter) Emit(string, interface{}) {} // addPluginState is a test helper that sets up a pluginState entry for crash tests. func addPluginState(ctrl *controller, pluginID string) { diff --git a/backend/pkg/plugin/resource/controller_integration_test.go b/backend/pkg/plugin/resource/controller_integration_test.go index d330fd5d..ad2725e9 100644 --- a/backend/pkg/plugin/resource/controller_integration_test.go +++ b/backend/pkg/plugin/resource/controller_integration_test.go @@ -170,7 +170,7 @@ func TestIntegration_WatchEventsFlow(t *testing.T) { // Emitter should have recorded the event. ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "p1", payload.PluginID) assert.Equal(t, "conn-1", payload.Connection) @@ -194,7 +194,7 @@ func TestIntegration_SubscriptionGates(t *testing.T) { sink.OnAdd(resource.WatchAddPayload{Connection: "conn-1", Key: "pods", ID: "pod-2"}) ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "pod-2", payload.ID) } @@ -237,7 +237,7 @@ func TestIntegration_RefCounted_Subscriptions(t *testing.T) { // Events still flow. sink.OnAdd(resource.WatchAddPayload{Connection: "conn-1", Key: "pods", ID: "pod-1"}) ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "pod-1", payload.ID) } @@ -260,10 +260,10 @@ func TestIntegration_ConnectionDisconnect(t *testing.T) { // Emitter should have a DISCONNECTED status event. ev := emitter.WaitForEvent(t, "connection/status", time.Second) - statusData, ok := ev.Data.(map[string]interface{}) + payload, ok := ev.Data[0].(ConnectionStatusPayload) require.True(t, ok) - assert.Equal(t, "DISCONNECTED", statusData["status"]) - assert.Equal(t, "conn-1", statusData["connectionID"]) + assert.Equal(t, "DISCONNECTED", payload.Status) + assert.Equal(t, "conn-1", payload.ConnectionID) } // EI-009: OnPluginStop removes plugin, connections, and subscriptions. @@ -310,7 +310,7 @@ func TestIntegration_MultiPlugin_Isolation(t *testing.T) { sink1.OnAdd(resource.WatchAddPayload{Connection: "conn-1", Key: "pods", ID: "pod-from-p1"}) ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "p1", payload.PluginID) assert.Equal(t, "pod-from-p1", payload.ID) @@ -326,7 +326,7 @@ func TestIntegration_MultiPlugin_Isolation(t *testing.T) { p1Events := 0 p2Events := 0 for _, e := range events { - p, ok := e.Data.(resource.WatchAddPayload) + p, ok := e.Data[0].(resource.WatchAddPayload) require.True(t, ok) if p.PluginID == "p1" { p1Events++ @@ -394,7 +394,7 @@ func TestIntegration_SubscribeBeforeConnect(t *testing.T) { sink.OnAdd(resource.WatchAddPayload{Connection: "conn-1", Key: "pods", ID: "pod-1"}) ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "pod-1", payload.ID) } @@ -424,9 +424,9 @@ func TestIntegration_OutOfOrderEvents(t *testing.T) { var eventTypes []string for _, e := range all { if e.Key == "p1/conn-1/pods/ADD" || e.Key == "p1/conn-1/pods/DELETE" { - if _, ok := e.Data.(resource.WatchAddPayload); ok { + if _, ok := e.Data[0].(resource.WatchAddPayload); ok { eventTypes = append(eventTypes, "ADD") - } else if _, ok := e.Data.(resource.WatchDeletePayload); ok { + } else if _, ok := e.Data[0].(resource.WatchDeletePayload); ok { eventTypes = append(eventTypes, "DELETE") } } @@ -491,7 +491,7 @@ func TestIntegration_SameKeyTwoPlugins(t *testing.T) { time.Sleep(50 * time.Millisecond) events := emitter.Events() for _, e := range events { - if payload, ok := e.Data.(resource.WatchAddPayload); ok { + if payload, ok := e.Data[0].(resource.WatchAddPayload); ok { assert.Equal(t, "p1", payload.PluginID, "event should only have p1 plugin ID") } } diff --git a/backend/pkg/plugin/resource/emitter.go b/backend/pkg/plugin/resource/emitter.go index 3d16da53..249b5182 100644 --- a/backend/pkg/plugin/resource/emitter.go +++ b/backend/pkg/plugin/resource/emitter.go @@ -1,26 +1,29 @@ package resource import ( - "context" - - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" ) // EventEmitter abstracts event emission for testability. -// Production uses wailsEmitter; tests use recordingEmitter. +// Production uses appEmitter; tests use recordingEmitter. type EventEmitter interface { - Emit(eventKey string, data interface{}) + Emit(eventKey string, data ...any) } -// wailsEmitter emits events via the Wails runtime. -type wailsEmitter struct { - ctx context.Context +// appEmitter emits events via the Wails v3 application instance. +type appEmitter struct { + app *application.App } -func newWailsEmitter(ctx context.Context) *wailsEmitter { - return &wailsEmitter{ctx: ctx} +func newAppEmitter(app *application.App) *appEmitter { + return &appEmitter{app: app} } -func (e *wailsEmitter) Emit(eventKey string, data interface{}) { - runtime.EventsEmit(e.ctx, eventKey, data) +func (e *appEmitter) Emit(eventKey string, data ...any) { + e.app.Event.Emit(eventKey, data...) } + +// NoopEmitter silently discards all events. Used before the app is initialized. +type NoopEmitter struct{} + +func (NoopEmitter) Emit(string, ...any) {} diff --git a/backend/pkg/plugin/resource/emitter_test.go b/backend/pkg/plugin/resource/emitter_test.go index 50ffc7b9..a9c0cd83 100644 --- a/backend/pkg/plugin/resource/emitter_test.go +++ b/backend/pkg/plugin/resource/emitter_test.go @@ -2,8 +2,8 @@ package resource import "testing" -func TestWailsEmitter_ImplementsInterface(t *testing.T) { - var _ EventEmitter = (*wailsEmitter)(nil) +func TestAppEmitter_ImplementsInterface(t *testing.T) { + var _ EventEmitter = (*appEmitter)(nil) } func TestRecordingEmitter_ImplementsInterface(t *testing.T) { @@ -11,5 +11,5 @@ func TestRecordingEmitter_ImplementsInterface(t *testing.T) { } func TestNoopEmitter_ImplementsInterface(t *testing.T) { - var _ EventEmitter = (*noopEmitter)(nil) + var _ EventEmitter = NoopEmitter{} } diff --git a/backend/pkg/plugin/resource/grpc_integration_test.go b/backend/pkg/plugin/resource/grpc_integration_test.go index fca7339d..38791200 100644 --- a/backend/pkg/plugin/resource/grpc_integration_test.go +++ b/backend/pkg/plugin/resource/grpc_integration_test.go @@ -158,7 +158,7 @@ func TestL3_03_WatchEventsFlowThroughGRPC(t *testing.T) { ev := emitter.WaitForEvent(t, "ADD", 5*time.Second) assert.Equal(t, "p1/conn-1/core::v1::Pod/ADD", ev.Key) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) require.True(t, ok) assert.Equal(t, "p1", payload.PluginID) assert.Equal(t, "conn-1", payload.Connection) @@ -263,7 +263,7 @@ func TestL3_05_StateEventKeyFormatViaGRPC(t *testing.T) { assert.Equal(t, "watch/STATE", events[1].Key) // Verify payload enrichment. - payload, ok := events[0].Data.(resource.WatchStateEvent) + payload, ok := events[0].Data[0].(resource.WatchStateEvent) require.True(t, ok) assert.Equal(t, "p1", payload.PluginID) assert.Equal(t, "my-cluster", payload.Connection) diff --git a/backend/pkg/plugin/resource/sink_test.go b/backend/pkg/plugin/resource/sink_test.go index abb79921..08096651 100644 --- a/backend/pkg/plugin/resource/sink_test.go +++ b/backend/pkg/plugin/resource/sink_test.go @@ -47,7 +47,7 @@ func TestSink_OnAdd_SetsPluginID(t *testing.T) { sink.OnAdd(resource.WatchAddPayload{Connection: "conn-1", Key: "pods"}) ev := emitter.WaitForEvent(t, "ADD", time.Second) - payload, ok := ev.Data.(resource.WatchAddPayload) + payload, ok := ev.Data[0].(resource.WatchAddPayload) assert.True(t, ok) assert.Equal(t, "plugin-a", payload.PluginID) } @@ -78,7 +78,7 @@ func TestSink_OnUpdate_SetsPluginID(t *testing.T) { sink.OnUpdate(resource.WatchUpdatePayload{Connection: "conn-1", Key: "pods"}) ev := emitter.WaitForEvent(t, "UPDATE", time.Second) - payload, ok := ev.Data.(resource.WatchUpdatePayload) + payload, ok := ev.Data[0].(resource.WatchUpdatePayload) assert.True(t, ok) assert.Equal(t, "plugin-a", payload.PluginID) } @@ -109,7 +109,7 @@ func TestSink_OnDelete_SetsPluginID(t *testing.T) { sink.OnDelete(resource.WatchDeletePayload{Connection: "conn-1", Key: "pods"}) ev := emitter.WaitForEvent(t, "DELETE", time.Second) - payload, ok := ev.Data.(resource.WatchDeletePayload) + payload, ok := ev.Data[0].(resource.WatchDeletePayload) assert.True(t, ok) assert.Equal(t, "plugin-a", payload.PluginID) } @@ -160,7 +160,7 @@ func TestSink_OnStateChange_SetsPluginID(t *testing.T) { }) ev := emitter.WaitForEvent(t, "STATE", time.Second) - payload, ok := ev.Data.(resource.WatchStateEvent) + payload, ok := ev.Data[0].(resource.WatchStateEvent) assert.True(t, ok) assert.Equal(t, "plugin-a", payload.PluginID) assert.Equal(t, "conn-1", payload.Connection) @@ -185,7 +185,7 @@ func TestSink_OnStateChange_EventKeyFormat(t *testing.T) { assert.Equal(t, "watch/STATE", all[1].Key) // Both events carry the same enriched payload - perPayload, ok := all[0].Data.(resource.WatchStateEvent) + perPayload, ok := all[0].Data[0].(resource.WatchStateEvent) assert.True(t, ok) assert.Equal(t, "plugin-a", perPayload.PluginID) assert.Equal(t, "my-cluster", perPayload.Connection) diff --git a/backend/pkg/plugin/resource/testutil_test.go b/backend/pkg/plugin/resource/testutil_test.go index 2394d8ff..c2c31494 100644 --- a/backend/pkg/plugin/resource/testutil_test.go +++ b/backend/pkg/plugin/resource/testutil_test.go @@ -26,7 +26,7 @@ import ( type emittedEvent struct { Key string - Data interface{} + Data []any } type recordingEmitter struct { @@ -39,7 +39,7 @@ func newRecordingEmitter() *recordingEmitter { return &recordingEmitter{changed: make(chan struct{})} } -func (e *recordingEmitter) Emit(key string, data interface{}) { +func (e *recordingEmitter) Emit(key string, data ...any) { e.mu.Lock() e.events = append(e.events, emittedEvent{Key: key, Data: data}) close(e.changed) @@ -490,9 +490,9 @@ func TestRecordingEmitter_EmitAndEvents(t *testing.T) { events := e.Events() require.Len(t, events, 2) assert.Equal(t, "key-1", events[0].Key) - assert.Equal(t, "data-1", events[0].Data) + assert.Equal(t, []any{"data-1"}, events[0].Data) assert.Equal(t, "key-2", events[1].Key) - assert.Equal(t, "data-2", events[1].Data) + assert.Equal(t, []any{"data-2"}, events[1].Data) } func TestRecordingEmitter_CountEvents(t *testing.T) { @@ -515,8 +515,8 @@ func TestRecordingEmitter_EventsWithKey(t *testing.T) { adds := e.EventsWithKey("ADD") require.Len(t, adds, 2) - assert.Equal(t, "a", adds[0].Data) - assert.Equal(t, "c", adds[1].Data) + assert.Equal(t, []any{"a"}, adds[0].Data) + assert.Equal(t, []any{"c"}, adds[1].Data) p1 := e.EventsWithKey("p1") assert.Len(t, p1, 2) @@ -528,7 +528,7 @@ func TestRecordingEmitter_WaitForEvent_Immediate(t *testing.T) { ev := e.WaitForEvent(t, "target", 100*time.Millisecond) assert.Equal(t, "target/event", ev.Key) - assert.Equal(t, "payload", ev.Data) + assert.Equal(t, []any{"payload"}, ev.Data) } func TestRecordingEmitter_WaitForEvent_Async(t *testing.T) { @@ -541,7 +541,7 @@ func TestRecordingEmitter_WaitForEvent_Async(t *testing.T) { ev := e.WaitForEvent(t, "async", 2*time.Second) assert.Equal(t, "async/event", ev.Key) - assert.Equal(t, "arrived", ev.Data) + assert.Equal(t, []any{"arrived"}, ev.Data) } func TestRecordingEmitter_WaitForNEvents(t *testing.T) { diff --git a/backend/pkg/plugin/settings/client.go b/backend/pkg/plugin/settings/client.go deleted file mode 100644 index ad09c6f7..00000000 --- a/backend/pkg/plugin/settings/client.go +++ /dev/null @@ -1,75 +0,0 @@ -package settings - -import ( - pkgsettings "github.com/omniviewdev/plugin-sdk/settings" -) - -// Service is the system/UI facing client for making settings requests to the settings controller. -type Service interface { - // ListPlugins returns a list of all the plugins that are registered with the settings controller - ListPlugins() ([]string, error) - - // Values returns a list of all of the values calculated in the current setting store - Values() map[string]any - - // PluginValues returns a list of all of the values calculated in the plugin's setting store - PluginValues(plugin string) map[string]any - - // ListSettings returns the settings store - ListSettings(plugin string) map[string]pkgsettings.Setting - - // GetSetting returns the setting by ID. This ID should be in the form of a dot separated string - // that represents the path to the setting. For example, "appearance.theme" - GetSetting(plugin, id string) (pkgsettings.Setting, error) - - // SetSetting sets the value of the setting by ID - SetSetting(plugin, id string, value any) error - - // SetSettings sets multiple settings at once - SetSettings(plugin string, settings map[string]any) error -} - -// TODO - I really do not like this. I wish we could just expose the interface to the IDE instead -// of having to manually embed the same controller into a struct and declare pointer recievers -// for each method. -// -// Currently a limitation of Wails it seems, unless I'm missing something. -type Client struct { - controller Controller -} - -func NewClient(controller Controller) *Client { - return &Client{ - controller: controller, - } -} - -var _ Service = (*Client)(nil) - -func (c *Client) Values() map[string]any { - return c.controller.Values() -} - -func (c *Client) PluginValues(plugin string) map[string]any { - return c.controller.PluginValues(plugin) -} - -func (c *Client) ListPlugins() ([]string, error) { - return c.controller.ListPlugins() -} - -func (c *Client) ListSettings(plugin string) map[string]pkgsettings.Setting { - return c.controller.ListSettings(plugin) -} - -func (c *Client) GetSetting(plugin, id string) (pkgsettings.Setting, error) { - return c.controller.GetSetting(plugin, id) -} - -func (c *Client) SetSetting(plugin, id string, value any) error { - return c.controller.SetSetting(plugin, id, value) -} - -func (c *Client) SetSettings(plugin string, settings map[string]any) error { - return c.controller.SetSettings(plugin, settings) -} diff --git a/backend/pkg/plugin/settings/controller.go b/backend/pkg/plugin/settings/controller.go index 5bf17fe3..16ff8487 100644 --- a/backend/pkg/plugin/settings/controller.go +++ b/backend/pkg/plugin/settings/controller.go @@ -6,6 +6,7 @@ import ( "fmt" "sync" + "github.com/wailsapp/wails/v3/pkg/application" pkgsettings "github.com/omniviewdev/plugin-sdk/settings" logging "github.com/omniviewdev/plugin-sdk/log" "go.opentelemetry.io/otel" @@ -25,11 +26,38 @@ const ( var tracer = otel.Tracer("omniview.settings") +// Service is the system/UI facing interface for making settings requests. +type Service interface { + // ListPlugins returns a list of all the plugins that are registered with the settings controller + ListPlugins() ([]string, error) + + // Values returns a list of all of the values calculated in the current setting store + Values() map[string]any + + // PluginValues returns a list of all of the values calculated in the plugin's setting store + PluginValues(plugin string) map[string]any + + // ListSettings returns the settings store + ListSettings(plugin string) map[string]pkgsettings.Setting + + // GetSetting returns the setting by ID. This ID should be in the form of a dot separated string + // that represents the path to the setting. For example, "appearance.theme" + GetSetting(plugin, id string) (pkgsettings.Setting, error) + + // SetSetting sets the value of the setting by ID + SetSetting(plugin, id string, value any) error + + // SetSettings sets multiple settings at once + SetSettings(plugin string, settings map[string]any) error +} + // Controller handles all requests to interface with the settings capabilities on installed plugins. // // This controller is embedded in the client IDE facing client. type Controller interface { internaltypes.Controller + ServiceStartup(ctx context.Context, options application.ServiceOptions) error + ServiceShutdown() error Service } @@ -52,6 +80,14 @@ func NewController(logger logging.Logger, sp pkgsettings.Provider) Controller { } } +func (c *controller) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + return nil +} + +func (c *controller) ServiceShutdown() error { + return nil +} + func (c *controller) OnPluginInit(pluginID string, meta config.PluginMeta) { logger := c.logger.With(logging.Any("pluginID", pluginID)) logger.Debugw(context.Background(), "OnPluginInit") diff --git a/backend/pkg/plugin/ui/client.go b/backend/pkg/plugin/ui/client.go deleted file mode 100644 index a61a5562..00000000 --- a/backend/pkg/plugin/ui/client.go +++ /dev/null @@ -1,52 +0,0 @@ -package ui - -type Client struct { - manager *componentManager -} - -func NewClient(manager *componentManager) *Client { - return &Client{ - manager: manager, - } -} - -type GetPluginComponentsInput struct { - Plugin string `json:"plugin"` -} - -// Get all the registered components for a plugin. -func (c *Client) GetPluginComponents( - params GetPluginComponentsInput, -) map[string][]ResourceComponent { - store := c.manager.GetResourceComponentStore() - return store.GetComponentsByResource(params.Plugin) -} - -type GetResourceComponentsInput struct { - Plugin string `json:"plugin"` - Resource string `json:"resource"` -} - -// Get all the registered components for a plugin's resource. -func (c *Client) GetResourceComponents(params GetResourceComponentsInput) []ResourceComponent { - store := c.manager.GetResourceComponentStore() - return store.GetComponentsForResource(params.Plugin, params.Resource) -} - -type GetResourceAreaComponentInput struct { - Plugin string `json:"plugin"` - Resource string `json:"resource"` - Area ResourceComponentArea `json:"area"` -} - -// Get the preferred component to display for the resource area. -func (c *Client) GetResourceAreaComponent(params GetResourceAreaComponentInput) *ResourceComponent { - store := c.manager.GetResourceComponentStore() - components := store.GetComponentsForResource(params.Plugin, params.Resource) - for _, component := range components { - if component.Area == params.Area { - return &component - } - } - return nil -} diff --git a/backend/pkg/plugin/ui/manager.go b/backend/pkg/plugin/ui/manager.go index b23f8bb8..ae1085aa 100644 --- a/backend/pkg/plugin/ui/manager.go +++ b/backend/pkg/plugin/ui/manager.go @@ -3,6 +3,7 @@ package ui import ( "context" + "github.com/wailsapp/wails/v3/pkg/application" logging "github.com/omniviewdev/plugin-sdk/log" "github.com/omniviewdev/omniview/backend/pkg/plugin/types" @@ -16,6 +17,38 @@ type componentManager struct { resourceComponentStore ResourceComponentStore } +// ServiceWrapper exposes only frontend-safe methods of componentManager. +// Internal plugin lifecycle methods (OnPluginInit, OnPluginStart, etc.) +// are excluded to prevent frontend invocation. +type ServiceWrapper struct { + cm *componentManager +} + +// NewServiceWrapper creates a ServiceWrapper around a componentManager. +func NewServiceWrapper(cm *componentManager) *ServiceWrapper { + return &ServiceWrapper{cm: cm} +} + +func (s *ServiceWrapper) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + return s.cm.ServiceStartup(ctx, options) +} + +func (s *ServiceWrapper) ServiceShutdown() error { + return s.cm.ServiceShutdown() +} + +func (s *ServiceWrapper) GetPluginComponents(params GetPluginComponentsInput) map[string][]ResourceComponent { + return s.cm.GetPluginComponents(params) +} + +func (s *ServiceWrapper) GetResourceComponents(params GetResourceComponentsInput) []ResourceComponent { + return s.cm.GetResourceComponents(params) +} + +func (s *ServiceWrapper) GetResourceAreaComponent(params GetResourceAreaComponentInput) *ResourceComponent { + return s.cm.GetResourceAreaComponent(params) +} + func NewComponentManager(logger logging.Logger) *componentManager { return &componentManager{ logger: logger.Named("ComponentManager"), @@ -23,6 +56,14 @@ func NewComponentManager(logger logging.Logger) *componentManager { } } +func (cm *componentManager) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + return nil +} + +func (cm *componentManager) ServiceShutdown() error { + return nil +} + var _ types.PluginManager = (*componentManager)(nil) func (cm *componentManager) OnPluginInit(_ context.Context, pluginID string, meta config.PluginMeta) error { @@ -78,6 +119,49 @@ func (cm *componentManager) GetResourceComponentStore() ResourceComponentStore { return cm.resourceComponentStore } +// =========================== Service methods (formerly in client.go) =========================== // + +type GetPluginComponentsInput struct { + Plugin string `json:"plugin"` +} + +// GetPluginComponents returns all the registered components for a plugin. +func (cm *componentManager) GetPluginComponents( + params GetPluginComponentsInput, +) map[string][]ResourceComponent { + store := cm.GetResourceComponentStore() + return store.GetComponentsByResource(params.Plugin) +} + +type GetResourceComponentsInput struct { + Plugin string `json:"plugin"` + Resource string `json:"resource"` +} + +// GetResourceComponents returns all the registered components for a plugin's resource. +func (cm *componentManager) GetResourceComponents(params GetResourceComponentsInput) []ResourceComponent { + store := cm.GetResourceComponentStore() + return store.GetComponentsForResource(params.Plugin, params.Resource) +} + +type GetResourceAreaComponentInput struct { + Plugin string `json:"plugin"` + Resource string `json:"resource"` + Area ResourceComponentArea `json:"area"` +} + +// GetResourceAreaComponent returns the preferred component to display for the resource area. +func (cm *componentManager) GetResourceAreaComponent(params GetResourceAreaComponentInput) *ResourceComponent { + store := cm.GetResourceComponentStore() + components := store.GetComponentsForResource(params.Plugin, params.Resource) + for _, component := range components { + if component.Area == params.Area { + return &component + } + } + return nil +} + // =========================== Handlers =========================== // func loadResourceComponents(meta config.PluginMeta) []ResourceComponent { diff --git a/backend/pkg/plugin/utils/client.go b/backend/pkg/plugin/utils/client.go index 6cabac48..08ef650b 100644 --- a/backend/pkg/plugin/utils/client.go +++ b/backend/pkg/plugin/utils/client.go @@ -1,10 +1,12 @@ package utils import ( + "context" "encoding/json" "log" "github.com/go-enry/go-enry/v2" + "github.com/wailsapp/wails/v3/pkg/application" "gopkg.in/yaml.v3" ) @@ -14,6 +16,14 @@ func NewClient() *Client { return &Client{} } +func (c *Client) ServiceStartup(_ context.Context, _ application.ServiceOptions) error { + return nil +} + +func (c *Client) ServiceShutdown() error { + return nil +} + type GetLanguageInput struct { Filename string `json:"filename"` Contents string `json:"contents"` diff --git a/backend/window/manager.go b/backend/window/manager.go new file mode 100644 index 00000000..e62de2d6 --- /dev/null +++ b/backend/window/manager.go @@ -0,0 +1,74 @@ +// Package window provides window lifecycle management for the application. +package window + +import ( + "github.com/wailsapp/wails/v3/pkg/application" + "github.com/wailsapp/wails/v3/pkg/events" +) + +// Manager manages the application's windows, including the main window +// and any secondary windows such as settings or devtools. +type Manager struct { + app *application.App +} + +// NewManager creates a new window Manager. It registers a hide-on-close hook +// on the provided main window so that closing the main window hides it +// instead of quitting the application. +func NewManager(app *application.App, mainWindow *application.WebviewWindow) *Manager { + m := &Manager{app: app} + m.registerMainWindowHideOnClose(mainWindow) + return m +} + +// Main returns the main application window by looking it up by name. +func (m *Manager) Main() *application.WebviewWindow { + w, ok := m.app.Window.GetByName("main") + if !ok { + return nil + } + ww, _ := w.(*application.WebviewWindow) + return ww +} + +// registerMainWindowHideOnClose hooks the WindowClosing event on the main +// window so that it hides instead of closing. This prevents the application +// from quitting when the user closes the main window. +func (m *Manager) registerMainWindowHideOnClose(w *application.WebviewWindow) { + w.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { + e.Cancel() + w.Hide() + }) +} + +// OpenSettings creates and shows a new settings window. The window uses +// normal close behavior — it is destroyed when closed. +func (m *Manager) OpenSettings() *application.WebviewWindow { + w := m.app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "settings", + Title: "Settings — Omniview", + URL: "/#/settings", + Width: 900, + Height: 700, + UseApplicationMenu: true, + }) + w.Show() + w.Focus() + return w +} + +// OpenDevtools creates and shows a new devtools window. The window uses +// normal close behavior — it is destroyed when closed. +func (m *Manager) OpenDevtools() *application.WebviewWindow { + w := m.app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "devtools", + Title: "DevTools — Omniview", + URL: "/#/devtools", + Width: 1200, + Height: 800, + UseApplicationMenu: true, + }) + w.Show() + w.Focus() + return w +} diff --git a/build/Taskfile.yml b/build/Taskfile.yml new file mode 100644 index 00000000..78cea8c5 --- /dev/null +++ b/build/Taskfile.yml @@ -0,0 +1,76 @@ +version: '3' + +tasks: + go:mod:tidy: + summary: Runs `go mod tidy` + internal: true + cmds: + - go mod tidy + + install:frontend:deps: + summary: Install frontend dependencies + dir: "{{.ROOT_DIR}}" + sources: + - package.json + - pnpm-lock.yaml + generates: + - node_modules/.pnpm/lock.yaml + cmds: + - pnpm install + + build:frontend: + label: build:frontend (DEV={{.DEV}}) + summary: Build the frontend project + dir: "{{.ROOT_DIR}}" + deps: + - task: install:frontend:deps + - task: generate:bindings + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + cmds: + - pnpm run {{.BUILD_COMMAND}} + env: + PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}' + vars: + BUILD_COMMAND: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}' + + generate:bindings: + label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}}) + summary: Generates bindings for the frontend + dir: "{{.ROOT_DIR}}" + deps: + - task: go:mod:tidy + sources: + - "**/*.go" + - go.mod + - go.sum + generates: + - packages/omniviewdev-runtime/src/bindings/**/* + cmds: + - GOWORK=off wails3 generate bindings -d packages/omniviewdev-runtime/src/bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts + + generate:icons: + summary: Generates platform icons from appicon.png + dir: build + sources: + - "appicon.png" + generates: + - "darwin/icons.icns" + - "windows/icon.ico" + cmds: + - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico + + dev:frontend: + summary: Runs the frontend in development mode + dir: "{{.ROOT_DIR}}" + deps: + - task: install:frontend:deps + cmds: + - pnpm exec vite --port {{.VITE_PORT}} --strictPort + + update:build-assets: + summary: Updates the build assets + dir: build + cmds: + - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir . diff --git a/build/config.yml b/build/config.yml new file mode 100644 index 00000000..194aa256 --- /dev/null +++ b/build/config.yml @@ -0,0 +1,46 @@ +version: '3' + +info: + companyName: "Omniview" + productName: "Omniview" + productIdentifier: "dev.omniview.app" + description: "A unified infrastructure management platform" + copyright: "(c) 2025, Omniview" + comments: "Omniview Desktop Application" + version: "0.0.1" + +dev_mode: + root_path: . + log_level: warn + debounce: 1000 + ignore: + dir: + - .git + - node_modules + - ui + - bin + - dist + - .task + - e2e + - packages + file: + - .DS_Store + - .gitignore + - .gitkeep + watched_extension: + - "*.go" + git_ignore: true + executes: + - cmd: wails3 build DEV=true + type: blocking + - cmd: wails3 task common:dev:frontend + type: background + - cmd: wails3 task run + type: primary + +fileAssociations: + - ext: icns + name: favicon + description: AppIcon + iconName: fileIcon + role: Editor diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist index 6763d1b4..0f95fca2 100644 --- a/build/darwin/Info.dev.plist +++ b/build/darwin/Info.dev.plist @@ -1,68 +1,61 @@ + - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.Name}} - CFBundleIdentifier - com.wails.{{.Name}} - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.omniview.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - NSAppTransportSecurity - - NSAllowsLocalNetworking - - - - + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + icns + + CFBundleTypeIconFile + fileIcon + CFBundleTypeName + favicon + CFBundleTypeRole + Editor + + + CFBundleExecutable + Omniview + CFBundleGetInfoString + Omniview Desktop Application + CFBundleIconFile + icons + CFBundleIdentifier + dev.omniview.app + CFBundleName + Omniview + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.1 + CFBundleURLTypes + + + CFBundleTypeRole + {{.Role}} + CFBundleURLName + com.omniview.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + + + CFBundleVersion + 0.0.1 + LSMinimumSystemVersion + 10.15.0 + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2025, Omniview + + \ No newline at end of file diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist index db05ad41..1acf7160 100644 --- a/build/darwin/Info.plist +++ b/build/darwin/Info.plist @@ -1,63 +1,43 @@ + - - CFBundlePackageType - APPL - CFBundleName - {{.Info.ProductName}} - CFBundleExecutable - {{.Name}} - CFBundleIdentifier - com.omniview.omniview - CFBundleVersion - {{.Info.ProductVersion}} - CFBundleGetInfoString - {{.Info.Comments}} - CFBundleShortVersionString - {{.Info.ProductVersion}} - CFBundleIconFile - iconfile - LSMinimumSystemVersion - 10.13.0 - NSHighResolutionCapable - true - NSHumanReadableCopyright - {{.Info.Copyright}} - {{if .Info.FileAssociations}} - CFBundleDocumentTypes - - {{range .Info.FileAssociations}} - - CFBundleTypeExtensions - - {{.Ext}} - - CFBundleTypeName - {{.Name}} - CFBundleTypeRole - {{.Role}} - CFBundleTypeIconFile - {{.IconName}} - - {{end}} - - {{end}} - {{if .Info.Protocols}} - CFBundleURLTypes - - {{range .Info.Protocols}} - - CFBundleURLName - com.omniview.{{.Scheme}} - CFBundleURLSchemes - - {{.Scheme}} - - CFBundleTypeRole - {{.Role}} - - {{end}} - - {{end}} - - + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + icns + + CFBundleTypeIconFile + fileIcon + CFBundleTypeName + favicon + CFBundleTypeRole + Editor + + + CFBundleExecutable + Omniview + CFBundleGetInfoString + Omniview Desktop Application + CFBundleIconFile + icons + CFBundleIdentifier + dev.omniview.app + CFBundleName + Omniview + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.1 + CFBundleVersion + 0.0.1 + LSMinimumSystemVersion + 10.15.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2025, Omniview + + \ No newline at end of file diff --git a/build/darwin/Taskfile.yml b/build/darwin/Taskfile.yml new file mode 100644 index 00000000..7f4dcc64 --- /dev/null +++ b/build/darwin/Taskfile.yml @@ -0,0 +1,95 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +vars: + SIGN_IDENTITY: "Developer ID Application: Joshua Pare (696AD8J8ZT)" + ENTITLEMENTS: "build/darwin/entitlements.plist" + # KEYCHAIN_PROFILE: "my-notarize-profile" + +tasks: + build: + summary: Builds the application + cmds: + - task: build:native + vars: + DEV: '{{.DEV}}' + + build:native: + summary: Builds the application natively on macOS + internal: true + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + DEV: + ref: .DEV + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} + vars: + BUILD_FLAGS: '{{if eq .DEV "true"}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + env: + GOOS: darwin + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default ARCH}}' + CGO_CFLAGS: "-mmacosx-version-min=10.15" + CGO_LDFLAGS: "-mmacosx-version-min=10.15" + MACOSX_DEPLOYMENT_TARGET: "10.15" + + package: + summary: Packages the application into a `.app` bundle + deps: + - task: build + cmds: + - task: create:app:bundle + + create:app:bundle: + summary: Creates an `.app` bundle + cmds: + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources" + - cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources" + - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS" + - cp build/darwin/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents" + - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app" + + run: + cmds: + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS" + - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources" + - | + if [ -f build/darwin/icons.icns ]; then + cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources" + fi + - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS" + - cp "build/darwin/Info.dev.plist" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Info.plist" + - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app" + - '"{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS/{{.APP_NAME}}"' + + sign: + summary: Signs the application bundle with Developer ID + deps: + - task: package + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}} + preconditions: + - sh: '[ -n "{{.SIGN_IDENTITY}}" ]' + msg: "SIGN_IDENTITY is required." + + sign:notarize: + summary: Signs and notarizes the application bundle + deps: + - task: package + cmds: + - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}} --notarize --keychain-profile {{.KEYCHAIN_PROFILE}} + preconditions: + - sh: '[ -n "{{.SIGN_IDENTITY}}" ]' + msg: "SIGN_IDENTITY is required." + - sh: '[ -n "{{.KEYCHAIN_PROFILE}}" ]' + msg: "KEYCHAIN_PROFILE is required." diff --git a/build/darwin/icons.icns b/build/darwin/icons.icns new file mode 100644 index 00000000..331200a5 Binary files /dev/null and b/build/darwin/icons.icns differ diff --git a/build/ios/Assets.xcassets b/build/ios/Assets.xcassets new file mode 100644 index 00000000..46fbb878 --- /dev/null +++ b/build/ios/Assets.xcassets @@ -0,0 +1,116 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "images" : [ + { + "filename" : "icon-20@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "icon-29@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "icon-40@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "icon-60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "icon-60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "icon-20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "icon-20@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "icon-29@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-40.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "icon-40@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "icon-76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "icon-83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "icon-1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ] +} \ No newline at end of file diff --git a/build/ios/Info.dev.plist b/build/ios/Info.dev.plist new file mode 100644 index 00000000..de6613d7 --- /dev/null +++ b/build/ios/Info.dev.plist @@ -0,0 +1,62 @@ + + + + + CFBundleExecutable + Omniview + CFBundleIdentifier + dev.omniview.app.dev + CFBundleName + Omniview (Dev) + CFBundleDisplayName + Omniview (Dev) + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.1-dev + CFBundleVersion + 0.0.1 + LSRequiresIPhoneOS + + MinimumOSVersion + 15.0 + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + + WailsDevelopmentMode + + + NSHumanReadableCopyright + (c) 2025, Omniview + + + CFBundleGetInfoString + Omniview Desktop Application + + + \ No newline at end of file diff --git a/build/ios/Info.plist b/build/ios/Info.plist new file mode 100644 index 00000000..51b10eb2 --- /dev/null +++ b/build/ios/Info.plist @@ -0,0 +1,59 @@ + + + + + CFBundleExecutable + Omniview + CFBundleIdentifier + dev.omniview.app + CFBundleName + Omniview + CFBundleDisplayName + Omniview + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.0.1 + CFBundleVersion + 0.0.1 + LSRequiresIPhoneOS + + MinimumOSVersion + 15.0 + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + + NSHumanReadableCopyright + (c) 2025, Omniview + + + CFBundleGetInfoString + Omniview Desktop Application + + + \ No newline at end of file diff --git a/build/ios/LaunchScreen.storyboard b/build/ios/LaunchScreen.storyboard new file mode 100644 index 00000000..436ad88d --- /dev/null +++ b/build/ios/LaunchScreen.storyboard @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/ios/build.sh b/build/ios/build.sh new file mode 100644 index 00000000..df8c2041 --- /dev/null +++ b/build/ios/build.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Build configuration +APP_NAME="Omniview" +BUNDLE_ID="dev.omniview.app" +VERSION="0.0.1" +BUILD_NUMBER="0.0.1" +BUILD_DIR="build/ios" +TARGET="simulator" + +echo "Building iOS app: $APP_NAME" +echo "Bundle ID: $BUNDLE_ID" +echo "Version: $VERSION ($BUILD_NUMBER)" +echo "Target: $TARGET" + +# Ensure build directory exists +mkdir -p "$BUILD_DIR" + +# Determine SDK and target architecture +if [ "$TARGET" = "simulator" ]; then + SDK="iphonesimulator" + ARCH="arm64-apple-ios15.0-simulator" +elif [ "$TARGET" = "device" ]; then + SDK="iphoneos" + ARCH="arm64-apple-ios15.0" +else + echo "Unknown target: $TARGET" + exit 1 +fi + +# Get SDK path +SDK_PATH=$(xcrun --sdk $SDK --show-sdk-path) + +# Compile the application +echo "Compiling with SDK: $SDK" +xcrun -sdk $SDK clang \ + -target $ARCH \ + -isysroot "$SDK_PATH" \ + -framework Foundation \ + -framework UIKit \ + -framework WebKit \ + -framework CoreGraphics \ + -o "$BUILD_DIR/$APP_NAME" \ + "$BUILD_DIR/main.m" + +# Create app bundle +echo "Creating app bundle..." +APP_BUNDLE="$BUILD_DIR/$APP_NAME.app" +rm -rf "$APP_BUNDLE" +mkdir -p "$APP_BUNDLE" + +# Move executable +mv "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/" + +# Copy Info.plist +cp "$BUILD_DIR/Info.plist" "$APP_BUNDLE/" + +# Sign the app +echo "Signing app..." +codesign --force --sign - "$APP_BUNDLE" + +echo "Build complete: $APP_BUNDLE" + +# Deploy to simulator if requested +if [ "$TARGET" = "simulator" ]; then + echo "Deploying to simulator..." + xcrun simctl terminate booted "$BUNDLE_ID" 2>/dev/null || true + xcrun simctl install booted "$APP_BUNDLE" + xcrun simctl launch booted "$BUNDLE_ID" + echo "App launched on simulator" +fi \ No newline at end of file diff --git a/build/ios/entitlements.plist b/build/ios/entitlements.plist new file mode 100644 index 00000000..cc5d9582 --- /dev/null +++ b/build/ios/entitlements.plist @@ -0,0 +1,21 @@ + + + + + + get-task-allow + + + + com.apple.security.app-sandbox + + + + com.apple.security.network.client + + + + com.apple.security.files.user-selected.read-only + + + \ No newline at end of file diff --git a/build/ios/project.pbxproj b/build/ios/project.pbxproj new file mode 100644 index 00000000..1cfb6665 --- /dev/null +++ b/build/ios/project.pbxproj @@ -0,0 +1,222 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = {}; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + C0DEBEEF0000000000000001 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000002 /* main.m */; }; + C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000101 /* UIKit.framework */; }; + C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000102 /* Foundation.framework */; }; + C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000103 /* WebKit.framework */; }; + C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000104 /* Security.framework */; }; + C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000105 /* CoreFoundation.framework */; }; + C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000106 /* libresolv.tbd */; }; + C0DEBEEF00000000000000F7 /* Omniview.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000107 /* Omniview.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + C0DEBEEF0000000000000002 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + C0DEBEEF0000000000000003 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C0DEBEEF0000000000000004 /* Omniview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Omniview.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + C0DEBEEF0000000000000101 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000102 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000103 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000104 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000105 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000106 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.text-based-dylib-definition; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; + C0DEBEEF0000000000000107 /* Omniview.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "Omniview.a"; path = ../../../bin/Omniview.a; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + C0DEBEEF0000000000000010 = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000020 /* Products */, + C0DEBEEF0000000000000045 /* Frameworks */, + C0DEBEEF0000000000000030 /* main */, + ); + sourceTree = ""; + }; + C0DEBEEF0000000000000020 /* Products */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000004 /* Omniview.app */, + ); + name = Products; + sourceTree = ""; + }; + C0DEBEEF0000000000000030 /* main */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000002 /* main.m */, + C0DEBEEF0000000000000003 /* Info.plist */, + ); + path = main; + sourceTree = SOURCE_ROOT; + }; + C0DEBEEF0000000000000045 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C0DEBEEF0000000000000101 /* UIKit.framework */, + C0DEBEEF0000000000000102 /* Foundation.framework */, + C0DEBEEF0000000000000103 /* WebKit.framework */, + C0DEBEEF0000000000000104 /* Security.framework */, + C0DEBEEF0000000000000105 /* CoreFoundation.framework */, + C0DEBEEF0000000000000106 /* libresolv.tbd */, + C0DEBEEF0000000000000107 /* Omniview.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + C0DEBEEF0000000000000040 /* Omniview */ = { + isa = PBXNativeTarget; + buildConfigurationList = C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "Omniview" */; + buildPhases = ( + C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */, + C0DEBEEF0000000000000050 /* Sources */, + C0DEBEEF0000000000000056 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Omniview"; + productName = "Omniview"; + productReference = C0DEBEEF0000000000000004 /* Omniview.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C0DEBEEF0000000000000060 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1500; + ORGANIZATIONNAME = "Omniview"; + TargetAttributes = { + C0DEBEEF0000000000000040 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */; + compatibilityVersion = "Xcode 15.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = C0DEBEEF0000000000000010; + productRefGroup = C0DEBEEF0000000000000020 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C0DEBEEF0000000000000040 /* Omniview */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXFrameworksBuildPhase section */ + C0DEBEEF0000000000000056 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C0DEBEEF00000000000000F7 /* Omniview.a in Frameworks */, + C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */, + C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */, + C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */, + C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */, + C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */, + C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Prebuild: Wails Go Archive"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\nAPP_ROOT=\"${PROJECT_DIR}/../../..\"\nSDK_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)\nexport GOOS=ios\nexport GOARCH=arm64\nexport CGO_ENABLED=1\nexport CGO_CFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0\"\nexport CGO_LDFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator\"\ncd \"${APP_ROOT}\"\n# Ensure overlay exists\nif [ ! -f build/ios/xcode/overlay.json ]; then\n wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml || true\nfi\n# Build Go c-archive if missing or older than sources\nif [ ! -f bin/Omniview.a ]; then\n echo \"Building Go c-archive...\"\n go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json -o bin/Omniview.a\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + C0DEBEEF0000000000000050 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C0DEBEEF0000000000000001 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C0DEBEEF0000000000000090 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = main/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = "dev.omniview.app"; + PRODUCT_NAME = "Omniview"; + CODE_SIGNING_ALLOWED = NO; + SDKROOT = iphonesimulator; + }; + name = Debug; + }; + C0DEBEEF00000000000000A0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = main/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + PRODUCT_BUNDLE_IDENTIFIER = "dev.omniview.app"; + PRODUCT_NAME = "Omniview"; + CODE_SIGNING_ALLOWED = NO; + SDKROOT = iphonesimulator; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "Omniview" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0DEBEEF0000000000000090 /* Debug */, + C0DEBEEF00000000000000A0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C0DEBEEF0000000000000090 /* Debug */, + C0DEBEEF00000000000000A0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = C0DEBEEF0000000000000060 /* Project object */; +} diff --git a/build/linux/Taskfile.yml b/build/linux/Taskfile.yml new file mode 100644 index 00000000..a80e13bb --- /dev/null +++ b/build/linux/Taskfile.yml @@ -0,0 +1,44 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Linux + cmds: + - task: build:native + vars: + DEV: '{{.DEV}}' + + build:native: + summary: Builds the application natively on Linux + internal: true + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + DEV: + ref: .DEV + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} + vars: + BUILD_FLAGS: '{{if eq .DEV "true"}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + env: + GOOS: linux + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default ARCH}}' + + package: + summary: Packages the application for Linux + deps: + - task: build + + run: + cmds: + - '{{.BIN_DIR}}/{{.APP_NAME}}' diff --git a/build/linux/desktop b/build/linux/desktop new file mode 100644 index 00000000..40b2e2c5 --- /dev/null +++ b/build/linux/desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=1.0 +Name=Omniview +Comment=A unified infrastructure management platform +# The Exec line includes %u to pass the URL to the application +Exec=/usr/local/bin/Omniview %u +Terminal=false +Type=Application +Icon=Omniview +Categories=Utility; +StartupWMClass=Omniview + + diff --git a/build/linux/nfpm/nfpm.yaml b/build/linux/nfpm/nfpm.yaml new file mode 100644 index 00000000..e16b252b --- /dev/null +++ b/build/linux/nfpm/nfpm.yaml @@ -0,0 +1,67 @@ +# Feel free to remove those if you don't want/need to use them. +# Make sure to check the documentation at https://nfpm.goreleaser.com +# +# The lines below are called `modelines`. See `:help modeline` + +name: "Omniview" +arch: ${GOARCH} +platform: "linux" +version: "0.0.1" +section: "default" +priority: "extra" +maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> +description: "A unified infrastructure management platform" +vendor: "Omniview" +homepage: "https://wails.io" +license: "MIT" +release: "1" + +contents: + - src: "./bin/Omniview" + dst: "/usr/local/bin/Omniview" + - src: "./build/appicon.png" + dst: "/usr/share/icons/hicolor/128x128/apps/Omniview.png" + - src: "./build/linux/Omniview.desktop" + dst: "/usr/share/applications/Omniview.desktop" + +# Default dependencies for Debian 12/Ubuntu 22.04+ with WebKit 4.1 +depends: + - libgtk-3-0 + - libwebkit2gtk-4.1-0 + +# Distribution-specific overrides for different package formats and WebKit versions +overrides: + # RPM packages for RHEL/CentOS/AlmaLinux/Rocky Linux (WebKit 4.0) + rpm: + depends: + - gtk3 + - webkit2gtk4.1 + + # Arch Linux packages (WebKit 4.1) + archlinux: + depends: + - gtk3 + - webkit2gtk-4.1 + +# scripts section to ensure desktop database is updated after install +scripts: + postinstall: "./build/linux/nfpm/scripts/postinstall.sh" + # You can also add preremove, postremove if needed + # preremove: "./build/linux/nfpm/scripts/preremove.sh" + # postremove: "./build/linux/nfpm/scripts/postremove.sh" + +# replaces: +# - foobar +# provides: +# - bar +# depends: +# - gtk3 +# - libwebkit2gtk +# recommends: +# - whatever +# suggests: +# - something-else +# conflicts: +# - not-foo +# - not-bar +# changelog: "changelog.yaml" diff --git a/build/windows/Taskfile.yml b/build/windows/Taskfile.yml new file mode 100644 index 00000000..4a3ef79e --- /dev/null +++ b/build/windows/Taskfile.yml @@ -0,0 +1,42 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Windows + cmds: + - task: build:native + vars: + DEV: '{{.DEV}}' + + build:native: + summary: Builds the application using native Go cross-compilation + internal: true + deps: + - task: common:go:mod:tidy + - task: common:build:frontend + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + DEV: + ref: .DEV + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o "{{.BIN_DIR}}/{{.APP_NAME}}.exe" + vars: + BUILD_FLAGS: '{{if eq .DEV "true"}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{end}}' + env: + GOOS: windows + CGO_ENABLED: 0 + GOARCH: '{{.ARCH | default ARCH}}' + + package: + summary: Packages the application for Windows + deps: + - task: build + + run: + cmds: + - '{{.BIN_DIR}}/{{.APP_NAME}}.exe' diff --git a/build/windows/icon.ico b/build/windows/icon.ico index f3347984..19a7e345 100644 Binary files a/build/windows/icon.ico and b/build/windows/icon.ico differ diff --git a/build/windows/info.json b/build/windows/info.json index 9727946b..f0a5ce9d 100644 --- a/build/windows/info.json +++ b/build/windows/info.json @@ -1,15 +1,15 @@ { "fixed": { - "file_version": "{{.Info.ProductVersion}}" + "file_version": "0.0.1" }, "info": { "0000": { - "ProductVersion": "{{.Info.ProductVersion}}", - "CompanyName": "{{.Info.CompanyName}}", - "FileDescription": "{{.Info.ProductName}}", - "LegalCopyright": "{{.Info.Copyright}}", - "ProductName": "{{.Info.ProductName}}", - "Comments": "{{.Info.Comments}}" + "ProductVersion": "0.0.1", + "CompanyName": "Omniview", + "FileDescription": "A unified infrastructure management platform", + "LegalCopyright": "(c) 2025, Omniview", + "ProductName": "Omniview", + "Comments": "Omniview Desktop Application" } } } \ No newline at end of file diff --git a/build/windows/nsis/wails_tools.nsh b/build/windows/nsis/wails_tools.nsh new file mode 100644 index 00000000..1ca46815 --- /dev/null +++ b/build/windows/nsis/wails_tools.nsh @@ -0,0 +1,242 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "Omniview" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "Omniview" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "Omniview" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "0.0.1" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "(c) 2025, Omniview" +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +!macro wails.setShellContext + ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" + SetShellVarContext all + ${else} + SetShellVarContext current + ${EndIf} +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + + !insertmacro APP_ASSOCIATE "icns" "favicon" "AppIcon" "$INSTDIR\fileIcon.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + File "..\fileIcon.ico" + +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + + !insertmacro APP_UNASSOCIATE "icns" "favicon" + Delete "$INSTDIR\fileIcon.ico" + +!macroend + +!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" +!macroend + +!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" +!macroend + +!macro wails.associateCustomProtocols + ; Create custom protocols associations + +!macroend + +!macro wails.unassociateCustomProtocols + ; Delete app custom protocol associations + +!macroend \ No newline at end of file diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest index 17e1a238..696bf7ba 100644 --- a/build/windows/wails.exe.manifest +++ b/build/windows/wails.exe.manifest @@ -1,6 +1,6 @@ - + @@ -12,4 +12,11 @@ permonitorv2,permonitor + + + + + + + \ No newline at end of file diff --git a/docs/superpowers/plans/2026-03-20-wails3-migration.md b/docs/superpowers/plans/2026-03-20-wails3-migration.md new file mode 100644 index 00000000..686ed4c0 --- /dev/null +++ b/docs/superpowers/plans/2026-03-20-wails3-migration.md @@ -0,0 +1,1428 @@ +# Wails v3 Migration Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Migrate the Omniview desktop application from Wails v2 (v2.11.0) to Wails v3, converting 17 bound structs to services, eliminating 394+ context references, updating the event system, migrating frontend bindings, and replacing the Makefile/wails.json build system with Taskfile. + +**Architecture:** Outside-in migration — stand up the v3 app shell first (entry point, window, build system, asset middleware, menus), then migrate the event system, then convert services one at a time starting with the resource controller as the proving ground. Each phase has a verification checkpoint. + +**Tech Stack:** Go 1.26, Wails v3 (`github.com/wailsapp/wails/v3`), React 19, TypeScript 5.8, Vite 6, `@wailsio/runtime`, pnpm, Taskfile (go-task) + +**Testing:** All test code MUST use `github.com/stretchr/testify` (`assert` and `require` sub-packages). Do not use raw `t.Fatalf`, `t.Errorf`, or `if != expected` patterns. The codebase has 13 test files with inconsistent raw assertions — if any of these files are modified during migration, convert their assertions to testify. + +**Spec:** `docs/superpowers/specs/2026-03-20-wails3-migration-design.md` + +**Wails v3 API References:** Located at `~/.claude/skills/wails-v3-migrator/references/` — consult `api-application.md`, `api-windows.md`, `api-events.md`, `api-menus.md`, `api-frontend-runtime.md`, `api-build-system.md`, and `api-platform-options.md` for exact API signatures when implementing each task. + +--- + +## File Structure + +### Files to Create + +``` +Taskfile.yml # Root build orchestrator (dev, build, package, run, check) +build/config.yml # Project metadata, dev mode config (replaces wails.json) +build/Taskfile.yml # Common tasks (frontend build, bindings, icons) +build/darwin/Taskfile.yml # macOS build/package/sign/notarize +build/darwin/Info.plist # macOS app metadata +build/windows/Taskfile.yml # Windows build/package +build/windows/info.json # Windows app metadata +build/linux/Taskfile.yml # Linux build/package +backend/menus/app.go # v3 application menu (replaces menus.go + view.go) +backend/menus/keybindings.go # Standalone key bindings +backend/menus/context.go # Go-side context menu definitions +backend/window/manager.go # WindowManager helper +``` + +### Files to Modify + +``` +main.go # Complete rewrite: application.New() + app.Run() +app.go # Rewrite: AppService with dialog builders, remove ctx +fileloader.go # Rename to plugin_asset_handler.go, remove http.Handler embed +go.mod # wails/v2 -> wails/v3 dependency +vite.config.ts # Add @wailsio/runtime/plugins/vite plugin +package.json # Add @wailsio/runtime dependency +.gitignore # Add .task + +backend/pkg/plugin/events.go # Remove eventEmitFn, update emitEvent +backend/pkg/plugin/resource/emitter.go # v3 EventEmitter interface (drop ctx) +backend/pkg/plugin/resource/testutil_test.go # Update recordingEmitter signature +backend/pkg/plugin/resource/emitter_test.go # Update interface tests +backend/pkg/plugin/resource/controller.go # Run() -> ServiceStartup(), add app field +backend/pkg/plugin/resource/client.go # DELETE (collapse into controller) +backend/pkg/plugin/exec/controller.go # Replace ctx with app, EventsEmit -> emitter +backend/pkg/plugin/exec/client.go # DELETE +backend/pkg/plugin/logs/controller.go # Replace ctx with app, EventsEmit -> emitter +backend/pkg/plugin/logs/client.go # DELETE +backend/pkg/plugin/metric/controller.go # Replace ctx with app +backend/pkg/plugin/metric/client.go # DELETE +backend/pkg/plugin/networker/controller.go # Replace ctx with app +backend/pkg/plugin/networker/client.go # DELETE +backend/pkg/plugin/settings/controller.go # Add ServiceStartup +backend/pkg/plugin/settings/client.go # DELETE +backend/pkg/plugin/data/controller.go # Add ServiceStartup +backend/pkg/plugin/data/client.go # DELETE +backend/pkg/plugin/ui/client.go # DELETE (merge into manager) +backend/pkg/plugin/utils/client.go # Add ServiceStartup +backend/pkg/plugin/manager.go # Replace ctx with app, ServiceStartup/Shutdown +backend/pkg/plugin/installer.go # Remove wails/v2/pkg/runtime import, update event calls +backend/pkg/plugin/devserver/manager.go # Replace ctx with app, ServiceStartup/Shutdown +backend/pkg/plugin/pluginlog/pluginlog.go # Update OnEmit callback pattern for v3 +backend/diagnostics/logger.go # Replace runtime.EventsEmit with emitter + +packages/omniviewdev-runtime/src/api.ts # Update binding paths +packages/omniviewdev-runtime/src/runtime.ts # Re-export @wailsio/runtime +packages/omniviewdev-runtime/package.json # Add @wailsio/runtime dep, update exports +``` + +### Files to Delete + +``` +wails.json # Replaced by build/config.yml + Taskfile.yml +Makefile # Replaced by Taskfile.yml +backend/menus/menus.go # Replaced by backend/menus/app.go +backend/menus/view.go # Merged into backend/menus/app.go +packages/omniviewdev-runtime/src/wailsjs/ # Entire directory (replaced by bindings/) +``` + +--- + +## Task 1: Install Wails v3 CLI and go-task + +**Files:** +- None (tooling setup) + +- [ ] **Step 1: Install Wails v3 CLI** + +```bash +go install github.com/wailsapp/wails/v3/cmd/wails3@latest +``` + +Verify: `wails3 version` prints version info. + +- [ ] **Step 2: Install go-task** + +```bash +go install github.com/go-task/task/v3/cmd/task@latest +``` + +Verify: `task --version` prints version info. + +- [ ] **Step 3: Install @wailsio/runtime npm package** + +```bash +pnpm add @wailsio/runtime +``` + +Verify: `pnpm ls @wailsio/runtime` shows installed version. + +--- + +## Task 2: Create Taskfile build system + +**Files:** +- Create: `Taskfile.yml` +- Create: `build/config.yml` +- Create: `build/Taskfile.yml` +- Create: `build/darwin/Taskfile.yml` +- Create: `build/darwin/Info.plist` +- Create: `build/windows/Taskfile.yml` +- Create: `build/windows/info.json` +- Create: `build/linux/Taskfile.yml` +- Modify: `.gitignore` + +Reference `~/.claude/skills/wails-v3-migrator/references/api-build-system.md` for the complete Taskfile structure, config.yml format, and platform-specific build tasks. + +- [ ] **Step 1: Scaffold Taskfile structure** + +Generate a reference v3 project in a temp directory to get the canonical Taskfile structure: + +```bash +cd /tmp && wails3 init -n omniview-ref -t vanilla +``` + +Copy the `Taskfile.yml` and `build/` directory structure from the generated project. These will serve as the base templates. + +- [ ] **Step 2: Create root Taskfile.yml** + +Create `Taskfile.yml` at the project root. This is the main orchestrator that replaces the Makefile. It must include: + +- `includes` for `common`, `windows`, `darwin`, `linux` subtaskfiles +- `vars` section with `APP_NAME: "Omniview"`, `BIN_DIR: "bin"`, `VITE_PORT` +- Tasks: `build`, `package`, `run`, `dev` (delegates to platform-specific or `wails3 dev`) +- CI check tasks: `check` (runs all), `check:go-build`, `check:go-vet`, `check:go-test`, `check:go-lint`, `check:fmt`, `check:bindings`, `check:ui-lint`, `check:ui-typecheck` +- Frontend tasks: `common:frontend:install`, `common:frontend:build`, `common:packages` +- Signing tasks: `darwin:sign`, `darwin:notarize` + +Replicate all targets from the current `Makefile` (see `Makefile:1-163`). Key translations: +- `GOWORK=off go build ./...` stays the same in Taskfile commands +- `pnpm install --frozen-lockfile` for `common:frontend:install` +- `pnpm build` for `common:frontend:build` +- `wails3 generate bindings` for `common:bindings` (replaces `wails generate module`) +- E2E tasks: `e2e`, `e2e-ui`, `e2e-report` for Playwright + +- [ ] **Step 3: Create build/config.yml** + +Create `build/config.yml` with project metadata. Reference `api-build-system.md` for format: + +```yaml +version: '3' +info: + companyName: "Omniview" + productName: "Omniview" + productIdentifier: "dev.omniview.app" + description: "The modern, lightweight, pluggable cross-platform IDE for DevOps engineers" + version: "0.0.1" + +dev_mode: + root_path: . + log_level: warn + debounce: 1000 + ignore: + dir: [.git, node_modules, frontend, bin, dist, packages] + file: [.DS_Store, .gitignore] + watched_extension: ["*.go"] + git_ignore: true + executes: + - cmd: wails3 build DEV=true + type: blocking + - cmd: wails3 task common:dev:frontend + type: background + - cmd: wails3 task run + type: primary +``` + +- [ ] **Step 4: Create build/Taskfile.yml (common tasks)** + +Reference the scaffolded project from Step 1. Include: +- `build:frontend` — `pnpm install && pnpm build` +- `dev:frontend` — `pnpm dev` +- `bindings` — `wails3 generate bindings` +- `icons` — `wails3 generate icons` +- Workspace package build tasks (providers, vite-plugin, ui, runtime — in order) + +- [ ] **Step 5: Create platform Taskfiles** + +Create `build/darwin/Taskfile.yml`, `build/windows/Taskfile.yml`, `build/linux/Taskfile.yml`. Each needs: +- `build` — platform-specific Go build with correct `-o` flag and ldflags +- `package` — create platform bundle (.app, NSIS installer, AppImage) +- `run` — execute the built binary +- For darwin: `sign` and `notarize` tasks (port from `Makefile:126-149`) + +Create `build/darwin/Info.plist` and `build/windows/info.json` with app metadata. Reference the scaffolded project. + +- [ ] **Step 6: Update .gitignore** + +Add to `.gitignore`: +``` +.task +``` + +- [ ] **Step 7: Verify Taskfile works** + +```bash +task --list +``` + +Expected: all tasks listed without errors. + +- [ ] **Step 8: Delete Makefile and wails.json** + +```bash +rm Makefile wails.json +``` + +- [ ] **Step 9: Commit** + +```bash +git add Taskfile.yml build/ .gitignore +git rm Makefile wails.json +git commit -m "build: replace Makefile and wails.json with Taskfile build system" +``` + +--- + +## Task 3: Update Go module dependency to Wails v3 + +**Files:** +- Modify: `go.mod` +- Modify: `go.sum` + +- [ ] **Step 1: Replace Wails v2 dependency with v3** + +```bash +go get github.com/wailsapp/wails/v3@latest +``` + +This will update `go.mod` from `github.com/wailsapp/wails/v2 v2.11.0` to the v3 module path. + +- [ ] **Step 2: Remove old v2 dependency** + +```bash +go mod edit -droprequire github.com/wailsapp/wails/v2 +go mod tidy +``` + +Note: The code won't compile yet — that's expected. This step just gets the dependency in place. + +- [ ] **Step 3: Commit** + +```bash +git add go.mod go.sum +git commit -m "deps: switch from wails/v2 to wails/v3" +``` + +--- + +## Task 4: Migrate EventEmitter interface to v3 + +**Files:** +- Modify: `backend/pkg/plugin/resource/emitter.go` +- Modify: `backend/pkg/plugin/resource/testutil_test.go` +- Modify: `backend/pkg/plugin/resource/emitter_test.go` +- Modify: `backend/pkg/plugin/events.go` + +This task updates the event abstraction layer to the v3 API. No Wails app reference needed yet — the interface changes are pure Go. + +- [ ] **Step 1: Update EventEmitter interface signature** + +Edit `backend/pkg/plugin/resource/emitter.go`. The interface changes from single `data interface{}` to variadic `data ...any`. The `wailsEmitter` implementation changes from storing `context.Context` to storing `*application.App`: + +```go +package resource + +import ( + "github.com/wailsapp/wails/v3/pkg/application" +) + +// EventEmitter abstracts event emission for testability. +// Production uses appEmitter; tests use recordingEmitter. +type EventEmitter interface { + Emit(eventKey string, data ...any) +} + +// appEmitter emits events via the Wails v3 application event system. +type appEmitter struct { + app *application.App +} + +func newAppEmitter(app *application.App) *appEmitter { + return &appEmitter{app: app} +} + +func (e *appEmitter) Emit(eventKey string, data ...any) { + e.app.Event.Emit(eventKey, data...) +} + +// noopEmitter discards all events. Used before the app is initialized. +type noopEmitter struct{} + +func (noopEmitter) Emit(string, ...any) {} +``` + +- [ ] **Step 2: Update recordingEmitter in tests** + +Edit `backend/pkg/plugin/resource/testutil_test.go`. Change `Emit` signature to match new interface: + +```go +type emittedEvent struct { + Key string + Data []any // Changed from interface{} to []any (variadic capture) +} + +func (e *recordingEmitter) Emit(key string, data ...any) { + e.mu.Lock() + e.events = append(e.events, emittedEvent{Key: key, Data: data}) + close(e.changed) + e.changed = make(chan struct{}) + e.mu.Unlock() +} +``` + +Also update all test assertions that check `.Data` — it's now a `[]any` slice, not a single `interface{}`. For example, in `TestRecordingEmitter_EmitAndEvents`: + +```go +assert.Equal(t, []any{"data-1"}, events[0].Data) +``` + +Update `TestRecordingEmitter_WaitForEvent_Immediate`, `TestRecordingEmitter_WaitForEvent_Async`, etc. similarly. + +- [ ] **Step 3: Update emitter_test.go** + +Edit `backend/pkg/plugin/resource/emitter_test.go` to verify the new interface is implemented correctly. The compile-time checks should reference `appEmitter` instead of `wailsEmitter`: + +```go +var _ EventEmitter = (*appEmitter)(nil) +var _ EventEmitter = (*recordingEmitter)(nil) +var _ EventEmitter = noopEmitter{} +``` + +- [ ] **Step 4: Update events.go — remove eventEmitFn and emitEvent** + +Edit `backend/pkg/plugin/events.go`. Remove the global `eventEmitFn` variable and `emitEvent` helper. The plugin package will use the `EventEmitter` interface directly instead: + +Remove lines 67-78 (the `eventEmitFn` var and `emitEvent` function). The `emitStateChange` function should accept an `EventEmitter` parameter instead of `context.Context`: + +```go +// emitStateChange emits a state change event via the provided emitter. +func emitStateChange(emitter resource.EventEmitter, pluginID string, t lifecycle.Transition) { + if emitter == nil { + return + } + emitter.Emit(EventStateChange, StateChangePayload{ + PluginID: pluginID, + From: t.From, + To: t.To, + Reason: t.Reason, + Timestamp: t.Timestamp, + }) +} +``` + +Remove the `github.com/wailsapp/wails/v2/pkg/runtime` import from this file. + +- [ ] **Step 5: Run tests** + +```bash +cd backend/pkg/plugin/resource && go test ./... -count=1 -v +``` + +Expected: All existing tests pass with the updated emitter signatures. + +- [ ] **Step 6: Commit** + +```bash +git add backend/pkg/plugin/resource/emitter.go backend/pkg/plugin/resource/testutil_test.go \ + backend/pkg/plugin/resource/emitter_test.go backend/pkg/plugin/events.go +git commit -m "refactor: update EventEmitter interface and helpers for wails v3" +``` + +--- + +## Task 5: Add typed event registration + +**Files:** +- Modify: `backend/pkg/plugin/events.go` +- Modify: Each controller file that defines event payload types + +- [ ] **Step 1: Add RegisterEvent calls to events.go init()** + +Add an `init()` function to `backend/pkg/plugin/events.go` that registers typed events for TypeScript generation. Reference `~/.claude/skills/wails-v3-migrator/references/api-events.md` for `RegisterEvent[T]` API: + +```go +func init() { + application.RegisterEvent[StateChangePayload](EventStateChange) + application.RegisterEvent[DeprecatedProtocolPayload](EventDeprecatedProtocol) + application.RegisterEvent[application.Void](EventInstallStarted) + application.RegisterEvent[application.Void](EventInstallFinished) + application.RegisterEvent[application.Void](EventInstallError) + application.RegisterEvent[application.Void](EventDevInstallStart) + application.RegisterEvent[application.Void](EventDevInstallError) + application.RegisterEvent[application.Void](EventDevInstallComplete) + application.RegisterEvent[application.Void](EventReloadStart) + application.RegisterEvent[application.Void](EventReloadError) + application.RegisterEvent[application.Void](EventReloadComplete) + application.RegisterEvent[application.Void](EventUpdateStarted) + application.RegisterEvent[application.Void](EventUpdateError) + application.RegisterEvent[application.Void](EventUpdateComplete) + application.RegisterEvent[application.Void](EventInitComplete) + application.RegisterEvent[application.Void](EventCrashRecoveryFailed) + application.RegisterEvent[application.Void](EventRecovered) + application.RegisterEvent[application.Void](EventStateWriteError) +} +``` + +- [ ] **Step 2: Add typed registrations in each controller package** + +For each controller that defines event payload types, add `RegisterEvent[T]` calls in `init()`. Search each controller package for event key constants and payload structs. The exact types need to be discovered per-controller during implementation. + +Key packages to check: +- `backend/pkg/plugin/exec/` — exec stream output events +- `backend/pkg/plugin/logs/` — log stream events +- `backend/pkg/plugin/metric/` — metric data events +- `backend/pkg/plugin/networker/` — port-forward session events (lines 29-30) +- `backend/pkg/plugin/devserver/` — dev server status/log/error events + +- [ ] **Step 3: Verify compilation** + +```bash +GOWORK=off go build ./... +``` + +Expected: Compiles (may have other errors from unmigrated code — that's OK, this just checks the event registration compiles). + +- [ ] **Step 4: Commit** + +```bash +git add backend/pkg/plugin/events.go backend/pkg/plugin/*/ +git commit -m "feat: add typed event registration for v3 TypeScript generation" +``` + +--- + +## Task 6: Migrate main.go entry point to v3 + +**Files:** +- Modify: `main.go` (major rewrite) +- Modify: `app.go` (rewrite to AppService) +- Modify: `fileloader.go` (rename, restructure as middleware handler) + +This is the largest single task. It converts the monolithic `wails.Run()` call to v3's phased structure. + +Reference `~/.claude/skills/wails-v3-migrator/references/api-application.md` for `application.Options`, `ServiceStartup`, service registration. Reference `api-windows.md` for `WebviewWindowOptions`. Reference `api-platform-options.md` for Mac/Windows/Linux options. + +- [ ] **Step 1: Rewrite main.go** + +Replace the entire `main.go` content. The new structure: + +1. **Keep** all pre-Wails setup (telemetry init, logger creation, diagnostics, settings provider, controller/manager creation, wiring) +2. **Remove** the `startup` closure (lines 198-298) — its contents move to each service's `ServiceStartup` +3. **Remove** the `wails.Run(&options.App{...})` call (lines 301-386) +4. **Add** `application.New(application.Options{...})` with: + - `Name: "Omniview"` + - `Services: []application.Service{...}` — all 17 services registered via `application.NewService()` or `application.NewServiceWithOptions()` + - `Assets: application.AssetOptions{Handler: application.AssetFileServerFS(assets), Middleware: ...}` — with plugin asset middleware +5. **Add** window creation: `app.Window.NewWithOptions(application.WebviewWindowOptions{...})` with `Name: "main"`, all dimensions, platform options, `UseApplicationMenu: true` +6. **Add** `app.Run()` with error handling + +Key details for the rewrite: +- The `pluginRefAdapter` and `pluginReloaderAdapter` types (lines 62-78) stay unchanged +- The controller/manager construction logic (lines 81-195) stays unchanged +- Services are registered in order: SettingsService, TelemetryService, ResourceService, ExecService, LogsService, MetricService, NetworkerService, DataService, UIService, UtilsService, DevServerService, PluginManagerService, PluginLogService, SettingsControllerService, DiagnosticsService, AppService +- The `PluginAssetHandler` (renamed from `FileLoader`) is used as middleware, NOT as a routed service +- Embed directives stay: `//go:embed all:dist` and `//go:embed build/appicon.png` +- Import `github.com/wailsapp/wails/v3/pkg/application` instead of v2 packages + +Window platform options mapping (from `api-platform-options.md`): +```go +Mac: application.MacWindow{ + TitleBar: application.MacTitleBarHiddenInset, + Appearance: application.NSAppearanceNameDarkAqua, + Backdrop: application.MacBackdropTranslucent, +}, +Linux: application.LinuxWindow{ + WebviewGpuPolicy: application.WebviewGpuPolicyOnDemand, +}, +Zoom: 1.0, +``` + +- [ ] **Step 2: Rewrite app.go as AppService** + +Replace `app.go`. The `App` struct becomes `AppService`: + +```go +type AppService struct { + app *application.App +} + +func NewAppService() *AppService { + return &AppService{} +} + +func (s *AppService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + s.app = application.Get() + return nil +} + +func (s *AppService) ServiceShutdown() error { + return nil +} + +func (s *AppService) GetOperatingSystem() string { /* same logic */ } + +func (s *AppService) OpenFileSelectionDialog(opts FileDialogOptions) ([]string, error) { + // Use v3 dialog builder: s.app.Dialog.OpenFile()...PromptForMultipleSelection() +} + +func (s *AppService) SaveFileDialog(opts FileDialogOptions) (string, error) { + // Use v3 dialog builder: s.app.Dialog.SaveFile()...PromptForSingleSelection() +} + +func (s *AppService) WriteFileContent(path string, content string) error { /* same */ } +``` + +Dialog migration — reference `~/.claude/skills/wails-v3-migrator/references/api-dialogs.md`: +- `OpenMultipleFilesDialog` → `s.app.Dialog.OpenFile().SetTitle(...).AddFilter(...).PromptForMultipleSelection()` +- `SaveFileDialog` → `s.app.Dialog.SaveFile().SetTitle(...).SetFilename(...).PromptForSingleSelection()` +- Remove `FileDialogOptions` wrapper struct — use builder methods directly. Keep the struct as a parameter type for the bound method if the frontend currently passes it. + +Remove the `Shutdownable` interface, `startup()`, `domReady()`, `beforeClose()` methods. Remove the `ctx context.Context` field. Remove `wailsruntime` import. + +Migrate lifecycle hooks: +- `domReady` is currently empty (`app.go:111-113`) — no migration needed, just delete it. If logic is added later, use `window.OnWindowEvent(events.Common.WindowRuntimeReady, handler)` in `AppService.ServiceStartup`. +- `beforeClose` currently returns false (`app.go:118-120`) — no migration needed, just delete it. If close prevention is needed later, use `window.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { e.Cancel() })` in `AppService.ServiceStartup`. + +- [ ] **Step 3: Rename fileloader.go and restructure** + +Rename `fileloader.go` to `plugin_asset_handler.go`. Rename struct from `FileLoader` to `PluginAssetHandler`. Remove the embedded `http.Handler` field. The `ServeHTTP` method stays but is called from middleware, not as a standalone handler. + +Update `main.go` to use it as middleware: +```go +Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), + Middleware: func(next http.Handler) http.Handler { + handler := NewPluginAssetHandler(log) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/_/") { + handler.ServeHTTP(w, r) + return + } + next.ServeHTTP(w, r) + }) + }, +}, +``` + +- [ ] **Step 4: Verify compilation** + +At this point most controllers still have v2 imports. The goal is just that `main.go`, `app.go`, and `plugin_asset_handler.go` compile with v3 imports. Other packages will be updated in subsequent tasks. + +```bash +GOWORK=off go build ./... +``` + +If compilation fails on other packages (expected), verify main package files compile in isolation by checking for syntax errors. + +- [ ] **Step 5: Commit** + +```bash +git add main.go app.go plugin_asset_handler.go +git rm fileloader.go +git commit -m "feat: migrate main.go entry point and app service to wails v3" +``` + +--- + +## Task 7: Migrate menus to v3 + +**Files:** +- Create: `backend/menus/app.go` +- Create: `backend/menus/keybindings.go` +- Create: `backend/menus/context.go` +- Delete: `backend/menus/menus.go` +- Delete: `backend/menus/view.go` + +Reference `~/.claude/skills/wails-v3-migrator/references/api-menus.md` for menu API, role menus, accelerator syntax, and context menu registration. + +- [ ] **Step 1: Create backend/menus/app.go** + +New file that replaces both `menus.go` and `view.go`. Uses v3 menu API: + +```go +package menus + +import ( + "runtime" + "github.com/wailsapp/wails/v3/pkg/application" +) + +// SetupAppMenu creates and sets the application menu. +func SetupAppMenu(app *application.App, window *application.WebviewWindow) { + menu := app.NewMenu() + + if runtime.GOOS == "darwin" { + menu.AddRole(application.AppMenu) + menu.AddRole(application.EditMenu) + menu.AddRole(application.WindowMenu) + } + + viewMenu := menu.AddSubmenu("View") + viewMenu.Add("Reload").SetAccelerator("CmdOrCtrl+R").OnClick(func(ctx *application.Context) { + window.Reload() + }) + viewMenu.Add("Force Reload").SetAccelerator("CmdOrCtrl+Shift+F").OnClick(func(ctx *application.Context) { + window.ForceReload() + }) + + viewMenu.AddSeparator() + viewMenu.Add("New Terminal Session").SetAccelerator("CmdOrCtrl+Shift+T").OnClick(func(ctx *application.Context) { + app.Event.Emit("menu/view/terminal/create") + }) + viewMenu.Add("Minimize Bottom Menu").SetAccelerator("CmdOrCtrl+Shift+B").OnClick(func(ctx *application.Context) { + app.Event.Emit("menu/view/bottomdrawer/minimize") + }) + viewMenu.Add("Maximize Bottom Menu").SetAccelerator("CmdOrCtrl+Alt+B").OnClick(func(ctx *application.Context) { + app.Event.Emit("menu/view/bottomdrawer/fullscreen") + }) + + viewMenu.AddSeparator() + viewMenu.Add("Close Sidebar").SetAccelerator("CmdOrCtrl+Shift+S").OnClick(func(ctx *application.Context) { + app.Event.Emit("menu/view/sidebar/minimize") + }) + + app.Menu.Set(menu) +} +``` + +Key translations from current code: +- `keys.CmdOrCtrl("r")` → `SetAccelerator("CmdOrCtrl+R")` +- `keys.Combo("f", keys.CmdOrCtrlKey, keys.ShiftKey)` → `SetAccelerator("CmdOrCtrl+Shift+F")` +- `keys.Combo("b", keys.CmdOrCtrlKey, keys.ShiftKey)` → `SetAccelerator("CmdOrCtrl+Shift+B")` +- `keys.Combo("b", keys.CmdOrCtrlKey, keys.OptionOrAltKey)` → `SetAccelerator("CmdOrCtrl+Alt+B")` +- `keys.Combo("s", keys.CmdOrCtrlKey, keys.ShiftKey)` → `SetAccelerator("CmdOrCtrl+Shift+S")` +- `wailsruntime.WindowReload(ctx)` → `window.Reload()` +- `wailsruntime.WindowReloadApp(ctx)` → `window.ForceReload()` +- `wailsruntime.EventsEmit(ctx, name)` → `app.Event.Emit(name)` +- `func(_ *menu.CallbackData)` → `func(ctx *application.Context)` + +- [ ] **Step 2: Create backend/menus/keybindings.go** + +```go +package menus + +import "github.com/wailsapp/wails/v3/pkg/application" + +// SetupKeyBindings registers standalone keyboard shortcuts. +func SetupKeyBindings(app *application.App, window *application.WebviewWindow) { + // These duplicate menu accelerators but also work when menus are hidden + app.KeyBinding.Add("ctrl+shift+t", func(w *application.WebviewWindow) { + app.Event.Emit("menu/view/terminal/create") + }) +} +``` + +- [ ] **Step 3: Create backend/menus/context.go** + +Define Go-side context menus for future frontend migration. Reference `api-menus.md` for `RegisterContextMenu`: + +```go +package menus + +import "github.com/wailsapp/wails/v3/pkg/application" + +// SetupContextMenus registers Go-side context menus by ID. +// Frontend activation via CSS --custom-contextmenu is a future sprint. +func SetupContextMenus(app *application.App) { + // Bottom drawer tab context menu + tabMenu := app.NewContextMenu() + tabMenu.Add("Close Tab").OnClick(func(ctx *application.Context) { + app.Event.Emit("context/tab/close") + }) + tabMenu.Add("Close Other Tabs").OnClick(func(ctx *application.Context) { + app.Event.Emit("context/tab/close-others") + }) + app.RegisterContextMenu("drawer-tab", tabMenu) +} +``` + +- [ ] **Step 4: Delete old menu files** + +```bash +rm backend/menus/menus.go backend/menus/view.go +``` + +- [ ] **Step 5: Wire menus into AppService.ServiceStartup** + +In `main.go` or `app.go`, call the menu setup functions after app and window are created (in `AppService.ServiceStartup` or after `app.Window.NewWithOptions`): + +```go +menus.SetupAppMenu(app, mainWindow) +menus.SetupKeyBindings(app, mainWindow) +menus.SetupContextMenus(app) +``` + +- [ ] **Step 6: Verify compilation** + +```bash +GOWORK=off go build ./backend/menus/... +``` + +- [ ] **Step 7: Commit** + +```bash +git add backend/menus/app.go backend/menus/keybindings.go backend/menus/context.go +git rm backend/menus/menus.go backend/menus/view.go +git commit -m "feat: migrate menus to v3 API with context menu stubs and keybindings" +``` + +--- + +## Task 8: Create WindowManager + +**Files:** +- Create: `backend/window/manager.go` + +- [ ] **Step 1: Create backend/window/manager.go** + +Reference `~/.claude/skills/wails-v3-migrator/references/api-windows.md` for `WebviewWindowOptions`, `GetByName`, window methods. Also reference the Wails v3 documented window recycling pattern from `~/Repos/wails/docs/src/content/docs/features/windows/multiple.mdx`. + +The `WindowManager` implements **hide-on-close recycling for the main window**. The main window holds all app state and plugin connections — closing it hides to tray/dock instead of quitting. Secondary windows (settings, devtools) are ephemeral and close normally since they're stateless and cheap to recreate. + +```go +package window + +import ( + "github.com/wailsapp/wails/v3/pkg/application" + "github.com/wailsapp/wails/v3/pkg/events" +) + +// Manager centralizes window creation, access, and lifecycle management. +// The main window uses hide-on-close recycling to stay alive in tray/dock. +// Secondary windows close normally. +type Manager struct { + app *application.App +} + +// NewManager creates a new WindowManager and registers hide-on-close +// on the main window so closing it hides to tray/dock instead of quitting. +func NewManager(app *application.App, main *application.WebviewWindow) *Manager { + m := &Manager{app: app} + m.registerMainWindowHideOnClose(main) + return m +} + +// Main returns the main application window. +func (m *Manager) Main() *application.WebviewWindow { + return m.app.Window.GetByName("main") +} + +// registerMainWindowHideOnClose intercepts WindowClosing on the main window, +// hiding it instead of quitting the app. The app stays alive in tray/dock. +func (m *Manager) registerMainWindowHideOnClose(w *application.WebviewWindow) { + w.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { + w.Hide() + e.Cancel() // prevent quit — app stays alive in tray/dock + }) +} + +// OpenSettings creates a fresh settings window. Closes normally when dismissed. +func (m *Manager) OpenSettings() *application.WebviewWindow { + return m.app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "settings", + Title: "Settings — Omniview", + URL: "/#/settings", + Width: 900, + Height: 700, + UseApplicationMenu: true, + }) +} + +// OpenDevtools creates a fresh devtools window. Closes normally when dismissed. +func (m *Manager) OpenDevtools() *application.WebviewWindow { + return m.app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "devtools", + Title: "DevTools — Omniview", + URL: "/#/devtools", + Width: 1200, + Height: 800, + UseApplicationMenu: true, + }) +} +``` + +Note: URLs use `/#/` prefix because the frontend uses hash routing (`createHashRouter`). The future `WindowPool` (for detachable terminals/logs) would add hide-on-close recycling to its pooled windows, but that's a separate sprint. + +- [ ] **Step 2: Commit** + +```bash +git add backend/window/manager.go +git commit -m "feat: add WindowManager for multi-window support" +``` + +--- + +## Task 9: Update Vite config for v3 + +**Files:** +- Modify: `vite.config.ts` + +- [ ] **Step 1: Add Wails Vite plugin** + +Edit `vite.config.ts`. Add the Wails plugin import and add it to the plugins array. Also update the `@omniviewdev/runtime/runtime` alias to point to the new re-export: + +```typescript +import wails from '@wailsio/runtime/plugins/vite'; +``` + +Add to the `plugins` array after `react()`: + +```typescript +plugins: [ + react({ /* existing config */ }), + wails('./packages/omniviewdev-runtime/src/bindings'), // path to generated bindings + { name: 'strip-dev-scripts', /* existing */ }, +], +``` + +The binding path must point to wherever `wails3 generate bindings` outputs. This will be configured to output into the runtime package. + +- [ ] **Step 2: Commit** + +```bash +git add vite.config.ts +git commit -m "feat: add wails v3 vite plugin to vite.config.ts" +``` + +--- + +## Task 10: Migrate resource controller (proving ground) + +**Files:** +- Modify: `backend/pkg/plugin/resource/controller.go` +- Delete: `backend/pkg/plugin/resource/client.go` + +This is the proving ground — the most complex service with event patterns, watch states, and dynamic event keys. + +- [ ] **Step 1: Add app field and ServiceStartup to controller** + +Edit `backend/pkg/plugin/resource/controller.go`. Add `*application.App` field to the `controller` struct (line 58). Change `Run(ctx context.Context)` (line 123) to `ServiceStartup`: + +```go +type controller struct { + app *application.App // NEW: replaces ctx + logger logging.Logger + settingsProvider pkgsettings.Provider + emitter EventEmitter + // ... rest stays the same +} + +func (c *controller) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + c.app = application.Get() + c.emitter = newAppEmitter(c.app) + c.dispatcher.Start() + return nil +} + +func (c *controller) ServiceShutdown() error { + c.dispatcher.Stop() + return nil +} +``` + +Remove the old `Run(ctx context.Context)` and `Shutdown()` methods. + +- [ ] **Step 2: Delete client.go** + +The `resource.Client` struct is a thin wrapper. All its methods delegate to the controller. Delete `backend/pkg/plugin/resource/client.go`. The controller is registered as the v3 service directly in `main.go`. + +Update `main.go` to remove `resourceClient := resource.NewClient(resourceController)` and register `resourceController` directly as a service. + +- [ ] **Step 3: Update any code that references resource.Client** + +Search for `resource.NewClient` and `resource.Client` in other files. Update imports and references to use the controller directly. + +- [ ] **Step 4: Run tests** + +```bash +cd backend/pkg/plugin/resource && go test ./... -count=1 -v +``` + +Expected: Tests pass. The `newTestControllerWithEmitter` helper in `testutil_test.go` already uses `recordingEmitter` directly, so tests don't need the app reference. + +- [ ] **Step 5: Commit** + +```bash +git add backend/pkg/plugin/resource/controller.go +git rm backend/pkg/plugin/resource/client.go +git commit -m "feat: migrate resource controller to v3 service, delete client wrapper" +``` + +--- + +## Task 11: Migrate remaining controllers to v3 services + +**Files:** Each controller package under `backend/pkg/plugin/` + +For each controller, apply the same pattern proven in Task 10: +1. Add `app *application.App` field to the struct +2. Replace `Run(ctx context.Context)` with `ServiceStartup(ctx context.Context, options application.ServiceOptions) error` +3. Replace `Shutdown()` with `ServiceShutdown() error` +4. Replace `ctx context.Context` field with `app *application.App` +5. Replace `runtime.EventsEmit(c.ctx, ...)` calls with emitter-based calls or `c.app.Event.Emit(...)` +6. Delete the client.go wrapper file +7. Run tests + +- [ ] **Step 1: Migrate exec controller** + +Edit `backend/pkg/plugin/exec/controller.go`: +- Struct (line 71): replace `ctx context.Context` (line 73) with `app *application.App` +- `Run` (line 92) → `ServiceStartup`, set `c.app = application.Get()` +- 6 `runtime.EventsEmit(c.ctx, ...)` calls (lines 151, 153, 173, 214, 216, 236) → `c.app.Event.Emit(...)` +- Delete `backend/pkg/plugin/exec/client.go` + +- [ ] **Step 2: Migrate logs controller** + +Edit `backend/pkg/plugin/logs/controller.go`: +- Struct (line 55): replace `ctx context.Context` (line 56) with `app *application.App` +- `Run` (line 96) → `ServiceStartup` +- `runtime.EventsEmit(c.ctx, eventKey, ...)` (line 123) → `c.app.Event.Emit(eventKey, ...)` +- Delete `backend/pkg/plugin/logs/client.go` + +- [ ] **Step 3: Migrate metric controller** + +Edit `backend/pkg/plugin/metric/controller.go`: +- Struct (line 80): replace `ctx context.Context` (line 81) with `app *application.App` +- `Run` (line 112) → `ServiceStartup` +- Delete `backend/pkg/plugin/metric/client.go` + +- [ ] **Step 4: Migrate networker controller** + +Edit `backend/pkg/plugin/networker/controller.go`: +- Struct (line 90): replace `ctx context.Context` (line 91) with `app *application.App` +- `Run` (line 103) → `ServiceStartup` +- Delete `backend/pkg/plugin/networker/client.go` + +- [ ] **Step 5: Migrate settings controller** + +Edit `backend/pkg/plugin/settings/controller.go`: +- No `Run` method — add `ServiceStartup` and `ServiceShutdown` +- Delete `backend/pkg/plugin/settings/client.go` + +- [ ] **Step 6: Migrate data controller** + +Edit `backend/pkg/plugin/data/controller.go`: +- No `Run` method — add `ServiceStartup` and `ServiceShutdown` +- Delete `backend/pkg/plugin/data/client.go` + +- [ ] **Step 7: Migrate UI manager + client** + +Merge `backend/pkg/plugin/ui/client.go` into the manager. Add `ServiceStartup`/`ServiceShutdown` to the manager struct. + +- [ ] **Step 8: Migrate utils client** + +Edit `backend/pkg/plugin/utils/client.go`. Add `ServiceStartup`/`ServiceShutdown`. + +- [ ] **Step 9: Migrate plugin manager** + +Edit `backend/pkg/plugin/manager.go`. This is the largest service: +- Replace stored `ctx` with `app *application.App` +- `Initialize(ctx)` + `Run(ctx)` merge into `ServiceStartup` +- `Shutdown()` → `ServiceShutdown() error` +- All `emitEvent(ctx, ...)` calls → use emitter interface +- `runtime.EventsEmit(pm.ctx, EventInitComplete)` (line 495) → `pm.app.Event.Emit(EventInitComplete)` + +- [ ] **Step 10: Migrate devserver manager** + +Edit `backend/pkg/plugin/devserver/manager.go`: +- Replace stored `ctx` with `app *application.App` +- `Initialize(ctx)` → `ServiceStartup` +- `Shutdown()` → `ServiceShutdown() error` +- All `runtime.EventsEmit(m.ctx, ...)` calls (lines 430, 437, 444) → `m.app.Event.Emit(...)` + +- [ ] **Step 11: Migrate installer.go** + +Edit `backend/pkg/plugin/installer.go`. This file imports `github.com/wailsapp/wails/v2/pkg/runtime`. Update any `runtime.EventsEmit` calls to use the emitter interface or `app.Event.Emit(...)`. Remove the v2 runtime import. + +- [ ] **Step 12: Migrate pluginlog manager callback wiring** + +The `pluginlog` manager uses an `OnEmit` callback pattern wired in `main.go`'s startup closure. During the `main.go` rewrite (Task 6), this callback closure that calls `runtime.EventsEmit(ctx, ...)` must be updated to use `app.Event.Emit(...)` instead. The `pluginlog` package itself may not import Wails directly, but its callback wiring in main.go does. + +- [ ] **Step 13: Migrate diagnostics logger** + +Edit `backend/diagnostics/logger.go`: +- `runtime.EventsEmit(ctx, ...)` (line 217) → use emitter or `app.Event.Emit(...)` + +- [ ] **Step 14: Run all Go tests** + +```bash +GOWORK=off go test ./... -count=1 +``` + +Expected: All tests pass. Note: test files for each controller may need updates if they construct controllers with `context.Context` arguments. Inspect test files during each controller migration, not just at the end. + +- [ ] **Step 15: Verify no remaining v2 imports** + +```bash +grep -r "wailsapp/wails/v2" --include="*.go" . +``` + +Expected: No matches. + +- [ ] **Step 16: Commit (split into multiple commits by batch)** + +Commit controllers in batches of 3-4 for easier review and bisection: + +```bash +# Batch 1: settings, exec, logs +git add backend/pkg/plugin/settings/ backend/pkg/plugin/exec/ backend/pkg/plugin/logs/ +git commit -m "feat: migrate settings, exec, logs controllers to v3 services" + +# Batch 2: metric, networker, data +git add backend/pkg/plugin/metric/ backend/pkg/plugin/networker/ backend/pkg/plugin/data/ +git commit -m "feat: migrate metric, networker, data controllers to v3 services" + +# Batch 3: ui, utils, installer +git add backend/pkg/plugin/ui/ backend/pkg/plugin/utils/ backend/pkg/plugin/installer.go +git commit -m "feat: migrate ui, utils, installer to v3 services" + +# Batch 4: plugin manager, devserver, pluginlog, diagnostics +git add backend/pkg/plugin/manager.go backend/pkg/plugin/devserver/ \ + backend/pkg/plugin/pluginlog/ backend/diagnostics/ +git commit -m "feat: migrate plugin manager, devserver, pluginlog, diagnostics to v3 services" +``` + +```bash +git add backend/pkg/plugin/ backend/diagnostics/ +git commit -m "feat: migrate all controllers to v3 services, delete client wrappers" +``` + +--- + +## Task 12: Update main.go service registration + +**Files:** +- Modify: `main.go` + +After all controllers are migrated, update `main.go` to register them correctly. + +- [ ] **Step 1: Update service registrations** + +Remove all `NewClient()` calls. Register controllers directly. + +**Important:** `application.NewService[T](instance *T)` requires a concrete pointer type, NOT an interface. For variables declared as interfaces (e.g., `resourceController Controller`), use `application.NewServiceWithOptions()` instead, or change the variable type to the concrete pointer type. + +For each service, determine whether the variable is a pointer or an interface: +- Variables that are already `*ConcreteType` (e.g., `app *AppService`) → use `application.NewService(app)` +- Variables that are interfaces (e.g., `resourceController Controller`) → either change the construction to return `*controller` directly, or use `application.NewServiceWithOptions(&svc, application.ServiceOptions{})` + +```go +Services: []application.Service{ + application.NewServiceWithOptions(settingsProvider, application.ServiceOptions{}), + application.NewServiceWithOptions(telemetryBinding, application.ServiceOptions{}), + application.NewServiceWithOptions(resourceController, application.ServiceOptions{}), + application.NewServiceWithOptions(execController, application.ServiceOptions{}), + application.NewServiceWithOptions(logsController, application.ServiceOptions{}), + application.NewServiceWithOptions(metricController, application.ServiceOptions{}), + application.NewServiceWithOptions(networkerController, application.ServiceOptions{}), + application.NewServiceWithOptions(dataController, application.ServiceOptions{}), + application.NewServiceWithOptions(uiManager, application.ServiceOptions{}), + application.NewServiceWithOptions(utilsClient, application.ServiceOptions{}), + application.NewServiceWithOptions(devServerManager, application.ServiceOptions{}), + application.NewServiceWithOptions(pluginManager, application.ServiceOptions{}), + application.NewServiceWithOptions(pluginLogManager, application.ServiceOptions{}), + application.NewServiceWithOptions(diagnosticsClient, application.ServiceOptions{}), + application.NewService(app), // AppService is a concrete pointer +}, +``` + +Remove the `EnumBind` array entirely — v3 auto-discovers enums. + +Remove the `OnStartup`, `OnDomReady`, `OnBeforeClose`, `OnShutdown` callbacks — replaced by `ServiceStartup`/`ServiceShutdown`. + +- [ ] **Step 2: Verify full compilation** + +```bash +GOWORK=off go build ./... +``` + +Expected: Full project compiles with v3 only. + +- [ ] **Step 3: Commit** + +```bash +git add main.go +git commit -m "feat: register all services in v3 application, remove EnumBind and lifecycle callbacks" +``` + +--- + +## Task 13: Migrate frontend runtime package + +**Files:** +- Modify: `packages/omniviewdev-runtime/src/runtime.ts` +- Modify: `packages/omniviewdev-runtime/src/api.ts` +- Modify: `packages/omniviewdev-runtime/package.json` + +- [ ] **Step 1: Update runtime.ts to re-export @wailsio/runtime** + +Replace `packages/omniviewdev-runtime/src/runtime.ts`: + +```typescript +export { Events, Window, Clipboard, Browser, Application, WML } from '@wailsio/runtime'; +``` + +- [ ] **Step 2: Update package.json exports** + +Add `@wailsio/runtime` as a dependency in `packages/omniviewdev-runtime/package.json`. Update exports to include bindings path: + +```json +{ + "dependencies": { + "@wailsio/runtime": "^3.0.0" + } +} +``` + +- [ ] **Step 3: Generate v3 bindings** + +Run `wails3 generate bindings` with output configured to `packages/omniviewdev-runtime/src/bindings/`. The exact command flags will need to be determined during implementation based on `wails3 generate bindings --help`. + +- [ ] **Step 4: Update api.ts to use new binding paths** + +Replace `packages/omniviewdev-runtime/src/api.ts` with imports from the new `bindings/` directory. The exact paths depend on what `wails3 generate bindings` produces. Example: + +```typescript +export * as ExecClient from './bindings/exec/ExecService'; +export * as ResourceClient from './bindings/resource/ResourceService'; +// ... etc for each service +``` + +Note: The exact module names depend on what the v3 binding generator outputs for each Go service type name. Verify after generation. + +- [ ] **Step 5: Commit** + +```bash +git add packages/omniviewdev-runtime/src/runtime.ts packages/omniviewdev-runtime/src/api.ts \ + packages/omniviewdev-runtime/package.json +git commit -m "feat: migrate runtime package to @wailsio/runtime and v3 bindings" +``` + +--- + +## Task 14: Migrate frontend event listeners + +**Files:** +- Modify: All files using `EventsOn`, `EventsEmit`, `EventsOff` from `@omniviewdev/runtime/runtime` + +The key change: `EventsOn(name, (data) => ...)` → `Events.On(name, (event) => { event.data ... })`. The cleanup function return pattern stays the same. + +There are approximately **33 files** using `EventsOn`/`EventsOff`/`EventsEmit` across the codebase. Use `grep -rn "EventsOn\|EventsOff\|EventsEmit" --include="*.ts" --include="*.tsx" .` to find all sites. Migrate in batches by package. + +**Note on `Once`:** The frontend `Events.Once()` method exists in `@wailsio/runtime`. On the Go side, `app.Event.Once()` is not available — use `app.Event.OnMultiple(name, handler, 1)` for one-shot listeners. + +- [ ] **Step 1: Update hooks in packages/omniviewdev-runtime/src/hooks/** + +Run `grep -rn "EventsOn\|EventsOff\|EventsEmit" --include="*.ts" --include="*.tsx" packages/omniviewdev-runtime/src/hooks/` to find all files. Expected ~15 files including: + +```typescript +// Before +import { EventsOn, EventsOff } from '@omniviewdev/runtime/runtime'; +const cancel = EventsOn('event-name', (data) => { ... }); + +// After +import { Events } from '@omniviewdev/runtime/runtime'; +const cancel = Events.On('event-name', (event) => { + const data = event.data; + // ... rest of handler +}); +``` + +Key files in hooks: +- `hooks/resource/useResources.ts` — multiple `EventsOn` with cleanup (lines 132-182) +- `hooks/resource/useStreamAction.ts` — stream action events +- `hooks/resource/useWatchState.ts` — watch state events +- `hooks/resource/useActiveSyncs.ts` — active sync events +- `hooks/connection/useConnections.ts` — `EventsOn` with cleanup (lines 50-56) +- `hooks/connection/useConnectionStatus.ts` — connection status events +- `hooks/metric/useMetricStream.ts` — metric stream events +- `hooks/networker/usePortForwardSessions.ts` — port-forward events + +For each: update import, wrap handler to unwrap `event.data`. + +- [ ] **Step 2: Update UI components and bridges** + +Run `grep -rn "EventsOn\|EventsOff\|EventsEmit" --include="*.ts" --include="*.tsx" ui/` to find all files. Expected ~18 files including: + +- `ui/providers/BottomDrawer/tabs.tsx` — `EventsOn("menu/view/terminal/create", ...)` +- `ui/providers/BottomDrawer/containers/Terminal.tsx` — 12+ `runtime.EventsOn(...)` calls +- `ui/providers/BottomDrawer/containers/LogViewer/hooks/useLogStream.ts` — log stream events +- `ui/providers/BottomDrawer/containers/LogViewer/sources/sessionSource.ts` — session events +- `ui/providers/RightDrawer/index.tsx` — drawer events +- `ui/features/pluginlogs/wailsBridge.ts` — `EventsOn('plugin/process/log', ...)` +- `ui/features/devtools/wailsBridge.ts` — dev server status bridge +- `ui/features/plugins/react/PluginServiceProvider.tsx` — plugin events +- `ui/features/plugins/adapters/createProductionDeps.ts` — production deps events +- `ui/features/logger/useLogger.tsx` — logger events +- `ui/hooks/plugin/useDevServer.ts` — dev server events +- `ui/hooks/plugin/usePluginManager.ts` — plugin manager events +- `ui/pages/connecting/index.tsx` — connection events +- `ui/layouts/core/main/BottomDrawer/index.tsx` — drawer events +- `ui/components/displays/Footer/AppStatusFooter.tsx` — status events + +For each: update import, wrap handler to unwrap `event.data`. + +Also check `packages/omniviewdev-providers/internal/runtime/runtime.d.ts` — this file may reference event types and need updating. + +- [ ] **Step 3: Remove EventsOff usage** + +Search for `EventsOff` calls. Replace with cleanup functions from `Events.On()`. If any code uses `EventsOff(name)` to remove all listeners, verify this is intentional and either: +- Replace with stored cleanup functions, or +- Use `Events.Off(name)` (v3 equivalent, removes ALL listeners for that name) + +- [ ] **Step 4: Run frontend type check** + +```bash +pnpm exec tsc -p tsconfig.app.json --noEmit +``` + +Expected: No type errors. + +- [ ] **Step 5: Commit** + +```bash +git add packages/omniviewdev-runtime/src/hooks/ ui/ +git commit -m "feat: migrate frontend event listeners to @wailsio/runtime Events API" +``` + +--- + +## Task 15: Update frontend binding imports + +**Files:** +- All frontend files importing from `wailsjs/go/...` + +- [ ] **Step 1: Find all wailsjs import sites** + +```bash +grep -rn "wailsjs/go/" --include="*.ts" --include="*.tsx" . +``` + +Expected: ~31 files across `packages/omniviewdev-runtime/src/` (hooks, context providers, api.ts) that import from `wailsjs/go/`. Each import needs to change from the old path to the new binding path via `@omniviewdev/runtime/api` re-exports. + +- [ ] **Step 2: Update imports** + +For each file, change: +```typescript +// Old +import { Something } from '@omniviewdev/runtime/api'; +// This import still works IF api.ts was updated in Task 13 + +// Old direct imports +import { Something } from '../../wailsjs/go/resource/Client'; +// New +import { Something } from '@omniviewdev/runtime/api'; +``` + +The `api.ts` re-exports should handle most of this transparently. Direct `wailsjs/go/...` imports need updating. + +- [ ] **Step 3: Delete old wailsjs directory** + +```bash +rm -rf packages/omniviewdev-runtime/src/wailsjs/ +``` + +- [ ] **Step 4: Run frontend type check** + +```bash +pnpm exec tsc -p tsconfig.app.json --noEmit +``` + +- [ ] **Step 5: Commit** + +```bash +git add -A +git commit -m "feat: update all frontend binding imports to v3 paths, delete wailsjs directory" +``` + +--- + +## Task 16: Set up frontend routing for multi-window + +**Files:** +- Modify: `ui/routes.tsx` + +- [ ] **Step 1: Verify existing routes** + +The app already uses `react-router-dom` with hash routing and has `/settings` route. Verify that `/settings` and any devtools route render correctly when loaded directly (not just navigated to). This is needed for multi-window where each window loads a specific URL. + +- [ ] **Step 2: Add devtools route if missing** + +If there's no `/devtools` route in `ui/routes.tsx`, add one: + +```typescript +{ + path: '/devtools', + element: , +} +``` + +- [ ] **Step 3: Commit** + +```bash +git add ui/routes.tsx +git commit -m "feat: ensure routes support direct URL loading for multi-window" +``` + +--- + +## Task 17: Final verification and cleanup + +**Files:** +- Modify: `.gitignore` + +- [ ] **Step 1: Verify no remaining v2 Go imports** + +```bash +grep -r "wailsapp/wails/v2" --include="*.go" . +``` + +Expected: No matches. + +- [ ] **Step 2: Verify no remaining wailsjs frontend imports** + +```bash +grep -rn "wailsjs" --include="*.ts" --include="*.tsx" . +``` + +Expected: No matches (or only in generated binding output). + +- [ ] **Step 3: Run full Go test suite** + +```bash +GOWORK=off go test ./... -count=1 +``` + +Expected: All tests pass. + +- [ ] **Step 4: Run frontend type check and lint** + +```bash +pnpm exec tsc -p tsconfig.app.json --noEmit +pnpm lint +``` + +Expected: No errors. + +- [ ] **Step 5: Generate fresh bindings** + +```bash +wails3 generate bindings +``` + +- [ ] **Step 6: Build and run** + +```bash +task dev +``` + +Expected: App boots, main window renders with correct title and dimensions. + +Verification checklist: +- [ ] App starts without errors +- [ ] Menus render and callbacks fire (View > Reload, New Terminal, etc.) +- [ ] Plugin assets load via `/_/` prefix +- [ ] Resource subscription and events work +- [ ] Exec sessions stream output +- [ ] Log streaming works +- [ ] Dialogs open (file selection, save) +- [ ] Settings page renders +- [ ] Plugins load and initialize + +- [ ] **Step 7: Production build** + +```bash +task build +``` + +Expected: Build succeeds, produces binary. + +- [ ] **Step 8: Run review checklist from spec** + +Go through every item in the Review Checklist section of `docs/superpowers/specs/2026-03-20-wails3-migration-design.md`. Verify each item is satisfied. + +- [ ] **Step 9: Update CI workflow** + +Edit `.github/workflows/pr-checks.yml` to use `task` commands instead of `make`: + +- Install go-task in CI +- Replace `make check` with `task check` +- Replace individual `make go-build` etc. with `task check:go-build` etc. + +- [ ] **Step 10: Final commit** + +```bash +git add -A +git commit -m "feat: complete wails v3 migration — all services, events, bindings, and build system migrated" +``` diff --git a/docs/superpowers/specs/2026-03-20-wails3-migration-design.md b/docs/superpowers/specs/2026-03-20-wails3-migration-design.md new file mode 100644 index 00000000..d7a820eb --- /dev/null +++ b/docs/superpowers/specs/2026-03-20-wails3-migration-design.md @@ -0,0 +1,781 @@ +# Wails v2 to v3 Migration Design — Omniview + +**Date**: 2026-03-20 +**Branch**: feat/wails3-migration +**Status**: Approved + +## Overview + +Migrate the Omniview desktop application from Wails v2 (v2.11.0) to Wails v3. +This is not a package bump — Wails v3 is a complete rewrite that changes the +application lifecycle, service model, runtime access patterns, event system, +frontend runtime, dialog/menu/tray APIs, and config structure. The migration +touches 253 Go files, 1,066 frontend TypeScript/JavaScript files, 17 bound +structs, 4 EnumBind arrays, 394+ context references, 25+ event emission sites, +and 30+ frontend event listeners. + +## Migration Strategy + +**Approach**: Outside-in — stand up the v3 app shell first (entry point, window, +build system, asset handler, menus), get a running app, then migrate services one +at a time. The resource controller goes first as the proving ground since it has +the most complex event patterns (watch states, dynamic event keys, subscription +lifecycle). That validated pattern becomes the template for remaining services. + +## Design Decisions + +| Decision | Choice | Rationale | +|---|---|---| +| Binding location | Keep shared package (`packages/omniviewdev-runtime/`) | Preserves existing monorepo architecture; other packages consume bindings | +| Client/controller pairs | Collapse — controllers become v3 services directly | Eliminates thin client wrapper boilerplate | +| Multi-window | Plan from start, implement incrementally | Name windows, create WindowManager, set up routing; settings and devtools are candidates | +| FileLoader | Migrate to asset middleware | Preserves same URL scheme (`/_/` prefix on asset server); no frontend URL changes needed | +| Typed events | Fully adopt `RegisterEvent[T]` for all payloads | Full TypeScript type generation, replaces manual types | +| Context menus | Keep frontend-managed, but register Go-side definitions now | Enables incremental migration to native menus by just adding HTML attributes | +| Build system | Fully replace Makefile with Taskfile | Adopts v3 convention completely | +| EventEmitter abstraction | Keep, update to v3 signature | Testability via `recordingEmitter` is valuable with 25+ emission sites | +| WML | Adopt where it fits | Simple window operations and triggers; complex interactions stay in TypeScript | +| EnumBind | Delete — v3 auto-discovers enums from source | No manual registration needed; generator discovers named types with constants | + +## Section 1: App Shell & Entry Point + +The monolithic `wails.Run(&options.App{...})` in `main.go` becomes a phased +structure. + +### App creation + +`application.New(application.Options{...})` with all services registered in the +`Services` array. The 17 bound items become `application.Service` registrations. +EnumBind arrays are deleted entirely — v3's binding generator auto-discovers +enum types. + +### Window creation + +A separate, explicit step: + +```go +mainWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "main", + Title: "Omniview", + URL: "/", + Width: 1920, + Height: 1080, + MinWidth: 1280, + MinHeight: 800, + BackgroundColour: application.NewRGBA(13, 17, 23, 255), + Mac: application.MacWindow{ + TitleBar: application.MacTitleBarHiddenInset, + Appearance: application.NSAppearanceNameDarkAqua, + Backdrop: application.MacBackdropTranslucent, + }, + Windows: application.WindowsWindow{ + // Windows-specific options + }, + Linux: application.LinuxWindow{ + WebviewGpuPolicy: application.WebviewGpuPolicyOnDemand, + }, + Zoom: 1.0, +}) +``` + +### Asset serving + +```go +Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), +} +``` + +The `FileLoader` custom handler becomes asset middleware (see Section 6). + +### Embed directives + +`//go:embed all:dist` stays as-is (v3 uses the same pattern). Verify during +implementation that the embed path matches the actual frontend build output +directory — if it changes (e.g., to `ui/dist/`), the embed directive must match. +`//go:embed build/appicon.png` stays for icon embedding. + +### Lifecycle decomposition + +The 100-line `startup` closure in `main.go:198-298` gets split — each +controller's `Run(ctx)` becomes that service's `ServiceStartup`. Mapping: + +| v2 lifecycle | v3 equivalent | +|---|---| +| `OnStartup` (startup closure) | `ServiceStartup` on each service | +| `OnShutdown` (lambda) | `ServiceShutdown` on each service | +| `OnDomReady` (app.domReady) | `window.OnWindowEvent(events.Common.WindowRuntimeReady, ...)` | +| `OnBeforeClose` (app.beforeClose) | `window.RegisterHook(events.Common.WindowClosing, ...)` | + +### Platform options + +Relocated from app-level to window-level options: + +- Mac `TitleBarHiddenInset()` (function) -> `MacTitleBarHiddenInset` (struct field) +- Mac `WebviewIsTransparent`/`WindowIsTranslucent` -> `Backdrop: MacBackdropTranslucent` +- Windows `ZoomFactor: 1.0` -> `WebviewWindowOptions.Zoom = 1.0` (generic) +- Linux `WebviewGpuPolicy` -> `WebviewWindowOptions.Linux.WebviewGpuPolicy` + +## Section 2: Service Architecture + +### Service conversion table + +| Current v2 | v3 Service | Migration notes | +|---|---|---| +| `app` (App struct) | `AppService` | Dialogs move to builder pattern; `FileDialogOptions`/`FileFilter` wrappers removed | +| `diagnosticsClient` | `DiagnosticsService` | Direct service | +| `telemetry.NewTelemetryBinding()` | `TelemetryService` | Already self-contained | +| `settingsProvider` | `SettingsService` | SDK type; thin adapter for `ServiceStartup`. Init (categories, change handlers) moves here | +| `pluginManager` | `PluginManagerService` | `Initialize()` + `Run()` merge into `ServiceStartup`; `Shutdown()` -> `ServiceShutdown()` | +| `pluginLogManager` | `PluginLogService` | Already standalone | +| `devServerManager` | `DevServerService` | `Initialize()` -> `ServiceStartup`; `Shutdown()` -> `ServiceShutdown()` | +| `resourceController` + `resourceClient` | `ResourceService` | Client wrapper deleted; controller is the service | +| `settingsController` + `settingsClient` | `SettingsControllerService` | Same pattern | +| `execController` + `execClient` | `ExecService` | Same pattern | +| `networkerController` + `networkerClient` | `NetworkerService` | Same pattern | +| `logsController` + `logsClient` | `LogsService` | Same pattern | +| `metricController` + `metricClient` | `MetricService` | Same pattern | +| `dataController` + `dataClient` | `DataService` | Same pattern | +| `uiManager` + `uiClient` | `UIService` | Same pattern | +| `utilsClient` | `UtilsService` | Already standalone | + +### Context elimination + +Every service that stores `context.Context` and receives it via `Run(ctx)` or +`Initialize(ctx)` gets an `*application.App` field instead, set via +`application.Get()` in `ServiceStartup`. The 394+ context references reduce to +app references. Nil context guards (`if ctx == nil { return }`) become nil app +guards or are eliminated entirely. + +### Inter-service dependencies + +Constructor injections stay — services are still created in `main()` before +`application.New()`. The difference is that `Run(ctx)` calls disappear; +`ServiceStartup` handles initialization automatically. + +### Service ordering + +v3 calls `ServiceStartup` in registration order and `ServiceShutdown` in +**reverse** registration order. The current startup sequence must be preserved +in the `Services` array. The reverse shutdown order means services registered +last (like `AppService`) shut down first, and foundational services (like +`SettingsService`) shut down last — matching the expected teardown pattern: + +1. `SettingsService` (settings init, category registration) +2. `TelemetryService` (hot-toggle wiring, depends on settings) +3. `ResourceService` (controller startup) +4. `ExecService` +5. `LogsService` +6. `MetricService` +7. `NetworkerService` +8. `DataService` +9. `UIService` +10. `UtilsService` +11. `DevServerService` (needs context before plugin manager) +12. `PluginManagerService` (depends on all controllers) +13. `PluginLogService` +14. `SettingsControllerService` +15. `DiagnosticsService` +16. `AppService` (menus, window manager — last) + +### Startup closure decomposition + +The `startup` closure in `main.go:198-298` splits across services: + +- Settings initialization -> `SettingsService.ServiceStartup` +- Telemetry hot-toggle wiring -> `TelemetryService.ServiceStartup` +- Controller `Run(ctx)` calls -> each controller's `ServiceStartup` +- `devServerManager.Initialize(ctx)` -> `DevServerService.ServiceStartup` +- `pluginManager.Initialize(ctx)` + `Run(ctx)` -> `PluginManagerService.ServiceStartup` +- `MenuSetApplicationMenu` -> `AppService.ServiceStartup` using `app.Menu.Set()` + +## Section 3: Event System + +### Go-side EventEmitter interface + +Updated to drop context: + +```go +// v3 interface +type EventEmitter interface { + Emit(eventKey string, data ...any) +} + +// Production implementation +type appEmitter struct { + app *application.App +} + +func newAppEmitter(app *application.App) *appEmitter { + return &appEmitter{app: app} +} + +func (e *appEmitter) Emit(eventKey string, data ...any) { + e.app.Event.Emit(eventKey, data...) // Emit returns bool (true if cancelled by hook); interface ignores it +} + +// Test implementation +type recordingEmitter struct { + events []emittedEvent + mu sync.Mutex +} + +func (e *recordingEmitter) Emit(eventKey string, data ...any) { + e.mu.Lock() + defer e.mu.Unlock() + e.events = append(e.events, emittedEvent{eventKey, data}) +} +``` + +The `emitEvent()` helper and replaceable `eventEmitFn` var in `events.go` are +replaced by the interface-based approach. + +### Typed event registration + +All event constants with defined payloads get `RegisterEvent[T]` in `init()`: + +```go +func init() { + application.RegisterEvent[StateChangePayload](EventStateChange) + application.RegisterEvent[DeprecatedProtocolPayload](EventDeprecatedProtocol) + // resource events, exec stream events, log events, metric events, etc. +} +``` + +Dynamic event keys (e.g., `${pluginID}/${connectionID}/${resourceKey}/ADD`) register +the base event type once; string interpolation at emit time. + +For events that carry no data, use `application.Void`: + +```go +application.RegisterEvent[application.Void](EventInitComplete) +``` + +### Event listener cleanup + +Go services that register listeners via `app.Event.On()` or `app.Event.Once()` +store cleanup functions in a `[]func()` slice, called during `ServiceShutdown()`. +Both `On()` and `Once()` return cleanup functions that must be captured. +`Once()` auto-unsubscribes after the first call but the cleanup function is still +needed if the service shuts down before the event fires: + +```go +type MyService struct { + app *application.App + cleanups []func() +} + +func (s *MyService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + s.app = application.Get() + cleanup := s.app.Event.On("event:name", func(e *application.CustomEvent) { + // handle + }) + s.cleanups = append(s.cleanups, cleanup) + return nil +} + +func (s *MyService) ServiceShutdown() error { + for _, cleanup := range s.cleanups { + cleanup() + } + return nil +} +``` + +### Frontend event migration + +```typescript +// v2 +import { EventsOn, EventsEmit, EventsOff } from '@omniviewdev/runtime/runtime' +EventsOn("name", (data) => { ... }) + +// v3 +import { Events } from '@wailsio/runtime' +const cleanup = Events.On("name", (event) => { + const data = event.data // unwrap from event object +}) +``` + +Existing `useEffect` + cleanup patterns map cleanly. Key change is unwrapping +`event.data` instead of receiving raw payload. + +### Concurrency consideration + +v3 dispatches each listener callback in its own goroutine — no ordering +guarantees. The exec controller's stream events and resource controller's watch +state events need verification during implementation. If ordering is required, +the listener should buffer and sequence internally. + +## Section 4: Frontend Migration + +### Binding imports + +Generated into `packages/omniviewdev-runtime/src/bindings/` via +`wails3 generate bindings`. Import paths change: + +```typescript +// v2 +import { SubscribeResource } from '@omniviewdev/runtime/wailsjs/go/resource/Client' + +// v3 +import { SubscribeResource } from '@omniviewdev/runtime/bindings/resource/ResourceService' +``` + +### Runtime imports + +Custom runtime wrapper at `packages/omniviewdev-runtime/src/wailsjs/runtime/` +replaced by `@wailsio/runtime`. The `omniviewdev-runtime` package re-exports: + +```typescript +export { Events, Window, Clipboard, Browser, Application } from '@wailsio/runtime' +``` + +Existing hooks update internal imports; their public API stays the same. + +### Vite plugin + +```typescript +import wails from '@wailsio/runtime/plugins/vite' + +export default defineConfig({ + plugins: [react(), wails('./bindings')], +}) +``` + +### WML adoption + +Simple window operations use declarative attributes: + +```html + + +``` + +Complex interactions (resource subscriptions, exec streams) stay in TypeScript. + +**Important**: `WML.Reload()` must be called after React DOM updates for WML +attributes to be picked up. Use `useEffect(() => { WML.Reload(); }, [])` in +components that use WML attributes. + +### Package updates + +- Add `@wailsio/runtime` to `package.json` +- Delete old `packages/omniviewdev-runtime/src/wailsjs/` directory after migration +- Generated type models from v3 binding generator replace manual `models.ts` + +## Section 5: Menu System + +### App menus + +Menus created via `app.NewMenu()` with `OnClick` callbacks: + +```go +func SetupMenus(app *application.App, window *application.WebviewWindow) { + menu := app.NewMenu() + + if runtime.GOOS == "darwin" { + menu.AddRole(application.AppMenu) + menu.AddRole(application.EditMenu) + menu.AddRole(application.WindowMenu) + } + + viewMenu := menu.AddSubmenu("View") + viewMenu.Add("Reload").SetAccelerator("CmdOrCtrl+R").OnClick(func(ctx *application.Context) { + window.Reload() + }) + // ... + app.Menu.Set(menu) +} +``` + +Key changes: +- No `context.Context` parameter +- `menu.CallbackData` -> `*application.Context` +- `keys.CmdOrCtrl("r")` -> `SetAccelerator("CmdOrCtrl+R")` +- `menu.AppMenu()` -> `AddRole(application.AppMenu)` + +### Package structure + +``` +backend/menus/ +├── app.go # Application menu (View menu, role menus) +├── keybindings.go # Standalone key bindings +└── context.go # Context menu registration (Go-side definitions) +``` + +### Context menu readiness + +Go-side context menus are defined and registered via +`app.RegisterContextMenu("id", menu)` during this migration. The frontend +doesn't use them yet — the CSS custom properties +(`style="--custom-contextmenu: id"`) get added in a future sprint. Having the +Go-side definitions ready means future migration is just adding CSS properties +to HTML elements, no backend work needed. + +```go +// context.go — register menus now, wire to frontend later +editorMenu := app.NewContextMenu() +editorMenu.Add("Cut").OnClick(cutHandler) +editorMenu.Add("Copy").OnClick(copyHandler) +editorMenu.Add("Paste").OnClick(pasteHandler) +app.RegisterContextMenu("editor", editorMenu) +``` + +```html + +
Right-click for options
+``` + +During implementation, identify all frontend-managed context menus and create +corresponding Go-side definitions. + +### Standalone key bindings + +View menu items that exist primarily as shortcuts (terminal create, drawer toggle, +sidebar toggle) get `app.KeyBinding.Add()` in addition to menu items. Decouples +shortcuts from the menu and supports per-window behavior in the future. + +## Section 6: FileLoader as Asset Middleware + +The `FileLoader` custom asset handler migrates to v3's `AssetOptions.Middleware` +field. This preserves the existing URL scheme — frontend `fetch("/_/...")` calls +continue to work without changes. Using a routed service would change URLs to +`http://wails.localhost/_/...` which would break existing frontend references. + +```go +Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), + Middleware: func(next http.Handler) http.Handler { + pluginAssetHandler := NewPluginAssetHandler(log) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/_/") { + pluginAssetHandler.ServeHTTP(w, r) + return + } + next.ServeHTTP(w, r) + }) + }, +} +``` + +The `PluginAssetHandler` (renamed from `FileLoader`) keeps the same security +logic: allowlist regex, path containment under `~/.omniview`, MIME type forcing, +no-cache for `remoteEntry.js`. The struct is simplified — it no longer needs to +embed `http.Handler` since it's not used as a standalone handler. It no longer +needs Wails context since v3 middleware receives standard `http.Request`. + +## Section 7: Multi-Window Architecture + +### Window naming + +Every window gets a name at creation for `app.Window.GetByName()` access. +Main window is named `"main"`. + +### WindowManager with main window recycling + +Internal helper (not a v3 service) that centralizes window creation and +implements **hide-on-close for the main window**. The main window holds all +application state and is expensive to recreate — closing it hides to tray/dock +instead of quitting. Secondary windows (settings, devtools) are ephemeral and +close normally since they're cheap to recreate. + +```go +type WindowManager struct { + app *application.App +} + +func NewWindowManager(app *application.App, main *application.WebviewWindow) *WindowManager { + wm := &WindowManager{app: app} + wm.registerMainWindowHideOnClose(main) + return wm +} + +func (wm *WindowManager) Main() *application.WebviewWindow { + return wm.app.Window.GetByName("main") +} + +// registerMainWindowHideOnClose intercepts close on the main window, +// hiding it instead of quitting the app. Re-show from tray/dock. +func (wm *WindowManager) registerMainWindowHideOnClose(w *application.WebviewWindow) { + w.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { + w.Hide() + e.Cancel() // prevent quit — app stays alive in tray/dock + }) +} + +// OpenSettings creates a fresh settings window. Closes normally. +func (wm *WindowManager) OpenSettings() *application.WebviewWindow { + return wm.app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "settings", + Title: "Settings — Omniview", + URL: "/#/settings", + Width: 900, + Height: 700, + UseApplicationMenu: true, + }) +} + +func (wm *WindowManager) OpenDevtools() *application.WebviewWindow { /* same pattern */ } +``` + +This follows the [Wails v3 documented best practice](~/Repos/wails/docs/src/content/docs/features/windows/multiple.mdx) +for efficient window management. The main window is the primary candidate for +recycling since it holds all the app state and plugin connections. Secondary +windows are stateless and close/recreate naturally. + +### WindowPool for detachable panels (future) + +For the future detachable panels feature (popping out terminals, log viewers, +etc.), a `WindowPool` should be used to efficiently manage multiple ephemeral +windows of the same type. The pool hides released windows instead of destroying +them and reuses them on acquire: + +```go +type WindowPool struct { + app *application.App + available []*application.WebviewWindow + inUse map[uint]*application.WebviewWindow + mu sync.Mutex +} + +func (wp *WindowPool) Acquire(opts application.WebviewWindowOptions) *application.WebviewWindow { + wp.mu.Lock() + defer wp.mu.Unlock() + + // Reuse a hidden window if available + if len(wp.available) > 0 { + w := wp.available[len(wp.available)-1] + wp.available = wp.available[:len(wp.available)-1] + wp.inUse[w.ID()] = w + w.SetURL(opts.URL) + w.SetTitle(opts.Title) + w.Show() + return w + } + + // Create new window + w := wp.app.Window.NewWithOptions(opts) + wp.inUse[w.ID()] = w + w.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { + wp.Release(w) + e.Cancel() + }) + return w +} + +func (wp *WindowPool) Release(w *application.WebviewWindow) { + wp.mu.Lock() + defer wp.mu.Unlock() + delete(wp.inUse, w.ID()) + w.Hide() + wp.available = append(wp.available, w) +} +``` + +The `WindowManager` should be structured so that `WindowPool` can be integrated +later without changing the manager's public API. The pool is NOT implemented in +this migration — it is documented here so the architecture supports it. + +### Window-scoped events + +All events broadcast via `app.Event.Emit()` initially (matching current +single-window behavior). Per-window targeting via `window.EmitEvent()` available +when needed. + +### Frontend routing + +React app supports different URL paths (`/`, `/settings`, `/devtools`). Each +window loads the same frontend bundle at a different route. Uses hash routing +(`/#/settings`, `/#/devtools`) to match the existing `createHashRouter` setup. + +### Phase 1 (this migration) + +Only main window created with hide-on-close recycling (hides to tray/dock +instead of quitting). `WindowManager` implemented with `Main()`, +`OpenSettings()`, `OpenDevtools()` ready but not wired into menus. Frontend +routing set up so routes render correctly. + +### Future work + +- Wire menu items and key bindings to open secondary windows +- Add window-scoped event targeting +- Implement `WindowPool` for detachable panels: popping out terminal sessions, + log viewers, etc. into pooled windows (e.g., `/#/detached/terminal/{id}`) + +## Section 8: Build System + +### Structure + +``` +Taskfile.yml # Root orchestrator +build/ +├── config.yml # Project metadata, dev mode config +├── appicon.png # App icon source +├── Taskfile.yml # Common tasks (frontend, bindings, icons) +├── darwin/ +│ ├── Taskfile.yml # macOS build/package/sign/notarize +│ └── Info.plist +├── windows/ +│ ├── Taskfile.yml # Windows build/package +│ └── info.json +└── linux/ + └── Taskfile.yml # Linux build/package +``` + +### Task mapping from Makefile + +| Makefile target | Taskfile task | +|---|---| +| `make dev` | `task dev` | +| `make build` | `task build` | +| `make go-build` | `task check:go-build` | +| `make go-vet` | `task check:go-vet` | +| `make go-test` | `task check:go-test` | +| `make go-lint` | `task check:go-lint` | +| `make bindings` | `task common:bindings` | +| `make bindings-check` | `task check:bindings` | +| `make ui-install` | `task common:frontend:install` | +| `make ui-build` | `task common:frontend:build` | +| `make ui-lint` | `task check:ui-lint` | +| `make ui-typecheck` | `task check:ui-typecheck` | +| `make check` | `task check` (runs all) | +| `make packages` | `task common:packages` | +| `make sign` | `task darwin:sign` | +| `make notarize` | `task darwin:notarize` | + +### config.yml + +```yaml +version: '3' +info: + companyName: "Omniview" + productName: "Omniview" + productIdentifier: "dev.omniview.app" + description: "The modern, lightweight, pluggable cross-platform IDE for DevOps engineers" + version: "0.0.1" + +dev_mode: + root_path: . + log_level: warn + debounce: 1000 + ignore: + dir: [.git, node_modules, frontend, bin, dist, packages] + file: [.DS_Store, .gitignore] + watched_extension: ["*.go"] + git_ignore: true +``` + +### CI updates + +`.github/workflows/pr-checks.yml` changes from `make` targets to `task` targets. +`go-task` installed in CI via `go install github.com/go-task/task/v3/cmd/task@latest` +or GitHub Action. + +### .gitignore additions + +- `.task` (Task runner checksum cache) + +### Files to delete + +- `wails.json` +- `Makefile` + +## Section 9: Migration Phases + +### Phase 1: App Shell + +- Convert `main.go` to `application.New()` + `app.Run()` +- Create main window with name `"main"` and all current options (including `UseApplicationMenu: true` for Windows/Linux) +- Set up `Taskfile.yml` + `build/config.yml`; delete `wails.json` and `Makefile` +- Migrate `FileLoader` -> `PluginAssetHandler` as asset middleware +- Migrate menus to v3 API; set up `menus/` package (app menus, keybindings, context menu stubs) +- Set up `WindowManager` with `Main()`, stubbed `OpenSettings()`, `OpenDevtools()` +- Update Go module dependency to Wails v3 +- Install `@wailsio/runtime` npm dependency and add Wails Vite plugin to `vite.config.ts` (required before any frontend migration in later phases) +- **Checkpoint**: App boots with `task dev`, main window renders, menus work, plugin assets load + +### Phase 2: Event System Foundation + +- Update `EventEmitter` interface to v3 signature (drop context) +- Create `appEmitter` using `*application.App` +- Update `recordingEmitter` for tests +- Remove `eventEmitFn` var and `emitEvent()` helper +- Add `RegisterEvent[T]` calls in `init()` for all typed event payloads +- **Checkpoint**: Go compiles, existing tests pass with updated `recordingEmitter` + +### Phase 3: Resource Controller (Proving Ground) + +- Collapse `resource.Controller` + `resource.Client` into `ResourceService` +- Replace stored `context.Context` with `*application.App` +- Migrate all resource event emission to v3 patterns +- Update frontend hooks (`useResources`, `useConnections`) to `@wailsio/runtime` +- Update frontend binding imports to new paths +- **Checkpoint**: Resource subscription, watch states, ADD/UPDATE/DELETE events work end-to-end + +### Phase 4: Remaining Services + +Migrate in dependency order, each following Phase 3 pattern. Names below use +the v3 service names from the conversion table in Section 2: + +1. `settingsController + settingsClient` -> `SettingsControllerService` +2. `execController + execClient` -> `ExecService` +3. `logsController + logsClient` -> `LogsService` +4. `metricController + metricClient` -> `MetricService` +5. `networkerController + networkerClient` -> `NetworkerService` +6. `dataController + dataClient` -> `DataService` +7. `uiManager + uiClient` -> `UIService` +8. `utilsClient` -> `UtilsService` +9. `pluginManager` -> `PluginManagerService` +10. `devServerManager` -> `DevServerService` +11. `diagnosticsClient` -> `DiagnosticsService` +12. `telemetry.NewTelemetryBinding()` -> `TelemetryService` +13. `settingsProvider` -> `SettingsService` (adapter) +14. `pluginLogManager` -> `PluginLogService` +15. `app` -> `AppService` + +**Checkpoint** per service: methods callable from frontend, events flow correctly. + +### Phase 5: Frontend Finalization + +- Update `packages/omniviewdev-runtime` exports (re-export v3 runtime types) +- Delete old `wailsjs/` directory +- Set up frontend routing for multi-window readiness +- Add WML attributes where appropriate +- Run `wails3 generate bindings` and verify TypeScript types +- **Checkpoint**: Full app works end-to-end + +### Phase 6: Cleanup & CI + +- Verify zero remaining `github.com/wailsapp/wails/v2` imports +- Update `.github/workflows/pr-checks.yml` for Taskfile +- Update `.gitignore` +- Run full migration review checklist +- **Checkpoint**: `task build` succeeds, `task check` passes, production build works + +## Review Checklist + +- [ ] No remaining `github.com/wailsapp/wails/v2` imports +- [ ] No `wails.Run(...)` — replaced with `application.New(...)` + `app.Run()` +- [ ] App type is `*application.App` not `*application.Application` +- [ ] Services registered via `application.NewService(...)` or `application.NewServiceWithOptions(...)` +- [ ] Old `startup(ctx)` replaced with `ServiceStartup(ctx, options) error` +- [ ] `ServiceShutdown()` takes no parameters +- [ ] Runtime calls use object methods, not `runtime.Something(ctx, ...)` +- [ ] Dialogs use builder pattern, not direct function calls +- [ ] Frontend imports use `./bindings/...` not `wailsjs/...` +- [ ] Frontend runtime from `@wailsio/runtime` not `../wailsjs/runtime/runtime` +- [ ] Go event handlers receive `*application.CustomEvent`, not `func(data ...interface{})` +- [ ] Frontend event handlers unwrap `event.data` +- [ ] Event listeners use cleanup functions from `On()`, not `Off(name)` +- [ ] Typed events registered via `RegisterEvent[T](name)` in `init()` +- [ ] `wails.json` deleted, replaced with `build/config.yml` + `Taskfile.yml` +- [ ] `Makefile` deleted, all targets migrated to Taskfile +- [ ] Embed directive uses `//go:embed all:dist` (keep `all:` prefix) +- [ ] Vite config uses `@wailsio/runtime/plugins/vite` +- [ ] `.gitignore` includes `.task` +- [ ] CLI commands use `task dev` / `task build` +- [ ] Context menus defined in Go via `app.RegisterContextMenu()` with CSS `--custom-contextmenu` +- [ ] Windows on Windows/Linux use `UseApplicationMenu: true` in window options +- [ ] `WindowManager` implemented with named windows and hide-on-close recycling for main window +- [ ] Frontend routing supports `/`, `/settings`, `/devtools` paths +- [ ] All test code uses `testify` (`assert`/`require`) — no raw `t.Fatalf`/`t.Errorf` in modified files diff --git a/e2e/package.json b/e2e/package.json index a15a25be..3faa0eaf 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -9,6 +9,6 @@ }, "devDependencies": { "@playwright/test": "1.50.1", - "@types/node": "^20.11.30" + "@types/node": "^25.5.0" } } diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts index 9a874b7d..74784aa8 100644 --- a/e2e/playwright.config.ts +++ b/e2e/playwright.config.ts @@ -1,5 +1,13 @@ import { defineConfig } from '@playwright/test'; +// E2E tests connect to the Wails app running in server mode (-tags server) +// on port 34115. Server mode provides a full HTTP server with the Go backend, +// allowing Playwright to test the complete app in a browser. +// +// NOTE: Wails v3 alpha.74 server mode has build tag conflicts on macOS +// (darwin files don't exclude the server tag). Until this is fixed upstream, +// E2E tests can only run in CI on Linux. Track: Taskfile.yml TODO. + export default defineConfig({ testDir: './tests', timeout: 30_000, @@ -15,12 +23,11 @@ export default defineConfig({ video: 'on-first-retry', trace: 'on-first-retry', }, - // Locally, Playwright manages wails dev lifecycle. - // In CI, wails dev is started as a background step because xvfb-run + - // wails dev creates a process tree that doesn't shut down cleanly. + // In CI (Linux), build and run in server mode. + // Locally on macOS, server mode is blocked — run manually if needed. webServer: process.env.CI ? undefined : { - command: 'cd .. && wails dev -loglevel Error', - url: 'http://localhost:34115', + command: 'cd .. && task run:server', + url: 'http://localhost:34115/health', timeout: 120_000, reuseExistingServer: true, }, diff --git a/go.mod b/go.mod index 4633b0a2..461bef84 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/tidwall/gjson v1.18.0 github.com/vrischmann/userdir v0.0.0-20151206171402-20f291cebd68 github.com/wailsapp/mimetype v1.4.1 - github.com/wailsapp/wails/v2 v2.11.0 + github.com/wailsapp/wails/v3 v3.0.0-alpha.74 go.opentelemetry.io/contrib/bridges/otelzap v0.17.0 go.opentelemetry.io/contrib/instrumentation/runtime v0.67.0 go.opentelemetry.io/otel v1.42.0 @@ -41,40 +41,52 @@ require ( ) require ( + dario.cat/mergo v1.0.2 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProtonMail/go-crypto v1.3.0 // indirect + github.com/adrg/xdg v0.5.3 // indirect github.com/bep/debounce v1.2.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.6.3 // indirect + github.com/coder/websocket v1.8.14 // indirect + github.com/cyphar/filepath-securejoin v0.6.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/ebitengine/purego v0.9.1 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.7.0 // indirect + github.com/go-git/go-git/v5 v5.16.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/labstack/echo/v4 v4.13.3 // indirect - github.com/labstack/gommon v0.4.2 // indirect + github.com/kevinburke/ssh_config v1.4.0 // indirect + github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leaanthony/go-ansi-parser v1.6.1 // indirect - github.com/leaanthony/gosod v1.0.4 // indirect - github.com/leaanthony/slicer v1.6.0 // indirect github.com/leaanthony/u v1.1.1 // indirect + github.com/lmittmann/tint v1.1.2 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -84,18 +96,19 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/onsi/ginkgo/v2 v2.22.0 // indirect github.com/onsi/gomega v1.36.1 // indirect + github.com/pjbgf/sha1cd v0.5.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/samber/lo v1.49.1 // indirect + github.com/samber/lo v1.52.0 // indirect + github.com/sergi/go-diff v1.4.0 // indirect + github.com/skeema/knownhosts v1.3.2 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/tkrajina/go-reflector v0.5.8 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wailsapp/go-webview2 v1.0.22 // indirect + github.com/wailsapp/go-webview2 v1.0.23 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect @@ -114,6 +127,7 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect k8s.io/api v0.33.0 // indirect k8s.io/apimachinery v0.33.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect diff --git a/go.sum b/go.sum index 8966ba70..b61b8364 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,16 @@ +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= +github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= +github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= +github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= @@ -6,14 +19,26 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= +github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= +github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= +github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -22,10 +47,22 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-enry/go-enry/v2 v2.8.7 h1:vbab0pcf5Yo1cHQLzbWZ+QomUh3EfEU8EiR5n7W0lnQ= github.com/go-enry/go-enry/v2 v2.8.7/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.7.0 h1:83lBUJhGWhYp0ngzCMSgllhUSuoHP1iEWYjsPl9nwqM= +github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y= +github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e h1:Lf/gRkoycfOBPa42vU2bbgPurFong6zXeFtPoxholzU= +github.com/go-json-experiment/json v0.0.0-20251027170946-4849db3c2f7e/go.mod h1:uNVvRXArCGbZ508SxYYTC5v1JWoz2voff5pm25jU1Ok= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -42,10 +79,12 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= @@ -59,8 +98,6 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgY github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= -github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= @@ -77,6 +114,8 @@ github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshf github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 h1:njuLRcjAuMKr7kI3D85AXWkw6/+v9PwtV6M6o11sWHQ= github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= @@ -85,28 +124,27 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ= +github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= +github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= -github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= -github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= -github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI= -github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= -github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= -github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= +github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w= +github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= @@ -139,6 +177,8 @@ github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= +github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -151,16 +191,23 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= -github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= +github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= +github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= +github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= +github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -174,22 +221,18 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ= -github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vrischmann/userdir v0.0.0-20151206171402-20f291cebd68 h1:Ah2/69Z24rwD6OByyOdpJDmttftz0FTF8Q4QZ/SF1E4= github.com/vrischmann/userdir v0.0.0-20151206171402-20f291cebd68/go.mod h1:EqKqAeKddSL9XSGnfXd/7iLncccKhR16HBKVva7ENw8= -github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58= -github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= +github.com/wailsapp/go-webview2 v1.0.23 h1:jmv8qhz1lHibCc79bMM/a/FqOnnzOGEisLav+a0b9P0= +github.com/wailsapp/go-webview2 v1.0.23/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/wailsapp/wails/v2 v2.11.0 h1:seLacV8pqupq32IjS4Y7V8ucab0WZwtK6VvUVxSBtqQ= -github.com/wailsapp/wails/v2 v2.11.0/go.mod h1:jrf0ZaM6+GBc1wRmXsM8cIvzlg0karYin3erahI4+0k= +github.com/wailsapp/wails/v3 v3.0.0-alpha.74 h1:wRm1EiDQtxDisXk46NtpiBH90STwfKp36NrTDwOEdxw= +github.com/wailsapp/wails/v3 v3.0.0-alpha.74/go.mod h1:4saK4A4K9970X+X7RkMwP2lyGbLogcUz54wVeq4C/V8= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -241,6 +284,7 @@ go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -250,6 +294,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= @@ -261,15 +306,19 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -307,6 +356,7 @@ google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhH google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= @@ -317,6 +367,9 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/main.go b/main.go index 75dde3fb..49735c88 100644 --- a/main.go +++ b/main.go @@ -3,21 +3,23 @@ package main import ( "context" "embed" + "encoding/json" "fmt" "net/url" "os" "path/filepath" + "time" logging "github.com/omniviewdev/plugin-sdk/log" + "github.com/omniviewdev/plugin-sdk/pkg/config" + sdktypes "github.com/omniviewdev/plugin-sdk/pkg/types" + execsdk "github.com/omniviewdev/plugin-sdk/pkg/v1/exec" + logssdk "github.com/omniviewdev/plugin-sdk/pkg/v1/logs" + metricsdk "github.com/omniviewdev/plugin-sdk/pkg/v1/metric" + networkersdk "github.com/omniviewdev/plugin-sdk/pkg/v1/networker" + sdkresource "github.com/omniviewdev/plugin-sdk/pkg/v1/resource" pkgsettings "github.com/omniviewdev/plugin-sdk/settings" - "github.com/wailsapp/wails/v2" - "github.com/wailsapp/wails/v2/pkg/logger" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/assetserver" - "github.com/wailsapp/wails/v2/pkg/options/linux" - "github.com/wailsapp/wails/v2/pkg/options/mac" - "github.com/wailsapp/wails/v2/pkg/options/windows" - "github.com/wailsapp/wails/v2/pkg/runtime" + "github.com/wailsapp/wails/v3/pkg/application" "go.uber.org/zap" @@ -37,12 +39,10 @@ import ( "github.com/omniviewdev/omniview/backend/pkg/plugin/types" "github.com/omniviewdev/omniview/backend/pkg/plugin/ui" "github.com/omniviewdev/omniview/backend/pkg/plugin/utils" + "github.com/omniviewdev/omniview/backend/window" coresettings "github.com/omniviewdev/omniview/internal/settings" "github.com/omniviewdev/omniview/internal/telemetry" "github.com/omniviewdev/omniview/internal/version" - - sdkresource "github.com/omniviewdev/plugin-sdk/pkg/v1/resource" - sdktypes "github.com/omniviewdev/plugin-sdk/pkg/types" ) const ( @@ -77,6 +77,815 @@ func (a *pluginReloaderAdapter) ReloadPlugin(id string) error { return err } +// PluginManagerService exposes only the frontend-safe methods of plugin.Manager. +// Internal methods (SetDevServerChecker, SetPluginLogManager, HandlePluginCrash, +// Initialize, Run, Shutdown) are excluded to avoid binding warnings from +// interface/function-type parameters. +type PluginManagerService struct { + mgr plugin.Manager +} + +func (s *PluginManagerService) InstallInDevMode() (*config.PluginMeta, error) { + return s.mgr.InstallInDevMode() +} +func (s *PluginManagerService) InstallFromPathPrompt() (*config.PluginMeta, error) { + return s.mgr.InstallFromPathPrompt() +} +func (s *PluginManagerService) InstallPluginFromPath(path string) (*config.PluginMeta, error) { + return s.mgr.InstallPluginFromPath(path) +} +func (s *PluginManagerService) InstallPluginVersion(pluginID, version string) (*config.PluginMeta, error) { + return s.mgr.InstallPluginVersion(pluginID, version) +} +func (s *PluginManagerService) LoadPlugin(id string, opts *plugin.LoadPluginOptions) (sdktypes.PluginInfo, error) { + return s.mgr.LoadPlugin(id, opts) +} +func (s *PluginManagerService) ReloadPlugin(id string) (sdktypes.PluginInfo, error) { + return s.mgr.ReloadPlugin(id) +} +func (s *PluginManagerService) RetryFailedPlugin(id string) (sdktypes.PluginInfo, error) { + return s.mgr.RetryFailedPlugin(id) +} +func (s *PluginManagerService) UninstallPlugin(id string) (sdktypes.PluginInfo, error) { + return s.mgr.UninstallPlugin(id) +} +func (s *PluginManagerService) GetPlugin(id string) (sdktypes.PluginInfo, error) { + return s.mgr.GetPlugin(id) +} +func (s *PluginManagerService) ListPlugins() []sdktypes.PluginInfo { + return s.mgr.ListPlugins() +} +func (s *PluginManagerService) GetPluginMeta(id string) (config.PluginMeta, error) { + return s.mgr.GetPluginMeta(id) +} +func (s *PluginManagerService) ListPluginMetas() []config.PluginMeta { + return s.mgr.ListPluginMetas() +} +func (s *PluginManagerService) ListAvailablePlugins() ([]registry.AvailablePlugin, error) { + return s.mgr.ListAvailablePlugins() +} +func (s *PluginManagerService) SearchPlugins(query, category, sort string) ([]registry.AvailablePlugin, error) { + return s.mgr.SearchPlugins(query, category, sort) +} +func (s *PluginManagerService) GetPluginReadme(pluginID string) (string, error) { + return s.mgr.GetPluginReadme(pluginID) +} +func (s *PluginManagerService) GetPluginVersions(pluginID string) ([]registry.VersionInfo, error) { + return s.mgr.GetPluginVersions(pluginID) +} +func (s *PluginManagerService) GetPluginReviews(pluginID string, page int) ([]registry.Review, error) { + return s.mgr.GetPluginReviews(pluginID, page) +} +func (s *PluginManagerService) GetPluginDownloadStats(pluginID string) (*registry.DownloadStats, error) { + return s.mgr.GetPluginDownloadStats(pluginID) +} +func (s *PluginManagerService) GetPluginReleaseHistory(pluginID string) ([]registry.VersionInfo, error) { + return s.mgr.GetPluginReleaseHistory(pluginID) +} + +// PluginLogService exposes only frontend-safe methods of pluginlog.Manager. +// Excludes OnEmit (EmitFunc type), Stream (io.Writer), Close, LogDir. +type PluginLogService struct { + mgr *pluginlog.Manager +} + +func (s *PluginLogService) GetLogs(pluginID string, count int) []pluginlog.LogEntry { + return s.mgr.GetLogs(pluginID, count) +} +func (s *PluginLogService) ListStreams() []string { + return s.mgr.ListStreams() +} +func (s *PluginLogService) SearchLogs(pluginID, pattern string) ([]pluginlog.LogEntry, error) { + return s.mgr.SearchLogs(pluginID, pattern) +} +func (s *PluginLogService) Subscribe(pluginID string) int { + return s.mgr.Subscribe(pluginID) +} +func (s *PluginLogService) Unsubscribe(pluginID string) int { + return s.mgr.Unsubscribe(pluginID) +} + +// DevServerService exposes only frontend-safe methods of devserver.DevServerManager. +// The DevServerManager implements ServiceStartup/ServiceShutdown directly, +// but registering it raw causes service/model shadowing. This wrapper separates +// the service identity from the model type. +type DevServerService struct { + mgr *devserver.DevServerManager +} + +func (s *DevServerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + return s.mgr.ServiceStartup(ctx, options) +} +func (s *DevServerService) ServiceShutdown() error { + return s.mgr.ServiceShutdown() +} +func (s *DevServerService) StartDevServer(pluginID string) (devserver.DevServerState, error) { + return s.mgr.StartDevServer(pluginID) +} +func (s *DevServerService) StartDevServerForPath(pluginID, devPath string) (devserver.DevServerState, error) { + return s.mgr.StartDevServerForPath(pluginID, devPath) +} +func (s *DevServerService) StopDevServer(pluginID string) error { + return s.mgr.StopDevServer(pluginID) +} +func (s *DevServerService) RestartDevServer(pluginID string) (devserver.DevServerState, error) { + return s.mgr.RestartDevServer(pluginID) +} +func (s *DevServerService) RebuildPlugin(pluginID string) error { + return s.mgr.RebuildPlugin(pluginID) +} +func (s *DevServerService) GetDevServerState(pluginID string) devserver.DevServerState { + return s.mgr.GetDevServerState(pluginID) +} +func (s *DevServerService) ListDevServerStates() []devserver.DevServerState { + return s.mgr.ListDevServerStates() +} +func (s *DevServerService) GetDevServerLogs(pluginID string, count int) []devserver.LogEntry { + return s.mgr.GetDevServerLogs(pluginID, count) +} +func (s *DevServerService) IsManaged(pluginID string) bool { + return s.mgr.IsManaged(pluginID) +} +func (s *DevServerService) GetExternalPluginInfo(pluginID string) *devserver.DevInfoFile { + return s.mgr.GetExternalPluginInfo(pluginID) +} + +// --------------------------------------------------------------------------- +// ResourceControllerService — explicit delegation (no interface embedding). +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, Run, SetCrashCallback, Graph, HasPlugin +// --------------------------------------------------------------------------- + +type ResourceControllerService struct { + ctrl resource.Controller +} + +func (s *ResourceControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} + +func (s *ResourceControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} + +// CRUD +func (s *ResourceControllerService) Get(pluginID, connectionID, key string, input sdkresource.GetInput) (*sdkresource.GetResult, error) { + return s.ctrl.Get(pluginID, connectionID, key, input) +} +func (s *ResourceControllerService) List(pluginID, connectionID, key string, input sdkresource.ListInput) (*sdkresource.ListResult, error) { + return s.ctrl.List(pluginID, connectionID, key, input) +} +func (s *ResourceControllerService) Find(pluginID, connectionID, key string, input sdkresource.FindInput) (*sdkresource.FindResult, error) { + return s.ctrl.Find(pluginID, connectionID, key, input) +} +func (s *ResourceControllerService) Create(pluginID, connectionID, key string, input sdkresource.CreateInput) (*sdkresource.CreateResult, error) { + return s.ctrl.Create(pluginID, connectionID, key, input) +} +func (s *ResourceControllerService) Update(pluginID, connectionID, key string, input sdkresource.UpdateInput) (*sdkresource.UpdateResult, error) { + return s.ctrl.Update(pluginID, connectionID, key, input) +} +func (s *ResourceControllerService) Delete(pluginID, connectionID, key string, input sdkresource.DeleteInput) (*sdkresource.DeleteResult, error) { + return s.ctrl.Delete(pluginID, connectionID, key, input) +} + +// Connection lifecycle +func (s *ResourceControllerService) StartConnection(pluginID, connectionID string) (sdktypes.ConnectionStatus, error) { + return s.ctrl.StartConnection(pluginID, connectionID) +} +func (s *ResourceControllerService) StopConnection(pluginID, connectionID string) (sdktypes.Connection, error) { + return s.ctrl.StopConnection(pluginID, connectionID) +} +func (s *ResourceControllerService) CheckConnection(pluginID, connectionID string) (sdktypes.ConnectionStatus, error) { + return s.ctrl.CheckConnection(pluginID, connectionID) +} +func (s *ResourceControllerService) LoadConnections(pluginID string) ([]sdktypes.Connection, error) { + return s.ctrl.LoadConnections(pluginID) +} +func (s *ResourceControllerService) ListConnections(pluginID string) ([]sdktypes.Connection, error) { + return s.ctrl.ListConnections(pluginID) +} +func (s *ResourceControllerService) ListAllConnections() (map[string][]sdktypes.Connection, error) { + return s.ctrl.ListAllConnections() +} +func (s *ResourceControllerService) GetAllConnectionStates() (map[string][]resource.ConnectionState, error) { + return s.ctrl.GetAllConnectionStates() +} +func (s *ResourceControllerService) GetConnection(pluginID, connectionID string) (sdktypes.Connection, error) { + return s.ctrl.GetConnection(pluginID, connectionID) +} +func (s *ResourceControllerService) GetConnectionNamespaces(pluginID, connectionID string) ([]string, error) { + return s.ctrl.GetConnectionNamespaces(pluginID, connectionID) +} +func (s *ResourceControllerService) AddConnection(pluginID string, connection sdktypes.Connection) error { + return s.ctrl.AddConnection(pluginID, connection) +} +func (s *ResourceControllerService) UpdateConnection(pluginID string, connection sdktypes.Connection) (sdktypes.Connection, error) { + return s.ctrl.UpdateConnection(pluginID, connection) +} +func (s *ResourceControllerService) RemoveConnection(pluginID, connectionID string) error { + return s.ctrl.RemoveConnection(pluginID, connectionID) +} + +// Watch lifecycle +func (s *ResourceControllerService) StartConnectionWatch(pluginID, connectionID string) error { + return s.ctrl.StartConnectionWatch(pluginID, connectionID) +} +func (s *ResourceControllerService) StopConnectionWatch(pluginID, connectionID string) error { + return s.ctrl.StopConnectionWatch(pluginID, connectionID) +} +func (s *ResourceControllerService) GetWatchState(pluginID, connectionID string) (*sdkresource.WatchConnectionSummary, error) { + return s.ctrl.GetWatchState(pluginID, connectionID) +} +func (s *ResourceControllerService) EnsureResourceWatch(pluginID, connectionID, resourceKey string) error { + return s.ctrl.EnsureResourceWatch(pluginID, connectionID, resourceKey) +} +func (s *ResourceControllerService) StopResourceWatch(pluginID, connectionID, resourceKey string) error { + return s.ctrl.StopResourceWatch(pluginID, connectionID, resourceKey) +} +func (s *ResourceControllerService) RestartResourceWatch(pluginID, connectionID, resourceKey string) error { + return s.ctrl.RestartResourceWatch(pluginID, connectionID, resourceKey) +} +func (s *ResourceControllerService) IsResourceWatchRunning(pluginID, connectionID, resourceKey string) (bool, error) { + return s.ctrl.IsResourceWatchRunning(pluginID, connectionID, resourceKey) +} + +// Subscriptions +func (s *ResourceControllerService) SubscribeResource(pluginID, connectionID, resourceKey string) error { + return s.ctrl.SubscribeResource(pluginID, connectionID, resourceKey) +} +func (s *ResourceControllerService) UnsubscribeResource(pluginID, connectionID, resourceKey string) error { + return s.ctrl.UnsubscribeResource(pluginID, connectionID, resourceKey) +} + +// Type metadata +func (s *ResourceControllerService) GetResourceGroups(pluginID, connectionID string) map[string]sdkresource.ResourceGroup { + return s.ctrl.GetResourceGroups(pluginID, connectionID) +} +func (s *ResourceControllerService) GetResourceGroup(pluginID, groupID string) (sdkresource.ResourceGroup, error) { + return s.ctrl.GetResourceGroup(pluginID, groupID) +} +func (s *ResourceControllerService) GetResourceTypes(pluginID, connectionID string) map[string]sdkresource.ResourceMeta { + return s.ctrl.GetResourceTypes(pluginID, connectionID) +} +func (s *ResourceControllerService) GetResourceType(pluginID, typeID string) (*sdkresource.ResourceMeta, error) { + return s.ctrl.GetResourceType(pluginID, typeID) +} +func (s *ResourceControllerService) HasResourceType(pluginID, typeID string) bool { + return s.ctrl.HasResourceType(pluginID, typeID) +} +func (s *ResourceControllerService) GetResourceDefinition(pluginID, typeID string) (sdkresource.ResourceDefinition, error) { + return s.ctrl.GetResourceDefinition(pluginID, typeID) +} +func (s *ResourceControllerService) GetResourceCapabilities(pluginID, key string) (*sdkresource.ResourceCapabilities, error) { + return s.ctrl.GetResourceCapabilities(pluginID, key) +} +func (s *ResourceControllerService) GetFilterFields(pluginID, connectionID, key string) ([]sdkresource.FilterField, error) { + return s.ctrl.GetFilterFields(pluginID, connectionID, key) +} +func (s *ResourceControllerService) GetResourceSchema(pluginID, connectionID, key string) (json.RawMessage, error) { + return s.ctrl.GetResourceSchema(pluginID, connectionID, key) +} + +// Actions +func (s *ResourceControllerService) GetActions(pluginID, connectionID, key string) ([]sdkresource.ActionDescriptor, error) { + return s.ctrl.GetActions(pluginID, connectionID, key) +} +func (s *ResourceControllerService) ExecuteAction(pluginID, connectionID, key, actionID string, input sdkresource.ActionInput) (*sdkresource.ActionResult, error) { + return s.ctrl.ExecuteAction(pluginID, connectionID, key, actionID, input) +} +func (s *ResourceControllerService) StreamAction(pluginID, connectionID, key, actionID string, input sdkresource.ActionInput) (string, error) { + return s.ctrl.StreamAction(pluginID, connectionID, key, actionID, input) +} + +// Editor schemas +func (s *ResourceControllerService) GetEditorSchemas(pluginID, connectionID string) ([]sdkresource.EditorSchema, error) { + return s.ctrl.GetEditorSchemas(pluginID, connectionID) +} + +// Relationships +func (s *ResourceControllerService) GetRelationships(pluginID, key string) ([]sdkresource.RelationshipDescriptor, error) { + return s.ctrl.GetRelationships(pluginID, key) +} +func (s *ResourceControllerService) ResolveRelationships(pluginID, connectionID, key, id, namespace string) ([]sdkresource.ResolvedRelationship, error) { + return s.ctrl.ResolveRelationships(pluginID, connectionID, key, id, namespace) +} + +// Health +func (s *ResourceControllerService) GetHealth(pluginID, connectionID, key string, data json.RawMessage) (*sdkresource.ResourceHealth, error) { + return s.ctrl.GetHealth(pluginID, connectionID, key, data) +} +func (s *ResourceControllerService) GetResourceEvents(pluginID, connectionID, key, id, namespace string, limit int32) ([]sdkresource.ResourceEvent, error) { + return s.ctrl.GetResourceEvents(pluginID, connectionID, key, id, namespace, limit) +} + +// ListPlugins +func (s *ResourceControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} + +// HasPlugin +func (s *ResourceControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} + +// --------------------------------------------------------------------------- +// SettingsControllerService — explicit delegation. +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, ServiceStartup, ServiceShutdown +// --------------------------------------------------------------------------- + +type SettingsControllerService struct { + ctrl settings.Controller +} + +func (s *SettingsControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *SettingsControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *SettingsControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} +func (s *SettingsControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} +func (s *SettingsControllerService) Values() map[string]any { + return s.ctrl.Values() +} +func (s *SettingsControllerService) PluginValues(plugin string) map[string]any { + return s.ctrl.PluginValues(plugin) +} +func (s *SettingsControllerService) ListSettings(plugin string) map[string]pkgsettings.Setting { + return s.ctrl.ListSettings(plugin) +} +func (s *SettingsControllerService) GetSetting(plugin, id string) (pkgsettings.Setting, error) { + return s.ctrl.GetSetting(plugin, id) +} +func (s *SettingsControllerService) SetSetting(plugin, id string, value any) error { + return s.ctrl.SetSetting(plugin, id, value) +} +func (s *SettingsControllerService) SetSettings(plugin string, settingsMap map[string]any) error { + return s.ctrl.SetSettings(plugin, settingsMap) +} + +// --------------------------------------------------------------------------- +// ExecControllerService — explicit delegation. +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, ServiceStartup, ServiceShutdown +// --------------------------------------------------------------------------- + +type ExecControllerService struct { + ctrl exec.Controller +} + +func (s *ExecControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *ExecControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *ExecControllerService) CreateSession(plugin, connectionID string, opts execsdk.SessionOptions) (*execsdk.Session, error) { + return s.ctrl.CreateSession(plugin, connectionID, opts) +} +func (s *ExecControllerService) CreateTerminal(opts execsdk.SessionOptions) (*execsdk.Session, error) { + return s.ctrl.CreateTerminal(opts) +} +func (s *ExecControllerService) ListSessions() ([]*execsdk.Session, error) { + return s.ctrl.ListSessions() +} +func (s *ExecControllerService) GetSession(sessionID string) (*execsdk.Session, error) { + return s.ctrl.GetSession(sessionID) +} +func (s *ExecControllerService) AttachSession(sessionID string) (*execsdk.Session, []byte, error) { + return s.ctrl.AttachSession(sessionID) +} +func (s *ExecControllerService) DetachSession(sessionID string) (*execsdk.Session, error) { + return s.ctrl.DetachSession(sessionID) +} +func (s *ExecControllerService) WriteSession(sessionID string, data []byte) error { + return s.ctrl.WriteSession(sessionID, data) +} +func (s *ExecControllerService) CloseSession(sessionID string) error { + return s.ctrl.CloseSession(sessionID) +} +func (s *ExecControllerService) ResizeSession(sessionID string, rows, cols uint16) error { + return s.ctrl.ResizeSession(sessionID, rows, cols) +} +func (s *ExecControllerService) GetHandler(plugin, resource string) *execsdk.Handler { + return s.ctrl.GetHandler(plugin, resource) +} +func (s *ExecControllerService) GetHandlers() map[string]map[string]execsdk.Handler { + return s.ctrl.GetHandlers() +} +func (s *ExecControllerService) GetPluginHandlers(plugin string) map[string]execsdk.Handler { + return s.ctrl.GetPluginHandlers(plugin) +} +func (s *ExecControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} +func (s *ExecControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} + +// --------------------------------------------------------------------------- +// LogsControllerService — explicit delegation. +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, ServiceStartup, ServiceShutdown +// --------------------------------------------------------------------------- + +type LogsControllerService struct { + ctrl pluginlogs.Controller +} + +func (s *LogsControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *LogsControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *LogsControllerService) GetSupportedResources(pluginID string) []logssdk.Handler { + return s.ctrl.GetSupportedResources(pluginID) +} +func (s *LogsControllerService) CreateSession(plugin, connectionID string, opts logssdk.CreateSessionOptions) (*logssdk.LogSession, error) { + return s.ctrl.CreateSession(plugin, connectionID, opts) +} +func (s *LogsControllerService) GetSession(sessionID string) (*logssdk.LogSession, error) { + return s.ctrl.GetSession(sessionID) +} +func (s *LogsControllerService) ListSessions() ([]*logssdk.LogSession, error) { + return s.ctrl.ListSessions() +} +func (s *LogsControllerService) CloseSession(sessionID string) error { + return s.ctrl.CloseSession(sessionID) +} +func (s *LogsControllerService) SendCommand(sessionID string, cmd logssdk.LogStreamCommand) error { + return s.ctrl.SendCommand(sessionID, cmd) +} +func (s *LogsControllerService) UpdateSessionOptions(sessionID string, opts logssdk.LogSessionOptions) (*logssdk.LogSession, error) { + return s.ctrl.UpdateSessionOptions(sessionID, opts) +} +func (s *LogsControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} +func (s *LogsControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} + +// --------------------------------------------------------------------------- +// MetricControllerService — explicit delegation. +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, ServiceStartup, ServiceShutdown +// --------------------------------------------------------------------------- + +type MetricControllerService struct { + ctrl pluginmetric.Controller +} + +func (s *MetricControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *MetricControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *MetricControllerService) GetProviders() []pluginmetric.MetricProviderSummary { + return s.ctrl.GetProviders() +} +func (s *MetricControllerService) GetProvidersForResource(resourceKey string) []pluginmetric.MetricProviderSummary { + return s.ctrl.GetProvidersForResource(resourceKey) +} +func (s *MetricControllerService) Query(pluginID, connectionID string, req metricsdk.QueryRequest) (*metricsdk.QueryResponse, error) { + return s.ctrl.Query(pluginID, connectionID, req) +} +func (s *MetricControllerService) QueryAll(connectionID, resourceKey, resourceID, namespace string, + resourceData map[string]interface{}, metricIDs []string, + shape metricsdk.MetricShape, startTime, endTime time.Time, step time.Duration, +) (map[string]*metricsdk.QueryResponse, error) { + return s.ctrl.QueryAll(connectionID, resourceKey, resourceID, namespace, resourceData, metricIDs, shape, startTime, endTime, step) +} +func (s *MetricControllerService) Subscribe(pluginID, connectionID string, req pluginmetric.SubscribeRequest) (string, error) { + return s.ctrl.Subscribe(pluginID, connectionID, req) +} +func (s *MetricControllerService) Unsubscribe(subscriptionID string) error { + return s.ctrl.Unsubscribe(subscriptionID) +} +func (s *MetricControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} +func (s *MetricControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} + +// --------------------------------------------------------------------------- +// NetworkerControllerService — explicit delegation. +// Excluded: OnPluginInit, OnPluginStart, OnPluginStop, OnPluginShutdown, +// OnPluginDestroy, ServiceStartup, ServiceShutdown +// --------------------------------------------------------------------------- + +type NetworkerControllerService struct { + ctrl networker.Controller +} + +func (s *NetworkerControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *NetworkerControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *NetworkerControllerService) GetSupportedPortForwardTargets(pluginID string) ([]string, error) { + return s.ctrl.GetSupportedPortForwardTargets(pluginID) +} +func (s *NetworkerControllerService) GetPortForwardSession(sessionID string) (*networkersdk.PortForwardSession, error) { + return s.ctrl.GetPortForwardSession(sessionID) +} +func (s *NetworkerControllerService) ListPortForwardSessions(pluginID, connectionID string) ([]*networkersdk.PortForwardSession, error) { + return s.ctrl.ListPortForwardSessions(pluginID, connectionID) +} +func (s *NetworkerControllerService) ListAllPortForwardSessions() ([]*networkersdk.PortForwardSession, error) { + return s.ctrl.ListAllPortForwardSessions() +} +func (s *NetworkerControllerService) FindPortForwardSessions(pluginID, connectionID string, request networkersdk.FindPortForwardSessionRequest) ([]*networkersdk.PortForwardSession, error) { + return s.ctrl.FindPortForwardSessions(pluginID, connectionID, request) +} +func (s *NetworkerControllerService) StartResourcePortForwardingSession(pluginID, connectionID string, opts networkersdk.PortForwardSessionOptions) (*networkersdk.PortForwardSession, error) { + return s.ctrl.StartResourcePortForwardingSession(pluginID, connectionID, opts) +} +func (s *NetworkerControllerService) ClosePortForwardSession(sessionID string) (*networkersdk.PortForwardSession, error) { + return s.ctrl.ClosePortForwardSession(sessionID) +} +func (s *NetworkerControllerService) ListPlugins() ([]string, error) { + return s.ctrl.ListPlugins() +} +func (s *NetworkerControllerService) HasPlugin(pluginID string) bool { + return s.ctrl.HasPlugin(pluginID) +} + +// --------------------------------------------------------------------------- +// DataControllerService — explicit delegation. +// Excluded: ServiceStartup, ServiceShutdown (data.Controller has no plugin +// lifecycle methods since it doesn't embed types.Controller). +// --------------------------------------------------------------------------- + +type DataControllerService struct { + ctrl data.Controller +} + +func (s *DataControllerService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { + if ss, ok := s.ctrl.(interface { + ServiceStartup(context.Context, application.ServiceOptions) error + }); ok { + return ss.ServiceStartup(ctx, options) + } + return nil +} +func (s *DataControllerService) ServiceShutdown() error { + if ss, ok := s.ctrl.(interface{ ServiceShutdown() error }); ok { + return ss.ServiceShutdown() + } + return nil +} +func (s *DataControllerService) Get(pluginID, key string) (any, error) { + return s.ctrl.Get(pluginID, key) +} +func (s *DataControllerService) Set(pluginID, key string, value any) error { + return s.ctrl.Set(pluginID, key, value) +} +func (s *DataControllerService) Delete(pluginID, key string) error { + return s.ctrl.Delete(pluginID, key) +} +func (s *DataControllerService) Keys(pluginID string) ([]string, error) { + return s.ctrl.Keys(pluginID) +} + +// --------------------------------------------------------------------------- +// SettingsProviderService — explicit delegation. +// Excluded: Initialize, RegisterChangeHandler, RegisterSetting, +// RegisterSettings (internal-only methods). +// --------------------------------------------------------------------------- + +type SettingsProviderService struct { + provider pkgsettings.Provider +} + +func (s *SettingsProviderService) LoadSettings() error { + return s.provider.LoadSettings() +} +func (s *SettingsProviderService) SaveSettings() error { + return s.provider.SaveSettings() +} +func (s *SettingsProviderService) ListSettings() pkgsettings.Store { + return s.provider.ListSettings() +} +func (s *SettingsProviderService) Values() map[string]any { + return s.provider.Values() +} +func (s *SettingsProviderService) GetSetting(id string) (pkgsettings.Setting, error) { + return s.provider.GetSetting(id) +} +func (s *SettingsProviderService) GetSettingValue(id string) (any, error) { + return s.provider.GetSettingValue(id) +} +func (s *SettingsProviderService) SetSetting(id string, value any) error { + return s.provider.SetSetting(id, value) +} +func (s *SettingsProviderService) SetSettings(settingsMap map[string]any) error { + return s.provider.SetSettings(settingsMap) +} +func (s *SettingsProviderService) ResetSetting(id string) error { + return s.provider.ResetSetting(id) +} +func (s *SettingsProviderService) GetCategories() []pkgsettings.Category { + return s.provider.GetCategories() +} +func (s *SettingsProviderService) GetCategory(id string) (pkgsettings.Category, error) { + return s.provider.GetCategory(id) +} +func (s *SettingsProviderService) GetCategoryValues(id string) (map[string]interface{}, error) { + return s.provider.GetCategoryValues(id) +} +func (s *SettingsProviderService) GetString(id string) (string, error) { + return s.provider.GetString(id) +} +func (s *SettingsProviderService) GetStringSlice(id string) ([]string, error) { + return s.provider.GetStringSlice(id) +} +func (s *SettingsProviderService) GetInt(id string) (int, error) { + return s.provider.GetInt(id) +} +func (s *SettingsProviderService) GetIntSlice(id string) ([]int, error) { + return s.provider.GetIntSlice(id) +} +func (s *SettingsProviderService) GetFloat(id string) (float64, error) { + return s.provider.GetFloat(id) +} +func (s *SettingsProviderService) GetFloatSlice(id string) ([]float64, error) { + return s.provider.GetFloatSlice(id) +} +func (s *SettingsProviderService) GetBool(id string) (bool, error) { + return s.provider.GetBool(id) +} + +// BootstrapService wraps the startup/shutdown logic that was previously in the +// Wails v2 OnStartup/OnShutdown closures. It implements ServiceStartup and +// ServiceShutdown so the Wails v3 runtime calls it automatically. +type BootstrapService struct { + log logging.Logger + settingsProvider pkgsettings.Provider + telemetrySvc *telemetry.Service + pluginManager plugin.Manager + pluginRegistryClient *registry.Client +} + +func (b *BootstrapService) ServiceStartup(ctx context.Context, _ application.ServiceOptions) error { + // Initialize the settings + if err := b.settingsProvider.Initialize( + ctx, + coresettings.General, + coresettings.Appearance, + coresettings.Terminal, + coresettings.Editor, + coresettings.Developer, + coresettings.Telemetry, + ); err != nil { + b.log.Errorw(ctx, "error while initializing settings system", "error", err) + } + + // Wire telemetry settings hot-toggle: when any setting in the + // "telemetry" category changes, rebuild TelemetryConfig and apply. + telemetryFromSettings := func(vals map[string]any) telemetry.TelemetryConfig { + cfg := b.telemetrySvc.Config() + if v, ok := vals["enabled"].(bool); ok { + cfg.Enabled = v + } + if v, ok := vals["traces"].(bool); ok { + cfg.Traces = v + } + if v, ok := vals["metrics"].(bool); ok { + cfg.Metrics = v + } + if v, ok := vals["logs_ship"].(bool); ok { + cfg.LogsShip = v + } + if v, ok := vals["logs_ship_level"].(string); ok { + cfg.LogsShipLevel = v + } + if v, ok := vals["profiling"].(bool); ok { + cfg.Profiling = v + } + if v, ok := vals["endpoint_otlp"].(string); ok { + cfg.OTLPEndpoint = v + } + if v, ok := vals["endpoint_pyroscope"].(string); ok { + cfg.PyroscopeEndpoint = v + } + if v, ok := vals["auth_header"].(string); ok { + cfg.AuthHeader = v + } + if v, ok := vals["auth_value"].(string); ok { + cfg.AuthValue = v + } + return cfg + } + + b.settingsProvider.RegisterChangeHandler("telemetry", func(vals map[string]any) { + cfg := telemetryFromSettings(vals) + if err := b.telemetrySvc.ApplyConfig(ctx, cfg); err != nil { + b.log.Errorw(ctx, "failed to apply telemetry config change", "error", err) + } else { + b.log.Infow(ctx, "telemetry config updated from settings") + } + }) + + // Apply the persisted telemetry settings immediately so telemetry + // activates on startup (the change handler only fires on changes). + if vals, err := b.settingsProvider.GetCategoryValues("telemetry"); err == nil { + cfg := telemetryFromSettings(vals) + if err := b.telemetrySvc.ApplyConfig(ctx, cfg); err != nil { + b.log.Errorw(ctx, "failed to apply initial telemetry config", "error", err) + } else { + b.log.Infow(ctx, "telemetry initialized from persisted settings", "enabled", cfg.Enabled) + } + } + + // Apply user-configured marketplace URL to the registry client. + if marketplaceURL, err := b.settingsProvider.GetString("developer.marketplace_url"); err == nil && marketplaceURL != "" { + b.pluginRegistryClient.SetBaseURL(marketplaceURL) + safeHost := marketplaceURL + if u, parseErr := url.Parse(marketplaceURL); parseErr == nil { + safeHost = u.Host + } + b.log.Infow(ctx, "using custom marketplace URL", "host", safeHost) + } + + // Controllers now implement ServiceStartup/ServiceShutdown and are + // registered as Wails v3 services, so Wails calls their lifecycle + // methods automatically. + + // Initialize the plugin system + if err := b.pluginManager.Initialize(ctx); err != nil { + b.log.Errorw(ctx, "error while initializing plugin system", "error", err) + } + b.pluginManager.Run(ctx) + + return nil +} + +func (b *BootstrapService) ServiceShutdown() error { + // DevServerManager and controllers have their own ServiceShutdown + // called by Wails v3 automatically. + b.pluginManager.Shutdown() + _ = b.telemetrySvc.Shutdown(context.Background()) + return nil +} + //nolint:funlen // main function is expected to be long func main() { // Bootstrap telemetry (tracing, metrics, log shipping, profiling). @@ -109,7 +918,6 @@ func main() { // Create our plugin system managers uiManager := ui.NewComponentManager(log) - uiClient := ui.NewClient(uiManager) managers := map[string]types.PluginManager{ "ui": uiManager, @@ -119,25 +927,18 @@ func main() { // Setup the plugin systems resourceController := resource.NewController(log, settingsProvider) - resourceClient := resource.NewClient(resourceController) settingsController := settings.NewController(log, settingsProvider) - settingsClient := settings.NewClient(settingsController) execController := exec.NewController(log, settingsProvider, resourceController) - execClient := exec.NewClient(execController) networkerController := networker.NewController(log, settingsProvider, resourceController) - networkerClient := networker.NewClient(networkerController) logsController := pluginlogs.NewController(log, settingsProvider, resourceController) - logsClient := pluginlogs.NewClient(logsController) metricController := pluginmetric.NewController(log, settingsProvider, resourceController) - metricClient := pluginmetric.NewClient(metricController) dataController := data.NewController(log) - dataClient := data.NewClient(dataController) // Initialize per-plugin log manager for capturing plugin process stderr. // Created here so it can be bound to Wails for UI access. @@ -193,198 +994,111 @@ func main() { pluginManager.SetPluginLogManager(pluginLogManager) } - // Create an instance of the app structure - app := NewApp() - startup := func(ctx context.Context) { - // Perform your setup here - app.startup(ctx) - - // Initialize the settings - if err := settingsProvider.Initialize( - ctx, - coresettings.General, - coresettings.Appearance, - coresettings.Terminal, - coresettings.Editor, - coresettings.Developer, - coresettings.Telemetry, - ); err != nil { - log.Errorw(ctx, "error while initializing settings system", "error", err) - } + // Create the AppService + appService := NewAppService() - // Wire telemetry settings hot-toggle: when any setting in the - // "telemetry" category changes, rebuild TelemetryConfig and apply. - telemetryFromSettings := func(vals map[string]any) telemetry.TelemetryConfig { - cfg := telemetrySvc.Config() - if v, ok := vals["enabled"].(bool); ok { - cfg.Enabled = v - } - if v, ok := vals["traces"].(bool); ok { - cfg.Traces = v - } - if v, ok := vals["metrics"].(bool); ok { - cfg.Metrics = v - } - if v, ok := vals["logs_ship"].(bool); ok { - cfg.LogsShip = v - } - if v, ok := vals["logs_ship_level"].(string); ok { - cfg.LogsShipLevel = v - } - if v, ok := vals["profiling"].(bool); ok { - cfg.Profiling = v - } - if v, ok := vals["endpoint_otlp"].(string); ok { - cfg.OTLPEndpoint = v - } - if v, ok := vals["endpoint_pyroscope"].(string); ok { - cfg.PyroscopeEndpoint = v - } - if v, ok := vals["auth_header"].(string); ok { - cfg.AuthHeader = v - } - if v, ok := vals["auth_value"].(string); ok { - cfg.AuthValue = v - } - return cfg - } - - settingsProvider.RegisterChangeHandler("telemetry", func(vals map[string]any) { - cfg := telemetryFromSettings(vals) - if err := telemetrySvc.ApplyConfig(ctx, cfg); err != nil { - log.Errorw(ctx, "failed to apply telemetry config change", "error", err) - } else { - log.Infow(ctx, "telemetry config updated from settings") - } - }) - - // Apply the persisted telemetry settings immediately so telemetry - // activates on startup (the change handler only fires on changes). - if vals, err := settingsProvider.GetCategoryValues("telemetry"); err == nil { - cfg := telemetryFromSettings(vals) - if err := telemetrySvc.ApplyConfig(ctx, cfg); err != nil { - log.Errorw(ctx, "failed to apply initial telemetry config", "error", err) - } else { - log.Infow(ctx, "telemetry initialized from persisted settings", "enabled", cfg.Enabled) - } - } + // Create the bootstrap service that wraps startup/shutdown logic + bootstrapService := &BootstrapService{ + log: log, + settingsProvider: settingsProvider, + telemetrySvc: telemetrySvc, + pluginManager: pluginManager, + pluginRegistryClient: pluginRegistryClient, + } - // Apply user-configured marketplace URL to the registry client. - if marketplaceURL, err := settingsProvider.GetString("developer.marketplace_url"); err == nil && marketplaceURL != "" { - pluginRegistryClient.SetBaseURL(marketplaceURL) - safeHost := marketplaceURL - if u, parseErr := url.Parse(marketplaceURL); parseErr == nil { - safeHost = u.Host - } - log.Infow(ctx, "using custom marketplace URL", "host", safeHost) - } + // Set up plugin asset handler middleware + pluginAssetHandler := NewPluginAssetHandler(log) - resourceController.Run(ctx) - execController.Run(ctx) - logsController.Run(ctx) - metricController.Run(ctx) - networkerController.Run(ctx) + // Wrap the plugin manager interface in a concrete struct for v3 service + // registration (NewService requires a concrete pointer type). + pluginManagerSvc := &PluginManagerService{mgr: pluginManager} - // Initialize dev server manager first so it has a context before - // pluginManager.Initialize() auto-starts dev servers. - devServerManager.Initialize(ctx) + // Build the service list. All concrete pointer types use NewService directly. + // BootstrapService is registered first so startup logic runs before other + // services that might depend on initialized controllers. It has no + // frontend-facing methods — only ServiceStartup/ServiceShutdown. + // Service registration order matters: Wails calls ServiceStartup in order. + // Controllers must be initialized (receive ctx + app) BEFORE the bootstrap + // service, because bootstrap calls pluginManager.Initialize() which triggers + // OnPluginStart on all controllers — they need ctx for gRPC streams. + services := []application.Service{ + // 1. Controllers — need ctx before plugin loading + application.NewService(&ResourceControllerService{ctrl: resourceController}), + application.NewService(&SettingsControllerService{ctrl: settingsController}), + application.NewService(&ExecControllerService{ctrl: execController}), + application.NewService(&NetworkerControllerService{ctrl: networkerController}), + application.NewService(&LogsControllerService{ctrl: logsController}), + application.NewService(&MetricControllerService{ctrl: metricController}), + application.NewService(&DataControllerService{ctrl: dataController}), + application.NewService(ui.NewServiceWrapper(uiManager)), + application.NewService(utilsClient), + application.NewService(&DevServerService{mgr: devServerManager}), + // 2. Bootstrap — initializes settings, telemetry, loads plugins + application.NewService(bootstrapService), + // 3. Frontend-facing services (no startup order dependency) + application.NewService(appService), + application.NewService(diagnosticsClient), + application.NewService(telemetry.NewTelemetryBinding(telemetrySvc)), + application.NewService(&SettingsProviderService{provider: settingsProvider}), + application.NewService(pluginManagerSvc), + } - // Initialize the plugin system - if err := pluginManager.Initialize(ctx); err != nil { - log.Errorw(ctx, "error while initializing plugin system", "error", err) - } - pluginManager.Run(ctx) - runtime.MenuSetApplicationMenu(ctx, menus.GetMenus(ctx)) + if pluginLogManager != nil { + services = append(services, application.NewService(&PluginLogService{mgr: pluginLogManager})) } - // Create application with options - err := wails.Run(&options.App{ + // Create the Wails v3 application + app := application.New(application.Options{ + Name: "Omniview", + Description: fmt.Sprintf("Omniview %s", version.Version), + Icon: icon, + Services: services, + Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), + Middleware: pluginAssetHandler.Middleware, + }, + // Server mode options — used when built with -tags server for + // headless/CI testing (e.g. Playwright E2E). + Server: application.ServerOptions{ + Host: "localhost", + Port: 34115, + }, + Mac: application.MacOptions{ + ApplicationShouldTerminateAfterLastWindowClosed: true, + }, + Linux: application.LinuxOptions{ + ProgramName: "Omniview", + }, + }) + + // Create the main window + mainWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{ + Name: "main", Title: "Omniview", Width: DefaultWebviewWidth, Height: DefaultWebviewHeight, MinWidth: MinWebviewWidth, MinHeight: MinWebviewHeight, - // MaxWidth: 1280, - // MaxHeight: 800, - DisableResize: false, - Fullscreen: false, - Frameless: false, - StartHidden: false, - HideWindowOnClose: false, //nolint:gomnd // #0D1117 dark theme background - BackgroundColour: &options.RGBA{R: 13, G: 17, B: 23, A: 255}, - AssetServer: &assetserver.Options{ - Assets: assets, - Handler: NewFileLoader(log), - }, - LogLevel: logger.DEBUG, - OnStartup: startup, - OnDomReady: app.domReady, - OnBeforeClose: app.beforeClose, - OnShutdown: func(ctx context.Context) { - devServerManager.Shutdown() - pluginManager.Shutdown() - _ = telemetrySvc.Shutdown(ctx) - }, - WindowStartState: options.Normal, - Bind: []any{ - app, - diagnosticsClient, - telemetry.NewTelemetryBinding(telemetrySvc), - - // core engines/providers - settingsProvider, - - // plugin system - pluginManager, - pluginLogManager, - devServerManager, - resourceClient, - settingsClient, - execClient, - networkerClient, - logsClient, - metricClient, - dataClient, - uiClient, - utilsClient, - }, - EnumBind: []any{ - pkgsettings.AllSettingTypes, - sdktypes.AllConnectionStatusCodes, - sdkresource.AllWatchStates, - sdkresource.AllSyncPolicies, - }, - // Windows platform specific options - Windows: &windows.Options{ - WebviewIsTransparent: false, - WindowIsTranslucent: false, - DisableWindowIcon: false, - // DisableFramelessWindowDecorations: false, - WebviewUserDataPath: "", - ZoomFactor: 1.0, - }, - // Mac platform specific options - Mac: &mac.Options{ - TitleBar: mac.TitleBarHiddenInset(), - Appearance: mac.NSAppearanceNameDarkAqua, - WebviewIsTransparent: true, - WindowIsTranslucent: true, - About: &mac.AboutInfo{ - Title: fmt.Sprintf("Omniview %s", version.Version), - //nolint:lll // about info is naturally long - Message: "The modern, lightweight, pluggable cross-platform IDE for DevOps engineers.\n\nCopyright © 2025", - Icon: icon, - }, - }, - Linux: &linux.Options{ - ProgramName: "Omniview", - Icon: icon, - WebviewGpuPolicy: linux.WebviewGpuPolicyOnDemand, - WindowIsTranslucent: true, + BackgroundColour: application.NewRGBA(13, 17, 23, 255), + UseApplicationMenu: true, + Mac: application.MacWindow{ + TitleBar: application.MacTitleBarHiddenInset, + Appearance: application.NSAppearanceNameDarkAqua, + Backdrop: application.MacBackdropTranslucent, }, }) - if err != nil { + + // Set up menus, keybindings, and context menus + menus.SetupAppMenu(app, mainWindow) + menus.SetupKeyBindings(app) + menus.SetupContextMenus(app) + + // Set up window manager (registers hide-on-close hook, etc.) + _ = window.NewManager(app, mainWindow) + + // Run the application + if err := app.Run(); err != nil { log.Fatalw(context.Background(), "wails app exited with error", "error", err) } } diff --git a/package.json b/package.json index d3b69fbe..641fc57e 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "pnpm run bundle:yaml-worker && tsc && vite build", + "build:dev": "vite build --minify false --mode development", "bundle:yaml-worker": "esbuild node_modules/monaco-yaml/yaml.worker.js --bundle --format=esm --outfile=ui/providers/monaco/yaml.worker.bundle.js --platform=browser", "postinstall": "pnpm run bundle:yaml-worker", "lint": "ESLINT_USE_FLAT_CONFIG=false eslint ui --ext ts,tsx --report-unused-disable-directives", @@ -68,21 +69,23 @@ "yaml": "^2.7.1" }, "devDependencies": { + "@rolldown/plugin-babel": "^0.2.2", "@stylistic/eslint-plugin": "^5.10.0", "@tanstack/react-query-devtools": "^5.76.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^14.2.1", "@types/jsonpath": "^0.2.4", "@types/lodash.get": "^4.4.9", - "@types/node": "^20.11.30", + "@types/node": "^25.5.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@types/systemjs": "^6.15.3", "@types/tinycolor2": "^1.4.6", "@typescript-eslint/eslint-plugin": "^8.31.0", "@typescript-eslint/parser": "^8.31.0", - "@vitejs/plugin-react": "^4.3.4", + "@vitejs/plugin-react": "^6.0.1", "@vitest/ui": "^4.0.18", + "@wailsio/runtime": "3.0.0-alpha.79", "@welldone-software/why-did-you-render": "^8.0.1", "autoprefixer": "^10.4.18", "babel-plugin-react-compiler": "^1.0.0", @@ -96,7 +99,7 @@ "identity-obj-proxy": "^3.0.0", "ts-node": "^10.9.2", "typescript": "^5.8.3", - "vite": "~6.2.6", + "vite": "~8.0.1", "vitest": "^4.0.18" }, "pnpm": { diff --git a/packages/omniviewdev-providers/index.ts b/packages/omniviewdev-providers/index.ts index 5122ed7d..aa89d4eb 100644 --- a/packages/omniviewdev-providers/index.ts +++ b/packages/omniviewdev-providers/index.ts @@ -12,7 +12,7 @@ export * as metric from './internal/metric/Client'; export * as networker from './internal/networker/Client'; export * as pluginManager from './internal/plugin/pluginManager'; export * as resource from './internal/resource/Client'; -export * as runtime from './internal/runtime/runtime'; +export { Application, Browser, Clipboard, Events, Screens, System, Window, WML } from '@wailsio/runtime'; export * as settings from './internal/settings/Client'; export * as settingsProvider from './internal/settings/provider'; export * as ui from './internal/ui/Client'; diff --git a/packages/omniviewdev-providers/internal/runtime/runtime.d.ts b/packages/omniviewdev-providers/internal/runtime/runtime.d.ts deleted file mode 100644 index 4445dac2..00000000 --- a/packages/omniviewdev-providers/internal/runtime/runtime.d.ts +++ /dev/null @@ -1,249 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width : number - height : number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) -// Returns the state of the window, i.e. whether the window is in full screen mode or not. -export function WindowIsFullscreen(): Promise; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) -// Returns the state of the window, i.e. whether the window is maximised or not. -export function WindowIsMaximised(): Promise; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) -// Returns the state of the window, i.e. whether the window is minimised or not. -export function WindowIsMinimised(): Promise; - -// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) -// Returns the state of the window, i.e. whether the window is normal or not. -export function WindowIsNormal(): Promise; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; - -// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) -// Returns the current text stored on clipboard -export function ClipboardGetText(): Promise; - -// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) -// Sets a text on the clipboard -export function ClipboardSetText(text: string): Promise; - -// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) -// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. -export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void - -// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) -// OnFileDropOff removes the drag and drop listeners and handlers. -export function OnFileDropOff() :void - -// Check if the file path resolver is available -export function CanResolveFilePaths(): boolean; - -// Resolves file paths for an array of files -export function ResolveFilePaths(files: File[]): void \ No newline at end of file diff --git a/packages/omniviewdev-providers/internal/runtime/runtime.js b/packages/omniviewdev-providers/internal/runtime/runtime.js deleted file mode 100644 index 7cb89d75..00000000 --- a/packages/omniviewdev-providers/internal/runtime/runtime.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName, ...additionalEventNames) { - return window.runtime.EventsOff(eventName, ...additionalEventNames); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowIsFullscreen() { - return window.runtime.WindowIsFullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowIsMaximised() { - return window.runtime.WindowIsMaximised(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function WindowIsMinimised() { - return window.runtime.WindowIsMinimised(); -} - -export function WindowIsNormal() { - return window.runtime.WindowIsNormal(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} - -export function ClipboardGetText() { - return window.runtime.ClipboardGetText(); -} - -export function ClipboardSetText(text) { - return window.runtime.ClipboardSetText(text); -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - return window.runtime.OnFileDrop(callback, useDropTarget); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - return window.runtime.OnFileDropOff(); -} - -export function CanResolveFilePaths() { - return window.runtime.CanResolveFilePaths(); -} - -export function ResolveFilePaths(files) { - return window.runtime.ResolveFilePaths(files); -} \ No newline at end of file diff --git a/packages/omniviewdev-providers/lib/portforward/hooks.tsx b/packages/omniviewdev-providers/lib/portforward/hooks.tsx index a1498379..bcf47929 100644 --- a/packages/omniviewdev-providers/lib/portforward/hooks.tsx +++ b/packages/omniviewdev-providers/lib/portforward/hooks.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { networker } from '../../internal/models'; -import { BrowserOpenURL } from '../../internal/runtime/runtime'; +import { Browser } from '@wailsio/runtime'; import { ClosePortForwardSession, FindPortForwardSessions, @@ -104,7 +104,7 @@ export function useResourcePortForwarder({ pluginID, connectionID, resourceID }: const session = await StartResourcePortForwardingSession(pluginID, connectionID, sessionOpts); setSessions([...sessions, session]); if (opts.openInBrowser) { - BrowserOpenURL(`http://localhost:${session.remote_port}`); + Browser.OpenURL(`http://localhost:${session.remote_port}`); } return session; diff --git a/packages/omniviewdev-providers/package.json b/packages/omniviewdev-providers/package.json index cdcc60dd..d87ca209 100644 --- a/packages/omniviewdev-providers/package.json +++ b/packages/omniviewdev-providers/package.json @@ -30,12 +30,15 @@ "node": ">=20" }, "devDependencies": { - "@types/node": "^20.12.7", + "@types/node": "^25.5.0", "@types/react": "^19.0.0", "@vitejs/plugin-react": "^4.2.1", "react": "^19.0.0", "tsup": "^8.0.2", "typescript": "^5.4.5", "vite": "^5.2.10" + }, + "dependencies": { + "@wailsio/runtime": "3.0.0-alpha.79" } } diff --git a/packages/omniviewdev-runtime/package.json b/packages/omniviewdev-runtime/package.json index 1f1a89bb..87883904 100644 --- a/packages/omniviewdev-runtime/package.json +++ b/packages/omniviewdev-runtime/package.json @@ -53,7 +53,7 @@ ], "devDependencies": { "@tanstack/react-query": "^5.76.1", - "@types/node": "^20.12.7", + "@types/node": "^25.5.0", "@types/react": "^19.0.0", "@vitejs/plugin-react": "^4.2.1", "notistack": "^3.0.1", @@ -66,6 +66,7 @@ "vite-plugin-dts": "^4.5.3" }, "dependencies": { + "@wailsio/runtime": "3.0.0-alpha.79", "lodash.get": "^4.4.2", "ts-invariant": "^0.10.3" } diff --git a/packages/omniviewdev-runtime/src/api.ts b/packages/omniviewdev-runtime/src/api.ts index d1b473f7..92b71282 100644 --- a/packages/omniviewdev-runtime/src/api.ts +++ b/packages/omniviewdev-runtime/src/api.ts @@ -1,16 +1,18 @@ -export * as ExecClient from './wailsjs/go/exec/Client'; -export * as NetworkerClient from './wailsjs/go/networker/Client'; -export * as PluginManager from './wailsjs/go/plugin/pluginManager'; -export * as ResourceClient from './wailsjs/go/resource/Client'; -export * as SettingsClient from './wailsjs/go/settings/Client'; -export * as SettingsProvider from './wailsjs/go/settings/provider'; -export * as UtilsClient from './wailsjs/go/utils/Client'; -export * as UIClient from './wailsjs/go/ui/Client'; -export * as DiagnosticsClient from './wailsjs/go/diagnostics/DiagnosticsClient'; -export * as LogsClient from './wailsjs/go/logs/Client'; -export * as MetricClient from './wailsjs/go/metric/Client'; +// v3 generated bindings — paths match `wails3 generate bindings -d packages/omniviewdev-runtime/src/bindings` +export * as ExecClient from './bindings/github.com/omniviewdev/omniview/execcontrollerservice'; +export * as NetworkerClient from './bindings/github.com/omniviewdev/omniview/networkercontrollerservice'; +export * as PluginManager from './bindings/github.com/omniviewdev/omniview/pluginmanagerservice'; +export * as ResourceClient from './bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +export * as SettingsClient from './bindings/github.com/omniviewdev/omniview/settingscontrollerservice'; +export * as SettingsProvider from './bindings/github.com/omniviewdev/omniview/settingsproviderservice'; +export * as UtilsClient from './bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/client'; +export * as UIClient from './bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/servicewrapper'; +export * as DiagnosticsClient from './bindings/github.com/omniviewdev/omniview/backend/diagnostics/diagnosticsclient'; +export * as LogsClient from './bindings/github.com/omniviewdev/omniview/logscontrollerservice'; +export * as MetricClient from './bindings/github.com/omniviewdev/omniview/metriccontrollerservice'; +export * as DataClient from './bindings/github.com/omniviewdev/omniview/datacontrollerservice'; -export * as DevServerManager from './wailsjs/go/devserver/DevServerManager'; -export * as PluginLogManager from './wailsjs/go/pluginlog/Manager'; +export * as DevServerManager from './bindings/github.com/omniviewdev/omniview/devserverservice'; +export * as PluginLogManager from './bindings/github.com/omniviewdev/omniview/pluginlogservice'; -export * from './wailsjs/go/main/App'; +export * from './bindings/github.com/omniviewdev/omniview/appservice'; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.d.ts b/packages/omniviewdev-runtime/src/bindings/encoding/json/index.ts old mode 100755 new mode 100644 similarity index 63% rename from packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.d.ts rename to packages/omniviewdev-runtime/src/bindings/encoding/json/index.ts index 1388abc6..05334178 --- a/packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.d.ts +++ b/packages/omniviewdev-runtime/src/bindings/encoding/json/index.ts @@ -1,4 +1,6 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT -export function IngestFrontendSignals(arg1:string):Promise; +export type { + RawMessage +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/encoding/json/models.ts b/packages/omniviewdev-runtime/src/bindings/encoding/json/models.ts new file mode 100644 index 00000000..1d01d3d9 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/encoding/json/models.ts @@ -0,0 +1,13 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * RawMessage is a raw encoded JSON value. + * It implements [Marshaler] and [Unmarshaler] and can + * be used to delay JSON decoding or precompute a JSON encoding. + */ +export type RawMessage = any; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/appservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/appservice.ts new file mode 100644 index 00000000..ad685376 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/appservice.ts @@ -0,0 +1,49 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * AppService is the main application service for Wails v3. + * It is registered as a Wails service and exposes methods to the frontend. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * GetOperatingSystem returns the operating system type this application is running on. + */ +export function GetOperatingSystem(): $CancellablePromise { + return $Call.ByID(1706570792); +} + +/** + * OpenFileSelectionDialog opens a native file selection dialog using the v3 Dialog API. + */ +export function OpenFileSelectionDialog(opts: $models.FileDialogOptions): $CancellablePromise { + return $Call.ByID(2957909098, opts).then(($result: any) => { + return $$createType0($result); + }); +} + +/** + * SaveFileDialog opens a native save file dialog using the v3 Dialog API. + */ +export function SaveFileDialog(opts: $models.FileDialogOptions): $CancellablePromise { + return $Call.ByID(473489213, opts); +} + +/** + * WriteFileContent writes string content to the given file path. + */ +export function WriteFileContent(path: string, content: string): $CancellablePromise { + return $Call.ByID(3778694836, path, content); +} + +// Private type creation functions +const $$createType0 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/diagnosticsclient.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/diagnosticsclient.ts new file mode 100644 index 00000000..3d71963c --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/diagnosticsclient.ts @@ -0,0 +1,68 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * DiagnosticsClient provides a client to the UI to be able to record ui side logs, + * view ui and backend logs, as well as other diagnostic imformation. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +/** + * Debug records a debug level log to the log sink + */ +export function Debug(msg: string, fields: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(2691208406, msg, fields); +} + +/** + * Error records an error level log to the log sink + */ +export function Error(msg: string, fields: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(3932965591, msg, fields); +} + +/** + * Info records an info level log to the log sink + */ +export function Info(msg: string, fields: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(1686862755, msg, fields); +} + +/** + * Log records an arbitrary log with a set level to the log sink + */ +export function Log(level: string, msg: string, fields: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(3705442919, level, msg, fields); +} + +/** + * ReadLog returns the string contents of the log requested + */ +export function ReadLog(logType: string): $CancellablePromise { + return $Call.ByID(3024854267, logType); +} + +/** + * StartTail starts tailing the log to the event stream + */ +export function StartTail(logType: string): $CancellablePromise { + return $Call.ByID(158417611, logType); +} + +/** + * StopTail stops tailing the log to the event stream + */ +export function StopTail(logType: string): $CancellablePromise { + return $Call.ByID(3413815733, logType); +} + +/** + * Warn records a warn level log to the log sink + */ +export function Warn(msg: string, fields: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(2047870999, msg, fields); +} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.d.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/index.ts old mode 100755 new mode 100644 similarity index 50% rename from packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.d.ts rename to packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/index.ts index daafdb53..ab6096de --- a/packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.d.ts +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/diagnostics/index.ts @@ -1,5 +1,7 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT -import {utils} from '../models'; -export function DetectLanguage(arg1:utils.GetLanguageInput):Promise; +import * as DiagnosticsClient from "./diagnosticsclient.js"; +export { + DiagnosticsClient +}; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/index.ts new file mode 100644 index 00000000..5448231c --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/index.ts @@ -0,0 +1,12 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + BuildError, + DevInfoFile, + DevProcessStatus, + DevServerErrorPayload, + DevServerMode, + DevServerState, + LogEntry +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/models.ts new file mode 100644 index 00000000..a607ee75 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/models.ts @@ -0,0 +1,280 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../../time/models.js"; + +/** + * BuildError is a structured build error parsed from Go compiler output. + */ +export class BuildError { + "file": string; + "line": number; + "column": number; + "message": string; + + /** Creates a new BuildError instance. */ + constructor($$source: Partial = {}) { + if (!("file" in $$source)) { + this["file"] = ""; + } + if (!("line" in $$source)) { + this["line"] = 0; + } + if (!("column" in $$source)) { + this["column"] = 0; + } + if (!("message" in $$source)) { + this["message"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new BuildError instance from a string or object. + */ + static createFrom($$source: any = {}): BuildError { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new BuildError($$parsedSource as Partial); + } +} + +/** + * DevInfoFile is the JSON structure of the .devinfo file written by externally-run plugins. + */ +export class DevInfoFile { + "pid": number; + "protocol": string; + "protocolVersion": number; + "addr": string; + "vitePort"?: number; + "pluginId"?: string; + "version"?: string; + "startedAt"?: string; + + /** Creates a new DevInfoFile instance. */ + constructor($$source: Partial = {}) { + if (!("pid" in $$source)) { + this["pid"] = 0; + } + if (!("protocol" in $$source)) { + this["protocol"] = ""; + } + if (!("protocolVersion" in $$source)) { + this["protocolVersion"] = 0; + } + if (!("addr" in $$source)) { + this["addr"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DevInfoFile instance from a string or object. + */ + static createFrom($$source: any = {}): DevInfoFile { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DevInfoFile($$parsedSource as Partial); + } +} + +/** + * DevProcessStatus describes the current status of either the Vite process or the Go watcher. + */ +export enum DevProcessStatus { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + DevProcessStatusIdle = "idle", + DevProcessStatusStarting = "starting", + DevProcessStatusBuilding = "building", + DevProcessStatusRunning = "running", + DevProcessStatusReady = "ready", + DevProcessStatusError = "error", + DevProcessStatusStopped = "stopped", +}; + +/** + * DevServerErrorPayload wraps a plugin ID and its build errors into a single + * event payload so it can be registered with RegisterEvent[T]. + */ +export class DevServerErrorPayload { + "pluginID": string; + "errors": BuildError[]; + + /** Creates a new DevServerErrorPayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("errors" in $$source)) { + this["errors"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DevServerErrorPayload instance from a string or object. + */ + static createFrom($$source: any = {}): DevServerErrorPayload { + const $$createField1_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("errors" in $$parsedSource) { + $$parsedSource["errors"] = $$createField1_0($$parsedSource["errors"]); + } + return new DevServerErrorPayload($$parsedSource as Partial); + } +} + +/** + * DevServerMode describes how the dev server for a plugin is managed. + */ +export enum DevServerMode { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * DevServerModeIdle means no dev server is running for this plugin. + */ + DevServerModeIdle = "idle", + + /** + * DevServerModeManaged means the IDE spawned and manages the Vite + Go watcher processes. + */ + DevServerModeManaged = "managed", + + /** + * DevServerModeExternal means the developer runs processes externally; + * the IDE connects via .devinfo file. + */ + DevServerModeExternal = "external", +}; + +/** + * DevServerState is the JSON-serializable state of a single plugin's dev server. + * This is sent to the frontend via Wails events and returned from query methods. + */ +export class DevServerState { + "pluginID": string; + "mode": DevServerMode; + "devPath": string; + "vitePort": number; + "viteURL": string; + "viteStatus": DevProcessStatus; + "goStatus": DevProcessStatus; + "lastBuildDuration": time$0.Duration; + "lastBuildTime": string; + "lastError": string; + "grpcConnected": boolean; + + /** Creates a new DevServerState instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("mode" in $$source)) { + this["mode"] = DevServerMode.$zero; + } + if (!("devPath" in $$source)) { + this["devPath"] = ""; + } + if (!("vitePort" in $$source)) { + this["vitePort"] = 0; + } + if (!("viteURL" in $$source)) { + this["viteURL"] = ""; + } + if (!("viteStatus" in $$source)) { + this["viteStatus"] = DevProcessStatus.$zero; + } + if (!("goStatus" in $$source)) { + this["goStatus"] = DevProcessStatus.$zero; + } + if (!("lastBuildDuration" in $$source)) { + this["lastBuildDuration"] = time$0.Duration.$zero; + } + if (!("lastBuildTime" in $$source)) { + this["lastBuildTime"] = ""; + } + if (!("lastError" in $$source)) { + this["lastError"] = ""; + } + if (!("grpcConnected" in $$source)) { + this["grpcConnected"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DevServerState instance from a string or object. + */ + static createFrom($$source: any = {}): DevServerState { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DevServerState($$parsedSource as Partial); + } +} + +/** + * LogEntry is a single log line from either the Vite process or the Go build. + */ +export class LogEntry { + "timestamp": string; + + /** + * "vite" | "go-build" | "go-watch" | "manager" + */ + "source": string; + + /** + * "info" | "warn" | "error" | "debug" + */ + "level": string; + "message": string; + "pluginID": string; + + /** Creates a new LogEntry instance. */ + constructor($$source: Partial = {}) { + if (!("timestamp" in $$source)) { + this["timestamp"] = ""; + } + if (!("source" in $$source)) { + this["source"] = ""; + } + if (!("level" in $$source)) { + this["level"] = ""; + } + if (!("message" in $$source)) { + this["message"] = ""; + } + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogEntry instance from a string or object. + */ + static createFrom($$source: any = {}): LogEntry { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LogEntry($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = BuildError.createFrom; +const $$createType1 = $Create.Array($$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/index.ts new file mode 100644 index 00000000..09ba5e15 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/index.ts @@ -0,0 +1,10 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + DeprecatedProtocolPayload, + LoadPluginOptions, + StateChangePayload, + UpdateErrorPayload, + UpdatePayload +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/index.ts new file mode 100644 index 00000000..12098948 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + PluginPhase +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/models.ts new file mode 100644 index 00000000..23244799 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/lifecycle/models.ts @@ -0,0 +1,39 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * PluginPhase represents the current lifecycle state of a plugin. + */ +export enum PluginPhase { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + PhaseUninstalled = "Uninstalled", + PhaseInstalling = "Installing", + PhaseInstalled = "Installed", + + /** + * dev only: initial go build + */ + PhaseBuilding = "Building", + + /** + * dev only: build error + */ + PhaseBuildFailed = "BuildFailed", + PhaseValidating = "Validating", + PhaseStarting = "Starting", + PhaseRunning = "Running", + PhaseDegraded = "Degraded", + PhaseRecovering = "Recovering", + PhaseStopping = "Stopping", + PhaseStopped = "Stopped", + PhaseFailed = "Failed", + PhaseUninstalling = "Uninstalling", +}; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/index.ts new file mode 100644 index 00000000..77984853 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/index.ts @@ -0,0 +1,7 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + MetricProviderSummary, + SubscribeRequest +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/models.ts new file mode 100644 index 00000000..d5f16b9c --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/models.ts @@ -0,0 +1,120 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as metric$0 from "../../../../../plugin-sdk/pkg/v1/metric/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../../time/models.js"; + +/** + * MetricProviderSummary is a lightweight summary of a metric provider, + * exposed to the frontend. + */ +export class MetricProviderSummary { + "plugin_id": string; + "provider_id": string; + "name": string; + "icon": string; + "description": string; + "handlers": metric$0.Handler[]; + + /** Creates a new MetricProviderSummary instance. */ + constructor($$source: Partial = {}) { + if (!("plugin_id" in $$source)) { + this["plugin_id"] = ""; + } + if (!("provider_id" in $$source)) { + this["provider_id"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("handlers" in $$source)) { + this["handlers"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new MetricProviderSummary instance from a string or object. + */ + static createFrom($$source: any = {}): MetricProviderSummary { + const $$createField5_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("handlers" in $$parsedSource) { + $$parsedSource["handlers"] = $$createField5_0($$parsedSource["handlers"]); + } + return new MetricProviderSummary($$parsedSource as Partial); + } +} + +/** + * SubscribeRequest contains parameters for subscribing to a metric stream. + */ +export class SubscribeRequest { + "resource_key": string; + "resource_id": string; + "resource_namespace": string; + "resource_data": { [_ in string]?: any }; + "metric_ids": string[]; + "interval": time$0.Duration; + + /** Creates a new SubscribeRequest instance. */ + constructor($$source: Partial = {}) { + if (!("resource_key" in $$source)) { + this["resource_key"] = ""; + } + if (!("resource_id" in $$source)) { + this["resource_id"] = ""; + } + if (!("resource_namespace" in $$source)) { + this["resource_namespace"] = ""; + } + if (!("resource_data" in $$source)) { + this["resource_data"] = {}; + } + if (!("metric_ids" in $$source)) { + this["metric_ids"] = []; + } + if (!("interval" in $$source)) { + this["interval"] = time$0.Duration.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SubscribeRequest instance from a string or object. + */ + static createFrom($$source: any = {}): SubscribeRequest { + const $$createField3_0 = $$createType2; + const $$createField4_0 = $$createType3; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resource_data" in $$parsedSource) { + $$parsedSource["resource_data"] = $$createField3_0($$parsedSource["resource_data"]); + } + if ("metric_ids" in $$parsedSource) { + $$parsedSource["metric_ids"] = $$createField4_0($$parsedSource["metric_ids"]); + } + return new SubscribeRequest($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = metric$0.Handler.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Map($Create.Any, $Create.Any); +const $$createType3 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/models.ts new file mode 100644 index 00000000..e09baf18 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/models.ts @@ -0,0 +1,184 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as lifecycle$0 from "./lifecycle/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as types$0 from "./types/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * DeprecatedProtocolPayload is sent with EventDeprecatedProtocol. + */ +export class DeprecatedProtocolPayload { + "pluginID": string; + "version": number; + "currentVersion": number; + + /** Creates a new DeprecatedProtocolPayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("version" in $$source)) { + this["version"] = 0; + } + if (!("currentVersion" in $$source)) { + this["currentVersion"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DeprecatedProtocolPayload instance from a string or object. + */ + static createFrom($$source: any = {}): DeprecatedProtocolPayload { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DeprecatedProtocolPayload($$parsedSource as Partial); + } +} + +/** + * LoadPluginOptions configures how a plugin is loaded. + */ +export class LoadPluginOptions { + "DevMode": boolean; + "DevModePath": string; + "ExistingState": types$0.PluginStateRecord | null; + + /** Creates a new LoadPluginOptions instance. */ + constructor($$source: Partial = {}) { + if (!("DevMode" in $$source)) { + this["DevMode"] = false; + } + if (!("DevModePath" in $$source)) { + this["DevModePath"] = ""; + } + if (!("ExistingState" in $$source)) { + this["ExistingState"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LoadPluginOptions instance from a string or object. + */ + static createFrom($$source: any = {}): LoadPluginOptions { + const $$createField2_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("ExistingState" in $$parsedSource) { + $$parsedSource["ExistingState"] = $$createField2_0($$parsedSource["ExistingState"]); + } + return new LoadPluginOptions($$parsedSource as Partial); + } +} + +/** + * StateChangePayload is sent with EventStateChange. + */ +export class StateChangePayload { + "pluginID": string; + "from": lifecycle$0.PluginPhase; + "to": lifecycle$0.PluginPhase; + "reason": string; + "timestamp": time$0.Time; + + /** Creates a new StateChangePayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("from" in $$source)) { + this["from"] = lifecycle$0.PluginPhase.$zero; + } + if (!("to" in $$source)) { + this["to"] = lifecycle$0.PluginPhase.$zero; + } + if (!("reason" in $$source)) { + this["reason"] = ""; + } + if (!("timestamp" in $$source)) { + this["timestamp"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new StateChangePayload instance from a string or object. + */ + static createFrom($$source: any = {}): StateChangePayload { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new StateChangePayload($$parsedSource as Partial); + } +} + +/** + * UpdateErrorPayload is sent with EventUpdateError. + */ +export class UpdateErrorPayload { + "pluginID": string; + "error": string; + + /** Creates a new UpdateErrorPayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("error" in $$source)) { + this["error"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateErrorPayload instance from a string or object. + */ + static createFrom($$source: any = {}): UpdateErrorPayload { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateErrorPayload($$parsedSource as Partial); + } +} + +/** + * UpdatePayload is sent with EventUpdateStarted and EventUpdateComplete. + */ +export class UpdatePayload { + "pluginID": string; + "version": string; + + /** Creates a new UpdatePayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("version" in $$source)) { + this["version"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdatePayload instance from a string or object. + */ + static createFrom($$source: any = {}): UpdatePayload { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdatePayload($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = types$0.PluginStateRecord.createFrom; +const $$createType1 = $Create.Nullable($$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/index.ts new file mode 100644 index 00000000..2ede70b9 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + LogEntry +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/models.ts new file mode 100644 index 00000000..fa14ae04 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/models.ts @@ -0,0 +1,56 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * LogEntry represents a single log line from a plugin process. + * Field names and JSON tags intentionally match devserver.LogEntry + * for frontend consistency. + */ +export class LogEntry { + "timestamp": string; + "pluginID": string; + + /** + * "plugin" (from hclog) — extensible + */ + "source": string; + + /** + * "trace" | "debug" | "info" | "warn" | "error" + */ + "level": string; + "message": string; + + /** Creates a new LogEntry instance. */ + constructor($$source: Partial = {}) { + if (!("timestamp" in $$source)) { + this["timestamp"] = ""; + } + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("source" in $$source)) { + this["source"] = ""; + } + if (!("level" in $$source)) { + this["level"] = ""; + } + if (!("message" in $$source)) { + this["message"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogEntry instance from a string or object. + */ + static createFrom($$source: any = {}): LogEntry { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new LogEntry($$parsedSource as Partial); + } +} diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/index.ts new file mode 100644 index 00000000..e3508778 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/index.ts @@ -0,0 +1,10 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + AvailablePlugin, + DailyStat, + DownloadStats, + Review, + VersionInfo +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/models.ts new file mode 100644 index 00000000..4466478d --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/registry/models.ts @@ -0,0 +1,276 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * AvailablePlugin represents a plugin from the marketplace, enriched with + * local install status for the desktop app frontend. + */ +export class AvailablePlugin { + "id": string; + "name": string; + "description": string; + "icon_url": string; + "category": string; + "tags": string[]; + "license": string; + "official": boolean; + "featured": boolean; + "download_count": number; + "average_rating": number; + "review_count": number; + "repository": string; + "url": string; + "publisher_name": string; + "installed": boolean; + "installed_version": string; + "latest_version": string; + "update_available": boolean; + + /** Creates a new AvailablePlugin instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("icon_url" in $$source)) { + this["icon_url"] = ""; + } + if (!("category" in $$source)) { + this["category"] = ""; + } + if (!("tags" in $$source)) { + this["tags"] = []; + } + if (!("license" in $$source)) { + this["license"] = ""; + } + if (!("official" in $$source)) { + this["official"] = false; + } + if (!("featured" in $$source)) { + this["featured"] = false; + } + if (!("download_count" in $$source)) { + this["download_count"] = 0; + } + if (!("average_rating" in $$source)) { + this["average_rating"] = 0; + } + if (!("review_count" in $$source)) { + this["review_count"] = 0; + } + if (!("repository" in $$source)) { + this["repository"] = ""; + } + if (!("url" in $$source)) { + this["url"] = ""; + } + if (!("publisher_name" in $$source)) { + this["publisher_name"] = ""; + } + if (!("installed" in $$source)) { + this["installed"] = false; + } + if (!("installed_version" in $$source)) { + this["installed_version"] = ""; + } + if (!("latest_version" in $$source)) { + this["latest_version"] = ""; + } + if (!("update_available" in $$source)) { + this["update_available"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new AvailablePlugin instance from a string or object. + */ + static createFrom($$source: any = {}): AvailablePlugin { + const $$createField5_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("tags" in $$parsedSource) { + $$parsedSource["tags"] = $$createField5_0($$parsedSource["tags"]); + } + return new AvailablePlugin($$parsedSource as Partial); + } +} + +/** + * DailyStat is a single day's download count. + */ +export class DailyStat { + "date": string; + "count": number; + + /** Creates a new DailyStat instance. */ + constructor($$source: Partial = {}) { + if (!("date" in $$source)) { + this["date"] = ""; + } + if (!("count" in $$source)) { + this["count"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DailyStat instance from a string or object. + */ + static createFrom($$source: any = {}): DailyStat { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DailyStat($$parsedSource as Partial); + } +} + +/** + * DownloadStats holds plugin download statistics. + */ +export class DownloadStats { + "total": number; + "last_month": number; + "last_week": number; + "daily_stats": DailyStat[]; + + /** Creates a new DownloadStats instance. */ + constructor($$source: Partial = {}) { + if (!("total" in $$source)) { + this["total"] = 0; + } + if (!("last_month" in $$source)) { + this["last_month"] = 0; + } + if (!("last_week" in $$source)) { + this["last_week"] = 0; + } + if (!("daily_stats" in $$source)) { + this["daily_stats"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DownloadStats instance from a string or object. + */ + static createFrom($$source: any = {}): DownloadStats { + const $$createField3_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("daily_stats" in $$parsedSource) { + $$parsedSource["daily_stats"] = $$createField3_0($$parsedSource["daily_stats"]); + } + return new DownloadStats($$parsedSource as Partial); + } +} + +/** + * Review represents a plugin review for the frontend. + */ +export class Review { + "id": string; + "user_id": number; + "rating": number; + "title": string; + "body": string; + "created_at": string; + + /** Creates a new Review instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("user_id" in $$source)) { + this["user_id"] = 0; + } + if (!("rating" in $$source)) { + this["rating"] = 0; + } + if (!("title" in $$source)) { + this["title"] = ""; + } + if (!("body" in $$source)) { + this["body"] = ""; + } + if (!("created_at" in $$source)) { + this["created_at"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Review instance from a string or object. + */ + static createFrom($$source: any = {}): Review { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new Review($$parsedSource as Partial); + } +} + +/** + * VersionInfo represents a plugin version for the frontend. + */ +export class VersionInfo { + "version": string; + "description": string; + "changelog": string; + "min_ide_version": string; + "max_ide_version": string; + "capabilities": string[]; + "created_at": string; + + /** Creates a new VersionInfo instance. */ + constructor($$source: Partial = {}) { + if (!("version" in $$source)) { + this["version"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("changelog" in $$source)) { + this["changelog"] = ""; + } + if (!("min_ide_version" in $$source)) { + this["min_ide_version"] = ""; + } + if (!("max_ide_version" in $$source)) { + this["max_ide_version"] = ""; + } + if (!("capabilities" in $$source)) { + this["capabilities"] = []; + } + if (!("created_at" in $$source)) { + this["created_at"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new VersionInfo instance from a string or object. + */ + static createFrom($$source: any = {}): VersionInfo { + const $$createField5_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("capabilities" in $$parsedSource) { + $$parsedSource["capabilities"] = $$createField5_0($$parsedSource["capabilities"]); + } + return new VersionInfo($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = $Create.Array($Create.Any); +const $$createType1 = DailyStat.createFrom; +const $$createType2 = $Create.Array($$createType1); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/index.ts new file mode 100644 index 00000000..ae8dd12e --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/index.ts @@ -0,0 +1,7 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + ConnectionState, + ConnectionStatusPayload +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/models.ts new file mode 100644 index 00000000..5120bc9f --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/resource/models.ts @@ -0,0 +1,141 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as types$0 from "../../../../../plugin-sdk/pkg/types/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as resource$0 from "../../../../../plugin-sdk/pkg/v1/resource/models.js"; + +/** + * ConnectionState is the full state snapshot for a single connection, + * combining metadata, lifecycle, and watch state. Returned by GetAllConnectionStates + * so the frontend can hydrate everything in a single call. + */ +export class ConnectionState { + /** + * Connection metadata (name, avatar, labels, etc.) + */ + "connection": types$0.Connection; + + /** + * Whether this connection is actively started/connected. + */ + "started": boolean; + + /** + * Per-resource watch states (resource key → WatchState enum). + */ + "resources": { [_ in string]?: resource$0.WatchState }; + + /** + * Per-resource object counts (resource key → count of cached objects). + */ + "resourceCounts": { [_ in string]?: number }; + + /** + * Aggregate counts computed server-side. + */ + "totalResources": number; + "syncedCount": number; + "errorCount": number; + + /** + * ISO 8601 timestamp of the last successful sync, or empty if never synced. + * String instead of time.Time for Wails serialization compatibility. + */ + "lastSyncTime"?: string; + + /** Creates a new ConnectionState instance. */ + constructor($$source: Partial = {}) { + if (!("connection" in $$source)) { + this["connection"] = (new types$0.Connection()); + } + if (!("started" in $$source)) { + this["started"] = false; + } + if (!("resources" in $$source)) { + this["resources"] = {}; + } + if (!("resourceCounts" in $$source)) { + this["resourceCounts"] = {}; + } + if (!("totalResources" in $$source)) { + this["totalResources"] = 0; + } + if (!("syncedCount" in $$source)) { + this["syncedCount"] = 0; + } + if (!("errorCount" in $$source)) { + this["errorCount"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ConnectionState instance from a string or object. + */ + static createFrom($$source: any = {}): ConnectionState { + const $$createField0_0 = $$createType0; + const $$createField2_0 = $$createType1; + const $$createField3_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("connection" in $$parsedSource) { + $$parsedSource["connection"] = $$createField0_0($$parsedSource["connection"]); + } + if ("resources" in $$parsedSource) { + $$parsedSource["resources"] = $$createField2_0($$parsedSource["resources"]); + } + if ("resourceCounts" in $$parsedSource) { + $$parsedSource["resourceCounts"] = $$createField3_0($$parsedSource["resourceCounts"]); + } + return new ConnectionState($$parsedSource as Partial); + } +} + +/** + * ConnectionStatusPayload is emitted when a connection's status changes. + */ +export class ConnectionStatusPayload { + "pluginID": string; + "connectionID": string; + "status": string; + "name": string; + + /** Creates a new ConnectionStatusPayload instance. */ + constructor($$source: Partial = {}) { + if (!("pluginID" in $$source)) { + this["pluginID"] = ""; + } + if (!("connectionID" in $$source)) { + this["connectionID"] = ""; + } + if (!("status" in $$source)) { + this["status"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ConnectionStatusPayload instance from a string or object. + */ + static createFrom($$source: any = {}): ConnectionStatusPayload { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ConnectionStatusPayload($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = types$0.Connection.createFrom; +const $$createType1 = $Create.Map($Create.Any, $Create.Any); +const $$createType2 = $Create.Map($Create.Any, $Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/index.ts new file mode 100644 index 00000000..082a80a8 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/index.ts @@ -0,0 +1,6 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + PluginStateRecord +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/models.ts new file mode 100644 index 00000000..8a1256f8 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/types/models.ts @@ -0,0 +1,73 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as lifecycle$0 from "../lifecycle/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as config$0 from "../../../../../plugin-sdk/pkg/config/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../../time/models.js"; + +/** + * PluginStateRecord is the subset of PluginRecord that gets persisted to disk. + */ +export class PluginStateRecord { + "id": string; + "phase": lifecycle$0.PluginPhase; + "metadata": config$0.PluginMeta; + "enabled": boolean; + "devMode": boolean; + "devPath"?: string; + "lastError"?: string; + "errorCount": number; + "installedAt": time$0.Time; + + /** Creates a new PluginStateRecord instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("phase" in $$source)) { + this["phase"] = lifecycle$0.PluginPhase.$zero; + } + if (!("metadata" in $$source)) { + this["metadata"] = (new config$0.PluginMeta()); + } + if (!("enabled" in $$source)) { + this["enabled"] = false; + } + if (!("devMode" in $$source)) { + this["devMode"] = false; + } + if (!("errorCount" in $$source)) { + this["errorCount"] = 0; + } + if (!("installedAt" in $$source)) { + this["installedAt"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginStateRecord instance from a string or object. + */ + static createFrom($$source: any = {}): PluginStateRecord { + const $$createField2_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("metadata" in $$parsedSource) { + $$parsedSource["metadata"] = $$createField2_0($$parsedSource["metadata"]); + } + return new PluginStateRecord($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = config$0.PluginMeta.createFrom; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/index.ts new file mode 100644 index 00000000..883ddfd5 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/index.ts @@ -0,0 +1,15 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as ServiceWrapper from "./servicewrapper.js"; +export { + ServiceWrapper +}; + +export { + GetPluginComponentsInput, + GetResourceAreaComponentInput, + GetResourceComponentsInput, + ResourceComponent, + ResourceComponentArea +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/models.ts new file mode 100644 index 00000000..8c0fadf6 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/models.ts @@ -0,0 +1,135 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +export class GetPluginComponentsInput { + "plugin": string; + + /** Creates a new GetPluginComponentsInput instance. */ + constructor($$source: Partial = {}) { + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetPluginComponentsInput instance from a string or object. + */ + static createFrom($$source: any = {}): GetPluginComponentsInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetPluginComponentsInput($$parsedSource as Partial); + } +} + +export class GetResourceAreaComponentInput { + "plugin": string; + "resource": string; + "area": ResourceComponentArea; + + /** Creates a new GetResourceAreaComponentInput instance. */ + constructor($$source: Partial = {}) { + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("resource" in $$source)) { + this["resource"] = ""; + } + if (!("area" in $$source)) { + this["area"] = ResourceComponentArea.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetResourceAreaComponentInput instance from a string or object. + */ + static createFrom($$source: any = {}): GetResourceAreaComponentInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetResourceAreaComponentInput($$parsedSource as Partial); + } +} + +export class GetResourceComponentsInput { + "plugin": string; + "resource": string; + + /** Creates a new GetResourceComponentsInput instance. */ + constructor($$source: Partial = {}) { + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("resource" in $$source)) { + this["resource"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetResourceComponentsInput instance from a string or object. + */ + static createFrom($$source: any = {}): GetResourceComponentsInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetResourceComponentsInput($$parsedSource as Partial); + } +} + +/** + * ResourceComponent represents a UI component that can be displayed as part of the UI. + */ +export class ResourceComponent { + "owner": string; + "name": string; + "plugin": string; + "resource": string; + "area": ResourceComponentArea; + "extension": string; + + /** Creates a new ResourceComponent instance. */ + constructor($$source: Partial = {}) { + if (!("owner" in $$source)) { + this["owner"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("resource" in $$source)) { + this["resource"] = ""; + } + if (!("area" in $$source)) { + this["area"] = ResourceComponentArea.$zero; + } + if (!("extension" in $$source)) { + this["extension"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceComponent instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceComponent { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ResourceComponent($$parsedSource as Partial); + } +} + +export enum ResourceComponentArea { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + ResourceComponentAreaSidebar = "SIDEBAR", + ResourceComponentAreaTable = "TABLE", +}; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/servicewrapper.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/servicewrapper.ts new file mode 100644 index 00000000..51947170 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/servicewrapper.ts @@ -0,0 +1,41 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * ServiceWrapper exposes only frontend-safe methods of componentManager. + * Internal plugin lifecycle methods (OnPluginInit, OnPluginStart, etc.) + * are excluded to prevent frontend invocation. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +export function GetPluginComponents(params: $models.GetPluginComponentsInput): $CancellablePromise<{ [_ in string]?: $models.ResourceComponent[] }> { + return $Call.ByID(2106300110, params).then(($result: any) => { + return $$createType2($result); + }); +} + +export function GetResourceAreaComponent(params: $models.GetResourceAreaComponentInput): $CancellablePromise<$models.ResourceComponent | null> { + return $Call.ByID(765209827, params).then(($result: any) => { + return $$createType3($result); + }); +} + +export function GetResourceComponents(params: $models.GetResourceComponentsInput): $CancellablePromise<$models.ResourceComponent[]> { + return $Call.ByID(2355436169, params).then(($result: any) => { + return $$createType1($result); + }); +} + +// Private type creation functions +const $$createType0 = $models.ResourceComponent.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Map($Create.Any, $$createType1); +const $$createType3 = $Create.Nullable($$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/client.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/client.ts new file mode 100644 index 00000000..6c32bc31 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/client.ts @@ -0,0 +1,17 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * DetectLanguage detects the language of a file based on its filename and contents. + */ +export function DetectLanguage(params: $models.GetLanguageInput): $CancellablePromise { + return $Call.ByID(3503478684, params); +} diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/index.ts new file mode 100644 index 00000000..06aa14d0 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/index.ts @@ -0,0 +1,11 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as Client from "./client.js"; +export { + Client +}; + +export { + GetLanguageInput +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/models.ts new file mode 100644 index 00000000..e26ddf13 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/utils/models.ts @@ -0,0 +1,31 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +export class GetLanguageInput { + "filename": string; + "contents": string; + + /** Creates a new GetLanguageInput instance. */ + constructor($$source: Partial = {}) { + if (!("filename" in $$source)) { + this["filename"] = ""; + } + if (!("contents" in $$source)) { + this["contents"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetLanguageInput instance from a string or object. + */ + static createFrom($$source: any = {}): GetLanguageInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetLanguageInput($$parsedSource as Partial); + } +} diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/datacontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/datacontrollerservice.ts new file mode 100644 index 00000000..ce433c04 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/datacontrollerservice.ts @@ -0,0 +1,27 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +export function Delete(pluginID: string, key: string): $CancellablePromise { + return $Call.ByID(2784630898, pluginID, key); +} + +export function Get(pluginID: string, key: string): $CancellablePromise { + return $Call.ByID(1249901663, pluginID, key); +} + +export function Keys(pluginID: string): $CancellablePromise { + return $Call.ByID(1862041893, pluginID).then(($result: any) => { + return $$createType0($result); + }); +} + +export function Set(pluginID: string, key: string, value: any): $CancellablePromise { + return $Call.ByID(1059399179, pluginID, key, value); +} + +// Private type creation functions +const $$createType0 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/devserverservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/devserverservice.ts new file mode 100644 index 00000000..5bc777c8 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/devserverservice.ts @@ -0,0 +1,80 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * DevServerService exposes only frontend-safe methods of devserver.DevServerManager. + * The DevServerManager implements ServiceStartup/ServiceShutdown directly, + * but registering it raw causes service/model shadowing. This wrapper separates + * the service identity from the model type. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as devserver$0 from "./backend/pkg/plugin/devserver/models.js"; + +export function GetDevServerLogs(pluginID: string, count: number): $CancellablePromise { + return $Call.ByID(56031670, pluginID, count).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetDevServerState(pluginID: string): $CancellablePromise { + return $Call.ByID(2931579078, pluginID).then(($result: any) => { + return $$createType2($result); + }); +} + +export function GetExternalPluginInfo(pluginID: string): $CancellablePromise { + return $Call.ByID(4231701063, pluginID).then(($result: any) => { + return $$createType4($result); + }); +} + +export function IsManaged(pluginID: string): $CancellablePromise { + return $Call.ByID(1031994258, pluginID); +} + +export function ListDevServerStates(): $CancellablePromise { + return $Call.ByID(3754746401).then(($result: any) => { + return $$createType5($result); + }); +} + +export function RebuildPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(4157478183, pluginID); +} + +export function RestartDevServer(pluginID: string): $CancellablePromise { + return $Call.ByID(2240108516, pluginID).then(($result: any) => { + return $$createType2($result); + }); +} + +export function StartDevServer(pluginID: string): $CancellablePromise { + return $Call.ByID(843165717, pluginID).then(($result: any) => { + return $$createType2($result); + }); +} + +export function StartDevServerForPath(pluginID: string, devPath: string): $CancellablePromise { + return $Call.ByID(4039660679, pluginID, devPath).then(($result: any) => { + return $$createType2($result); + }); +} + +export function StopDevServer(pluginID: string): $CancellablePromise { + return $Call.ByID(1563164227, pluginID); +} + +// Private type creation functions +const $$createType0 = devserver$0.LogEntry.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = devserver$0.DevServerState.createFrom; +const $$createType3 = devserver$0.DevInfoFile.createFrom; +const $$createType4 = $Create.Nullable($$createType3); +const $$createType5 = $Create.Array($$createType2); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/execcontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/execcontrollerservice.ts new file mode 100644 index 00000000..0ac2ff41 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/execcontrollerservice.ts @@ -0,0 +1,98 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as exec$0 from "../plugin-sdk/pkg/v1/exec/models.js"; + +export function AttachSession(sessionID: string): $CancellablePromise<[exec$0.Session | null, string]> { + return $Call.ByID(1518986335, sessionID).then(($result: any) => { + $result[0] = $$createType1($result[0]); + $result[1] = $Create.ByteSlice($result[1]); + return $result; + }); +} + +export function CloseSession(sessionID: string): $CancellablePromise { + return $Call.ByID(108486360, sessionID); +} + +export function CreateSession(plugin: string, connectionID: string, opts: exec$0.SessionOptions): $CancellablePromise { + return $Call.ByID(1614266952, plugin, connectionID, opts).then(($result: any) => { + return $$createType1($result); + }); +} + +export function CreateTerminal(opts: exec$0.SessionOptions): $CancellablePromise { + return $Call.ByID(331634124, opts).then(($result: any) => { + return $$createType1($result); + }); +} + +export function DetachSession(sessionID: string): $CancellablePromise { + return $Call.ByID(1895341881, sessionID).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetHandler(plugin: string, resource: string): $CancellablePromise { + return $Call.ByID(215427448, plugin, resource).then(($result: any) => { + return $$createType3($result); + }); +} + +export function GetHandlers(): $CancellablePromise<{ [_ in string]?: { [_ in string]?: exec$0.Handler } }> { + return $Call.ByID(1102421073).then(($result: any) => { + return $$createType5($result); + }); +} + +export function GetPluginHandlers(plugin: string): $CancellablePromise<{ [_ in string]?: exec$0.Handler }> { + return $Call.ByID(3546807494, plugin).then(($result: any) => { + return $$createType4($result); + }); +} + +export function GetSession(sessionID: string): $CancellablePromise { + return $Call.ByID(2974088048, sessionID).then(($result: any) => { + return $$createType1($result); + }); +} + +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(300230163, pluginID); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(17539472).then(($result: any) => { + return $$createType6($result); + }); +} + +export function ListSessions(): $CancellablePromise<(exec$0.Session | null)[]> { + return $Call.ByID(360069693).then(($result: any) => { + return $$createType7($result); + }); +} + +export function ResizeSession(sessionID: string, rows: number, cols: number): $CancellablePromise { + return $Call.ByID(548917388, sessionID, rows, cols); +} + +export function WriteSession(sessionID: string, data: string): $CancellablePromise { + return $Call.ByID(195216577, sessionID, data); +} + +// Private type creation functions +const $$createType0 = exec$0.Session.createFrom; +const $$createType1 = $Create.Nullable($$createType0); +const $$createType2 = exec$0.Handler.createFrom; +const $$createType3 = $Create.Nullable($$createType2); +const $$createType4 = $Create.Map($Create.Any, $$createType2); +const $$createType5 = $Create.Map($Create.Any, $$createType4); +const $$createType6 = $Create.Array($Create.Any); +const $$createType7 = $Create.Array($$createType1); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/index.ts new file mode 100644 index 00000000..5439b18d --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/index.ts @@ -0,0 +1,34 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as AppService from "./appservice.js"; +import * as DataControllerService from "./datacontrollerservice.js"; +import * as DevServerService from "./devserverservice.js"; +import * as ExecControllerService from "./execcontrollerservice.js"; +import * as LogsControllerService from "./logscontrollerservice.js"; +import * as MetricControllerService from "./metriccontrollerservice.js"; +import * as NetworkerControllerService from "./networkercontrollerservice.js"; +import * as PluginLogService from "./pluginlogservice.js"; +import * as PluginManagerService from "./pluginmanagerservice.js"; +import * as ResourceControllerService from "./resourcecontrollerservice.js"; +import * as SettingsControllerService from "./settingscontrollerservice.js"; +import * as SettingsProviderService from "./settingsproviderservice.js"; +export { + AppService, + DataControllerService, + DevServerService, + ExecControllerService, + LogsControllerService, + MetricControllerService, + NetworkerControllerService, + PluginLogService, + PluginManagerService, + ResourceControllerService, + SettingsControllerService, + SettingsProviderService +}; + +export { + FileDialogOptions, + FileFilter +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/index.ts new file mode 100644 index 00000000..c2a74e92 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/index.ts @@ -0,0 +1,7 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as TelemetryBinding from "./telemetrybinding.js"; +export { + TelemetryBinding +}; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/telemetrybinding.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/telemetrybinding.ts new file mode 100644 index 00000000..7f6e3000 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/internal/telemetry/telemetrybinding.ts @@ -0,0 +1,20 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * TelemetryBinding exposes telemetry operations to the Wails frontend. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +/** + * IngestFrontendSignals accepts a JSON payload from the frontend containing + * logs, errors, and measurements, and converts them into backend telemetry + * signals (Zap logs, OTel trace span events). + */ +export function IngestFrontendSignals(payload: string): $CancellablePromise { + return $Call.ByID(623015471, payload); +} diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/logscontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/logscontrollerservice.ts new file mode 100644 index 00000000..91b66cae --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/logscontrollerservice.ts @@ -0,0 +1,66 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as logs$0 from "../plugin-sdk/pkg/v1/logs/models.js"; + +export function CloseSession(sessionID: string): $CancellablePromise { + return $Call.ByID(3286870078, sessionID); +} + +export function CreateSession(plugin: string, connectionID: string, opts: logs$0.CreateSessionOptions): $CancellablePromise { + return $Call.ByID(1710486702, plugin, connectionID, opts).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetSession(sessionID: string): $CancellablePromise { + return $Call.ByID(365161342, sessionID).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetSupportedResources(pluginID: string): $CancellablePromise { + return $Call.ByID(1885041493, pluginID).then(($result: any) => { + return $$createType3($result); + }); +} + +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(34226137, pluginID); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(3747829186).then(($result: any) => { + return $$createType4($result); + }); +} + +export function ListSessions(): $CancellablePromise<(logs$0.LogSession | null)[]> { + return $Call.ByID(4219296599).then(($result: any) => { + return $$createType5($result); + }); +} + +export function SendCommand(sessionID: string, cmd: logs$0.LogStreamCommand): $CancellablePromise { + return $Call.ByID(4186946429, sessionID, cmd); +} + +export function UpdateSessionOptions(sessionID: string, opts: logs$0.LogSessionOptions): $CancellablePromise { + return $Call.ByID(4077718521, sessionID, opts).then(($result: any) => { + return $$createType1($result); + }); +} + +// Private type creation functions +const $$createType0 = logs$0.LogSession.createFrom; +const $$createType1 = $Create.Nullable($$createType0); +const $$createType2 = logs$0.Handler.createFrom; +const $$createType3 = $Create.Array($$createType2); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = $Create.Array($$createType1); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/metriccontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/metriccontrollerservice.ts new file mode 100644 index 00000000..ee5d68f1 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/metriccontrollerservice.ts @@ -0,0 +1,66 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as metric$0 from "./backend/pkg/plugin/metric/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as metric$1 from "../plugin-sdk/pkg/v1/metric/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../time/models.js"; + +export function GetProviders(): $CancellablePromise { + return $Call.ByID(2838019531).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetProvidersForResource(resourceKey: string): $CancellablePromise { + return $Call.ByID(643157078, resourceKey).then(($result: any) => { + return $$createType1($result); + }); +} + +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(3044575076, pluginID); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(162304859).then(($result: any) => { + return $$createType2($result); + }); +} + +export function Query(pluginID: string, connectionID: string, req: metric$1.QueryRequest): $CancellablePromise { + return $Call.ByID(3357897247, pluginID, connectionID, req).then(($result: any) => { + return $$createType4($result); + }); +} + +export function QueryAll(connectionID: string, resourceKey: string, resourceID: string, $namespace: string, resourceData: { [_ in string]?: any }, metricIDs: string[], shape: metric$1.MetricShape, startTime: time$0.Time, endTime: time$0.Time, step: time$0.Duration): $CancellablePromise<{ [_ in string]?: metric$1.QueryResponse | null }> { + return $Call.ByID(2842472394, connectionID, resourceKey, resourceID, $namespace, resourceData, metricIDs, shape, startTime, endTime, step).then(($result: any) => { + return $$createType5($result); + }); +} + +export function Subscribe(pluginID: string, connectionID: string, req: metric$0.SubscribeRequest): $CancellablePromise { + return $Call.ByID(320253359, pluginID, connectionID, req); +} + +export function Unsubscribe(subscriptionID: string): $CancellablePromise { + return $Call.ByID(715373378, subscriptionID); +} + +// Private type creation functions +const $$createType0 = metric$0.MetricProviderSummary.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Array($Create.Any); +const $$createType3 = metric$1.QueryResponse.createFrom; +const $$createType4 = $Create.Nullable($$createType3); +const $$createType5 = $Create.Map($Create.Any, $$createType4); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/models.ts new file mode 100644 index 00000000..4e1aec92 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/models.ts @@ -0,0 +1,101 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * FileDialogOptions defines options for file dialogs exposed to the frontend. + */ +export class FileDialogOptions { + "defaultDirectory": string; + "defaultFilename": string; + "title": string; + "filters": FileFilter[]; + "showHiddenFiles": boolean; + "canCreateDirectories": boolean; + "resolvesAliases": boolean; + "treatPackagesAsDirectories": boolean; + + /** Creates a new FileDialogOptions instance. */ + constructor($$source: Partial = {}) { + if (!("defaultDirectory" in $$source)) { + this["defaultDirectory"] = ""; + } + if (!("defaultFilename" in $$source)) { + this["defaultFilename"] = ""; + } + if (!("title" in $$source)) { + this["title"] = ""; + } + if (!("filters" in $$source)) { + this["filters"] = []; + } + if (!("showHiddenFiles" in $$source)) { + this["showHiddenFiles"] = false; + } + if (!("canCreateDirectories" in $$source)) { + this["canCreateDirectories"] = false; + } + if (!("resolvesAliases" in $$source)) { + this["resolvesAliases"] = false; + } + if (!("treatPackagesAsDirectories" in $$source)) { + this["treatPackagesAsDirectories"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FileDialogOptions instance from a string or object. + */ + static createFrom($$source: any = {}): FileDialogOptions { + const $$createField3_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("filters" in $$parsedSource) { + $$parsedSource["filters"] = $$createField3_0($$parsedSource["filters"]); + } + return new FileDialogOptions($$parsedSource as Partial); + } +} + +/** + * FileFilter defines a filter for dialog boxes. + */ +export class FileFilter { + /** + * Filter information EG: "Image Files (*.jpg, *.png)" + */ + "displayName": string; + + /** + * semicolon separated list of extensions, EG: "*.jpg;*.png" + */ + "pattern": string; + + /** Creates a new FileFilter instance. */ + constructor($$source: Partial = {}) { + if (!("displayName" in $$source)) { + this["displayName"] = ""; + } + if (!("pattern" in $$source)) { + this["pattern"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FileFilter instance from a string or object. + */ + static createFrom($$source: any = {}): FileFilter { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new FileFilter($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = FileFilter.createFrom; +const $$createType1 = $Create.Array($$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/networkercontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/networkercontrollerservice.ts new file mode 100644 index 00000000..5e1efdb4 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/networkercontrollerservice.ts @@ -0,0 +1,68 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as networker$0 from "../plugin-sdk/pkg/v1/networker/models.js"; + +export function ClosePortForwardSession(sessionID: string): $CancellablePromise { + return $Call.ByID(280793032, sessionID).then(($result: any) => { + return $$createType1($result); + }); +} + +export function FindPortForwardSessions(pluginID: string, connectionID: string, request: networker$0.FindPortForwardSessionRequest): $CancellablePromise<(networker$0.PortForwardSession | null)[]> { + return $Call.ByID(3429152344, pluginID, connectionID, request).then(($result: any) => { + return $$createType2($result); + }); +} + +export function GetPortForwardSession(sessionID: string): $CancellablePromise { + return $Call.ByID(2765408144, sessionID).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetSupportedPortForwardTargets(pluginID: string): $CancellablePromise { + return $Call.ByID(2199710208, pluginID).then(($result: any) => { + return $$createType3($result); + }); +} + +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(1410344939, pluginID); +} + +export function ListAllPortForwardSessions(): $CancellablePromise<(networker$0.PortForwardSession | null)[]> { + return $Call.ByID(92526888).then(($result: any) => { + return $$createType2($result); + }); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(3677762456).then(($result: any) => { + return $$createType3($result); + }); +} + +export function ListPortForwardSessions(pluginID: string, connectionID: string): $CancellablePromise<(networker$0.PortForwardSession | null)[]> { + return $Call.ByID(521717509, pluginID, connectionID).then(($result: any) => { + return $$createType2($result); + }); +} + +export function StartResourcePortForwardingSession(pluginID: string, connectionID: string, opts: networker$0.PortForwardSessionOptions): $CancellablePromise { + return $Call.ByID(4289977092, pluginID, connectionID, opts).then(($result: any) => { + return $$createType1($result); + }); +} + +// Private type creation functions +const $$createType0 = networker$0.PortForwardSession.createFrom; +const $$createType1 = $Create.Nullable($$createType0); +const $$createType2 = $Create.Array($$createType1); +const $$createType3 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginlogservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginlogservice.ts new file mode 100644 index 00000000..c3490502 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginlogservice.ts @@ -0,0 +1,47 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * PluginLogService exposes only frontend-safe methods of pluginlog.Manager. + * Excludes OnEmit (EmitFunc type), Stream (io.Writer), Close, LogDir. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as pluginlog$0 from "./backend/pkg/plugin/pluginlog/models.js"; + +export function GetLogs(pluginID: string, count: number): $CancellablePromise { + return $Call.ByID(3633742133, pluginID, count).then(($result: any) => { + return $$createType1($result); + }); +} + +export function ListStreams(): $CancellablePromise { + return $Call.ByID(1957306775).then(($result: any) => { + return $$createType2($result); + }); +} + +export function SearchLogs(pluginID: string, pattern: string): $CancellablePromise { + return $Call.ByID(753912009, pluginID, pattern).then(($result: any) => { + return $$createType1($result); + }); +} + +export function Subscribe(pluginID: string): $CancellablePromise { + return $Call.ByID(358553566, pluginID); +} + +export function Unsubscribe(pluginID: string): $CancellablePromise { + return $Call.ByID(3199182151, pluginID); +} + +// Private type creation functions +const $$createType0 = pluginlog$0.LogEntry.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginmanagerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginmanagerservice.ts new file mode 100644 index 00000000..6ce02889 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/pluginmanagerservice.ts @@ -0,0 +1,154 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * PluginManagerService exposes only the frontend-safe methods of plugin.Manager. + * Internal methods (SetDevServerChecker, SetPluginLogManager, HandlePluginCrash, + * Initialize, Run, Shutdown) are excluded to avoid binding warnings from + * interface/function-type parameters. + * @module + */ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as plugin$0 from "./backend/pkg/plugin/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as registry$0 from "./backend/pkg/plugin/registry/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as config$0 from "../plugin-sdk/pkg/config/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as types$0 from "../plugin-sdk/pkg/types/models.js"; + +export function GetPlugin(id: string): $CancellablePromise { + return $Call.ByID(4036673098, id).then(($result: any) => { + return $$createType0($result); + }); +} + +export function GetPluginDownloadStats(pluginID: string): $CancellablePromise { + return $Call.ByID(2726517273, pluginID).then(($result: any) => { + return $$createType2($result); + }); +} + +export function GetPluginMeta(id: string): $CancellablePromise { + return $Call.ByID(499197031, id).then(($result: any) => { + return $$createType3($result); + }); +} + +export function GetPluginReadme(pluginID: string): $CancellablePromise { + return $Call.ByID(2763449240, pluginID); +} + +export function GetPluginReleaseHistory(pluginID: string): $CancellablePromise { + return $Call.ByID(1156861621, pluginID).then(($result: any) => { + return $$createType5($result); + }); +} + +export function GetPluginReviews(pluginID: string, page: number): $CancellablePromise { + return $Call.ByID(933402483, pluginID, page).then(($result: any) => { + return $$createType7($result); + }); +} + +export function GetPluginVersions(pluginID: string): $CancellablePromise { + return $Call.ByID(997632447, pluginID).then(($result: any) => { + return $$createType5($result); + }); +} + +export function InstallFromPathPrompt(): $CancellablePromise { + return $Call.ByID(467309803).then(($result: any) => { + return $$createType8($result); + }); +} + +export function InstallInDevMode(): $CancellablePromise { + return $Call.ByID(830591135).then(($result: any) => { + return $$createType8($result); + }); +} + +export function InstallPluginFromPath(path: string): $CancellablePromise { + return $Call.ByID(1186389510, path).then(($result: any) => { + return $$createType8($result); + }); +} + +export function InstallPluginVersion(pluginID: string, version: string): $CancellablePromise { + return $Call.ByID(2959706071, pluginID, version).then(($result: any) => { + return $$createType8($result); + }); +} + +export function ListAvailablePlugins(): $CancellablePromise { + return $Call.ByID(588186274).then(($result: any) => { + return $$createType10($result); + }); +} + +export function ListPluginMetas(): $CancellablePromise { + return $Call.ByID(3279236650).then(($result: any) => { + return $$createType11($result); + }); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(1059385665).then(($result: any) => { + return $$createType12($result); + }); +} + +export function LoadPlugin(id: string, opts: plugin$0.LoadPluginOptions | null): $CancellablePromise { + return $Call.ByID(815485296, id, opts).then(($result: any) => { + return $$createType0($result); + }); +} + +export function ReloadPlugin(id: string): $CancellablePromise { + return $Call.ByID(3455220157, id).then(($result: any) => { + return $$createType0($result); + }); +} + +export function RetryFailedPlugin(id: string): $CancellablePromise { + return $Call.ByID(4058095161, id).then(($result: any) => { + return $$createType0($result); + }); +} + +export function SearchPlugins(query: string, category: string, sort: string): $CancellablePromise { + return $Call.ByID(4050877057, query, category, sort).then(($result: any) => { + return $$createType10($result); + }); +} + +export function UninstallPlugin(id: string): $CancellablePromise { + return $Call.ByID(1540344876, id).then(($result: any) => { + return $$createType0($result); + }); +} + +// Private type creation functions +const $$createType0 = types$0.PluginInfo.createFrom; +const $$createType1 = registry$0.DownloadStats.createFrom; +const $$createType2 = $Create.Nullable($$createType1); +const $$createType3 = config$0.PluginMeta.createFrom; +const $$createType4 = registry$0.VersionInfo.createFrom; +const $$createType5 = $Create.Array($$createType4); +const $$createType6 = registry$0.Review.createFrom; +const $$createType7 = $Create.Array($$createType6); +const $$createType8 = $Create.Nullable($$createType3); +const $$createType9 = registry$0.AvailablePlugin.createFrom; +const $$createType10 = $Create.Array($$createType9); +const $$createType11 = $Create.Array($$createType3); +const $$createType12 = $Create.Array($$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/resourcecontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/resourcecontrollerservice.ts new file mode 100644 index 00000000..868e3616 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/resourcecontrollerservice.ts @@ -0,0 +1,348 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as resource$1 from "./backend/pkg/plugin/resource/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as types$0 from "../plugin-sdk/pkg/types/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as resource$0 from "../plugin-sdk/pkg/v1/resource/models.js"; + +export function AddConnection(pluginID: string, connection: types$0.Connection): $CancellablePromise { + return $Call.ByID(323717028, pluginID, connection); +} + +export function CheckConnection(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(1290919551, pluginID, connectionID).then(($result: any) => { + return $$createType0($result); + }); +} + +export function Create(pluginID: string, connectionID: string, key: string, input: resource$0.CreateInput): $CancellablePromise { + return $Call.ByID(2471289469, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType2($result); + }); +} + +export function Delete(pluginID: string, connectionID: string, key: string, input: resource$0.DeleteInput): $CancellablePromise { + return $Call.ByID(1373038698, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType4($result); + }); +} + +export function EnsureResourceWatch(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(2051591842, pluginID, connectionID, resourceKey); +} + +export function ExecuteAction(pluginID: string, connectionID: string, key: string, actionID: string, input: resource$0.ActionInput): $CancellablePromise { + return $Call.ByID(1114089986, pluginID, connectionID, key, actionID, input).then(($result: any) => { + return $$createType6($result); + }); +} + +export function Find(pluginID: string, connectionID: string, key: string, input: resource$0.FindInput): $CancellablePromise { + return $Call.ByID(1394089850, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType8($result); + }); +} + +/** + * CRUD + */ +export function Get(pluginID: string, connectionID: string, key: string, input: resource$0.GetInput): $CancellablePromise { + return $Call.ByID(3010951415, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType10($result); + }); +} + +/** + * Actions + */ +export function GetActions(pluginID: string, connectionID: string, key: string): $CancellablePromise { + return $Call.ByID(1736730842, pluginID, connectionID, key).then(($result: any) => { + return $$createType12($result); + }); +} + +export function GetAllConnectionStates(): $CancellablePromise<{ [_ in string]?: resource$1.ConnectionState[] }> { + return $Call.ByID(2891839656).then(($result: any) => { + return $$createType15($result); + }); +} + +export function GetConnection(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(3091451887, pluginID, connectionID).then(($result: any) => { + return $$createType16($result); + }); +} + +export function GetConnectionNamespaces(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(117148787, pluginID, connectionID).then(($result: any) => { + return $$createType17($result); + }); +} + +/** + * Editor schemas + */ +export function GetEditorSchemas(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(574615474, pluginID, connectionID).then(($result: any) => { + return $$createType19($result); + }); +} + +export function GetFilterFields(pluginID: string, connectionID: string, key: string): $CancellablePromise { + return $Call.ByID(846915320, pluginID, connectionID, key).then(($result: any) => { + return $$createType21($result); + }); +} + +/** + * Health + */ +export function GetHealth(pluginID: string, connectionID: string, key: string, data: json$0.RawMessage): $CancellablePromise { + return $Call.ByID(3196416417, pluginID, connectionID, key, data).then(($result: any) => { + return $$createType23($result); + }); +} + +/** + * Relationships + */ +export function GetRelationships(pluginID: string, key: string): $CancellablePromise { + return $Call.ByID(1704500202, pluginID, key).then(($result: any) => { + return $$createType25($result); + }); +} + +export function GetResourceCapabilities(pluginID: string, key: string): $CancellablePromise { + return $Call.ByID(349911617, pluginID, key).then(($result: any) => { + return $$createType27($result); + }); +} + +export function GetResourceDefinition(pluginID: string, typeID: string): $CancellablePromise { + return $Call.ByID(303232926, pluginID, typeID).then(($result: any) => { + return $$createType28($result); + }); +} + +export function GetResourceEvents(pluginID: string, connectionID: string, key: string, id: string, $namespace: string, limit: number): $CancellablePromise { + return $Call.ByID(3557154150, pluginID, connectionID, key, id, $namespace, limit).then(($result: any) => { + return $$createType30($result); + }); +} + +export function GetResourceGroup(pluginID: string, groupID: string): $CancellablePromise { + return $Call.ByID(883761498, pluginID, groupID).then(($result: any) => { + return $$createType31($result); + }); +} + +/** + * Type metadata + */ +export function GetResourceGroups(pluginID: string, connectionID: string): $CancellablePromise<{ [_ in string]?: resource$0.ResourceGroup }> { + return $Call.ByID(361444235, pluginID, connectionID).then(($result: any) => { + return $$createType32($result); + }); +} + +export function GetResourceSchema(pluginID: string, connectionID: string, key: string): $CancellablePromise { + return $Call.ByID(2340247220, pluginID, connectionID, key); +} + +export function GetResourceType(pluginID: string, typeID: string): $CancellablePromise { + return $Call.ByID(1933014139, pluginID, typeID).then(($result: any) => { + return $$createType34($result); + }); +} + +export function GetResourceTypes(pluginID: string, connectionID: string): $CancellablePromise<{ [_ in string]?: resource$0.ResourceMeta }> { + return $Call.ByID(1749788824, pluginID, connectionID).then(($result: any) => { + return $$createType35($result); + }); +} + +export function GetWatchState(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(3415900307, pluginID, connectionID).then(($result: any) => { + return $$createType37($result); + }); +} + +/** + * HasPlugin + */ +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(298991208, pluginID); +} + +export function HasResourceType(pluginID: string, typeID: string): $CancellablePromise { + return $Call.ByID(2438176183, pluginID, typeID); +} + +export function IsResourceWatchRunning(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(1484591543, pluginID, connectionID, resourceKey); +} + +export function List(pluginID: string, connectionID: string, key: string, input: resource$0.ListInput): $CancellablePromise { + return $Call.ByID(2720302497, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType39($result); + }); +} + +export function ListAllConnections(): $CancellablePromise<{ [_ in string]?: types$0.Connection[] }> { + return $Call.ByID(193139961).then(($result: any) => { + return $$createType41($result); + }); +} + +export function ListConnections(pluginID: string): $CancellablePromise { + return $Call.ByID(1313312490, pluginID).then(($result: any) => { + return $$createType40($result); + }); +} + +/** + * ListPlugins + */ +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(1994505295).then(($result: any) => { + return $$createType17($result); + }); +} + +export function LoadConnections(pluginID: string): $CancellablePromise { + return $Call.ByID(2825857474, pluginID).then(($result: any) => { + return $$createType40($result); + }); +} + +export function RemoveConnection(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(4277958737, pluginID, connectionID); +} + +export function ResolveRelationships(pluginID: string, connectionID: string, key: string, id: string, $namespace: string): $CancellablePromise { + return $Call.ByID(2178039126, pluginID, connectionID, key, id, $namespace).then(($result: any) => { + return $$createType43($result); + }); +} + +export function RestartResourceWatch(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(1683997851, pluginID, connectionID, resourceKey); +} + +/** + * Connection lifecycle + */ +export function StartConnection(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(102380759, pluginID, connectionID).then(($result: any) => { + return $$createType0($result); + }); +} + +/** + * Watch lifecycle + */ +export function StartConnectionWatch(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(3263327310, pluginID, connectionID); +} + +export function StopConnection(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(739223609, pluginID, connectionID).then(($result: any) => { + return $$createType16($result); + }); +} + +export function StopConnectionWatch(pluginID: string, connectionID: string): $CancellablePromise { + return $Call.ByID(2312638644, pluginID, connectionID); +} + +export function StopResourceWatch(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(3825993976, pluginID, connectionID, resourceKey); +} + +export function StreamAction(pluginID: string, connectionID: string, key: string, actionID: string, input: resource$0.ActionInput): $CancellablePromise { + return $Call.ByID(3335970527, pluginID, connectionID, key, actionID, input); +} + +/** + * Subscriptions + */ +export function SubscribeResource(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(600780239, pluginID, connectionID, resourceKey); +} + +export function UnsubscribeResource(pluginID: string, connectionID: string, resourceKey: string): $CancellablePromise { + return $Call.ByID(1661481870, pluginID, connectionID, resourceKey); +} + +export function Update(pluginID: string, connectionID: string, key: string, input: resource$0.UpdateInput): $CancellablePromise { + return $Call.ByID(1751256212, pluginID, connectionID, key, input).then(($result: any) => { + return $$createType45($result); + }); +} + +export function UpdateConnection(pluginID: string, connection: types$0.Connection): $CancellablePromise { + return $Call.ByID(2879271972, pluginID, connection).then(($result: any) => { + return $$createType16($result); + }); +} + +// Private type creation functions +const $$createType0 = types$0.ConnectionStatus.createFrom; +const $$createType1 = resource$0.CreateResult.createFrom; +const $$createType2 = $Create.Nullable($$createType1); +const $$createType3 = resource$0.DeleteResult.createFrom; +const $$createType4 = $Create.Nullable($$createType3); +const $$createType5 = resource$0.ActionResult.createFrom; +const $$createType6 = $Create.Nullable($$createType5); +const $$createType7 = resource$0.FindResult.createFrom; +const $$createType8 = $Create.Nullable($$createType7); +const $$createType9 = resource$0.GetResult.createFrom; +const $$createType10 = $Create.Nullable($$createType9); +const $$createType11 = resource$0.ActionDescriptor.createFrom; +const $$createType12 = $Create.Array($$createType11); +const $$createType13 = resource$1.ConnectionState.createFrom; +const $$createType14 = $Create.Array($$createType13); +const $$createType15 = $Create.Map($Create.Any, $$createType14); +const $$createType16 = types$0.Connection.createFrom; +const $$createType17 = $Create.Array($Create.Any); +const $$createType18 = resource$0.EditorSchema.createFrom; +const $$createType19 = $Create.Array($$createType18); +const $$createType20 = resource$0.FilterField.createFrom; +const $$createType21 = $Create.Array($$createType20); +const $$createType22 = resource$0.ResourceHealth.createFrom; +const $$createType23 = $Create.Nullable($$createType22); +const $$createType24 = resource$0.RelationshipDescriptor.createFrom; +const $$createType25 = $Create.Array($$createType24); +const $$createType26 = resource$0.ResourceCapabilities.createFrom; +const $$createType27 = $Create.Nullable($$createType26); +const $$createType28 = resource$0.ResourceDefinition.createFrom; +const $$createType29 = resource$0.ResourceEvent.createFrom; +const $$createType30 = $Create.Array($$createType29); +const $$createType31 = resource$0.ResourceGroup.createFrom; +const $$createType32 = $Create.Map($Create.Any, $$createType31); +const $$createType33 = resource$0.ResourceMeta.createFrom; +const $$createType34 = $Create.Nullable($$createType33); +const $$createType35 = $Create.Map($Create.Any, $$createType33); +const $$createType36 = resource$0.WatchConnectionSummary.createFrom; +const $$createType37 = $Create.Nullable($$createType36); +const $$createType38 = resource$0.ListResult.createFrom; +const $$createType39 = $Create.Nullable($$createType38); +const $$createType40 = $Create.Array($$createType16); +const $$createType41 = $Create.Map($Create.Any, $$createType40); +const $$createType42 = resource$0.ResolvedRelationship.createFrom; +const $$createType43 = $Create.Array($$createType42); +const $$createType44 = resource$0.UpdateResult.createFrom; +const $$createType45 = $Create.Nullable($$createType44); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingscontrollerservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingscontrollerservice.ts new file mode 100644 index 00000000..ba7bd2f3 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingscontrollerservice.ts @@ -0,0 +1,58 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as settings$0 from "../plugin-sdk/settings/models.js"; + +export function GetSetting(plugin: string, id: string): $CancellablePromise { + return $Call.ByID(1209436200, plugin, id).then(($result: any) => { + return $$createType0($result); + }); +} + +export function HasPlugin(pluginID: string): $CancellablePromise { + return $Call.ByID(440913115, pluginID); +} + +export function ListPlugins(): $CancellablePromise { + return $Call.ByID(1187124872).then(($result: any) => { + return $$createType1($result); + }); +} + +export function ListSettings(plugin: string): $CancellablePromise<{ [_ in string]?: settings$0.Setting }> { + return $Call.ByID(2802109877, plugin).then(($result: any) => { + return $$createType2($result); + }); +} + +export function PluginValues(plugin: string): $CancellablePromise<{ [_ in string]?: any }> { + return $Call.ByID(2715948825, plugin).then(($result: any) => { + return $$createType3($result); + }); +} + +export function SetSetting(plugin: string, id: string, value: any): $CancellablePromise { + return $Call.ByID(2603413180, plugin, id, value); +} + +export function SetSettings(plugin: string, settingsMap: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(381415389, plugin, settingsMap); +} + +export function Values(): $CancellablePromise<{ [_ in string]?: any }> { + return $Call.ByID(2715455302).then(($result: any) => { + return $$createType3($result); + }); +} + +// Private type creation functions +const $$createType0 = settings$0.Setting.createFrom; +const $$createType1 = $Create.Array($Create.Any); +const $$createType2 = $Create.Map($Create.Any, $$createType0); +const $$createType3 = $Create.Map($Create.Any, $Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingsproviderservice.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingsproviderservice.ts new file mode 100644 index 00000000..fd1718c5 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/omniview/settingsproviderservice.ts @@ -0,0 +1,120 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as settings$0 from "../plugin-sdk/settings/models.js"; + +export function GetBool(id: string): $CancellablePromise { + return $Call.ByID(199975759, id); +} + +export function GetCategories(): $CancellablePromise { + return $Call.ByID(1339187527).then(($result: any) => { + return $$createType1($result); + }); +} + +export function GetCategory(id: string): $CancellablePromise { + return $Call.ByID(2732589519, id).then(($result: any) => { + return $$createType0($result); + }); +} + +export function GetCategoryValues(id: string): $CancellablePromise<{ [_ in string]?: any }> { + return $Call.ByID(3158210645, id).then(($result: any) => { + return $$createType2($result); + }); +} + +export function GetFloat(id: string): $CancellablePromise { + return $Call.ByID(3278855775, id); +} + +export function GetFloatSlice(id: string): $CancellablePromise { + return $Call.ByID(588704383, id).then(($result: any) => { + return $$createType3($result); + }); +} + +export function GetInt(id: string): $CancellablePromise { + return $Call.ByID(3084011556, id); +} + +export function GetIntSlice(id: string): $CancellablePromise { + return $Call.ByID(1052115198, id).then(($result: any) => { + return $$createType4($result); + }); +} + +export function GetSetting(id: string): $CancellablePromise { + return $Call.ByID(250150593, id).then(($result: any) => { + return $$createType5($result); + }); +} + +export function GetSettingValue(id: string): $CancellablePromise { + return $Call.ByID(4025421518, id); +} + +export function GetString(id: string): $CancellablePromise { + return $Call.ByID(1187755918, id); +} + +export function GetStringSlice(id: string): $CancellablePromise { + return $Call.ByID(1832879132, id).then(($result: any) => { + return $$createType6($result); + }); +} + +export function ListSettings(): $CancellablePromise { + return $Call.ByID(89725144).then(($result: any) => { + return $$createType7($result); + }); +} + +export function LoadSettings(): $CancellablePromise { + return $Call.ByID(2308717928); +} + +export function ResetSetting(id: string): $CancellablePromise { + return $Call.ByID(2245976448, id); +} + +export function SaveSettings(): $CancellablePromise { + return $Call.ByID(3807115937); +} + +export function SetSetting(id: string, value: any): $CancellablePromise { + return $Call.ByID(2825655029, id, value); +} + +export function SetSettings(settingsMap: { [_ in string]?: any }): $CancellablePromise { + return $Call.ByID(2820745458, settingsMap); +} + +export function Values(): $CancellablePromise<{ [_ in string]?: any }> { + return $Call.ByID(3413962943).then(($result: any) => { + return $$createType2($result); + }); +} + +// Private type creation functions +const $$createType0 = settings$0.Category.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = $Create.Map($Create.Any, $Create.Any); +const $$createType3 = $Create.Array($Create.Any); +const $$createType4 = $Create.Array($Create.Any); +const $$createType5 = settings$0.Setting.createFrom; +const $$createType6 = $Create.Array($Create.Any); +var $$createType7 = (function $$initCreateType7(...args: any[]): any { + if ($$createType7 === $$initCreateType7) { + $$createType7 = $$createType8; + } + return $$createType7(...args); +}); +const $$createType8 = $Create.Map($Create.Any, $$createType0); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/index.ts new file mode 100644 index 00000000..e6af18f2 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/index.ts @@ -0,0 +1,13 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + PluginAuthor, + PluginComponentArea, + PluginComponents, + PluginMaintainer, + PluginMeta, + PluginResourceComponent, + PluginTheme, + PluginThemeColors +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models.ts new file mode 100644 index 00000000..7a9e0ed9 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models.ts @@ -0,0 +1,323 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +export class PluginAuthor { + "name": string; + "email": string; + "url": string; + + /** Creates a new PluginAuthor instance. */ + constructor($$source: Partial = {}) { + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("email" in $$source)) { + this["email"] = ""; + } + if (!("url" in $$source)) { + this["url"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginAuthor instance from a string or object. + */ + static createFrom($$source: any = {}): PluginAuthor { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PluginAuthor($$parsedSource as Partial); + } +} + +export enum PluginComponentArea { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + PluginComponentAreaEditor = "EDITOR", + PluginComponentAreaSidebar = "SIDEBAR", +}; + +export class PluginComponents { + "resource": PluginResourceComponent[]; + + /** Creates a new PluginComponents instance. */ + constructor($$source: Partial = {}) { + if (!("resource" in $$source)) { + this["resource"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginComponents instance from a string or object. + */ + static createFrom($$source: any = {}): PluginComponents { + const $$createField0_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resource" in $$parsedSource) { + $$parsedSource["resource"] = $$createField0_0($$parsedSource["resource"]); + } + return new PluginComponents($$parsedSource as Partial); + } +} + +export class PluginMaintainer { + "name": string; + "email": string; + + /** Creates a new PluginMaintainer instance. */ + constructor($$source: Partial = {}) { + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("email" in $$source)) { + this["email"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginMaintainer instance from a string or object. + */ + static createFrom($$source: any = {}): PluginMaintainer { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PluginMaintainer($$parsedSource as Partial); + } +} + +/** + * PluginMeta is the plugin description file located at the root of a plugin. + */ +export class PluginMeta { + "id": string; + "version": string; + "name": string; + "icon": string; + "icon_url": string; + "description": string; + "repository": string; + "website": string; + "category": string; + "license": string; + "author"?: PluginAuthor | null; + "maintainers": PluginMaintainer[]; + "tags": string[]; + "dependencies": string[]; + "capabilities": string[]; + "theme": PluginTheme; + "components": PluginComponents; + "schema_version": number; + "sdk_protocol_version": number; + + /** Creates a new PluginMeta instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("version" in $$source)) { + this["version"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("icon_url" in $$source)) { + this["icon_url"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("repository" in $$source)) { + this["repository"] = ""; + } + if (!("website" in $$source)) { + this["website"] = ""; + } + if (!("category" in $$source)) { + this["category"] = ""; + } + if (!("license" in $$source)) { + this["license"] = ""; + } + if (!("maintainers" in $$source)) { + this["maintainers"] = []; + } + if (!("tags" in $$source)) { + this["tags"] = []; + } + if (!("dependencies" in $$source)) { + this["dependencies"] = []; + } + if (!("capabilities" in $$source)) { + this["capabilities"] = []; + } + if (!("theme" in $$source)) { + this["theme"] = (new PluginTheme()); + } + if (!("components" in $$source)) { + this["components"] = (new PluginComponents()); + } + if (!("schema_version" in $$source)) { + this["schema_version"] = 0; + } + if (!("sdk_protocol_version" in $$source)) { + this["sdk_protocol_version"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginMeta instance from a string or object. + */ + static createFrom($$source: any = {}): PluginMeta { + const $$createField10_0 = $$createType3; + const $$createField11_0 = $$createType5; + const $$createField12_0 = $$createType6; + const $$createField13_0 = $$createType6; + const $$createField14_0 = $$createType6; + const $$createField15_0 = $$createType7; + const $$createField16_0 = $$createType8; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("author" in $$parsedSource) { + $$parsedSource["author"] = $$createField10_0($$parsedSource["author"]); + } + if ("maintainers" in $$parsedSource) { + $$parsedSource["maintainers"] = $$createField11_0($$parsedSource["maintainers"]); + } + if ("tags" in $$parsedSource) { + $$parsedSource["tags"] = $$createField12_0($$parsedSource["tags"]); + } + if ("dependencies" in $$parsedSource) { + $$parsedSource["dependencies"] = $$createField13_0($$parsedSource["dependencies"]); + } + if ("capabilities" in $$parsedSource) { + $$parsedSource["capabilities"] = $$createField14_0($$parsedSource["capabilities"]); + } + if ("theme" in $$parsedSource) { + $$parsedSource["theme"] = $$createField15_0($$parsedSource["theme"]); + } + if ("components" in $$parsedSource) { + $$parsedSource["components"] = $$createField16_0($$parsedSource["components"]); + } + return new PluginMeta($$parsedSource as Partial); + } +} + +export class PluginResourceComponent { + "name": string; + "plugin": string; + "area": PluginComponentArea; + "resources": string[]; + "extension": string; + + /** Creates a new PluginResourceComponent instance. */ + constructor($$source: Partial = {}) { + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("area" in $$source)) { + this["area"] = PluginComponentArea.$zero; + } + if (!("resources" in $$source)) { + this["resources"] = []; + } + if (!("extension" in $$source)) { + this["extension"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginResourceComponent instance from a string or object. + */ + static createFrom($$source: any = {}): PluginResourceComponent { + const $$createField3_0 = $$createType6; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resources" in $$parsedSource) { + $$parsedSource["resources"] = $$createField3_0($$parsedSource["resources"]); + } + return new PluginResourceComponent($$parsedSource as Partial); + } +} + +export class PluginTheme { + "colors": PluginThemeColors; + + /** Creates a new PluginTheme instance. */ + constructor($$source: Partial = {}) { + if (!("colors" in $$source)) { + this["colors"] = (new PluginThemeColors()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginTheme instance from a string or object. + */ + static createFrom($$source: any = {}): PluginTheme { + const $$createField0_0 = $$createType9; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("colors" in $$parsedSource) { + $$parsedSource["colors"] = $$createField0_0($$parsedSource["colors"]); + } + return new PluginTheme($$parsedSource as Partial); + } +} + +export class PluginThemeColors { + "primary": string; + "secondary": string; + "tertiary": string; + + /** Creates a new PluginThemeColors instance. */ + constructor($$source: Partial = {}) { + if (!("primary" in $$source)) { + this["primary"] = ""; + } + if (!("secondary" in $$source)) { + this["secondary"] = ""; + } + if (!("tertiary" in $$source)) { + this["tertiary"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginThemeColors instance from a string or object. + */ + static createFrom($$source: any = {}): PluginThemeColors { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PluginThemeColors($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = PluginResourceComponent.createFrom; +const $$createType1 = $Create.Array($$createType0); +const $$createType2 = PluginAuthor.createFrom; +const $$createType3 = $Create.Nullable($$createType2); +const $$createType4 = PluginMaintainer.createFrom; +const $$createType5 = $Create.Array($$createType4); +const $$createType6 = $Create.Array($Create.Any); +const $$createType7 = PluginTheme.createFrom; +const $$createType8 = PluginComponents.createFrom; +const $$createType9 = PluginThemeColors.createFrom; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/index.ts new file mode 100644 index 00000000..6f037524 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/index.ts @@ -0,0 +1,14 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + Capability, + Connection, + ConnectionAutoConnect, + ConnectionAutoConnectRetry, + ConnectionAutoConnectTrigger, + ConnectionLifecycle, + ConnectionStatus, + ConnectionStatusCode, + PluginInfo +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models.ts new file mode 100644 index 00000000..4e00bd59 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models.ts @@ -0,0 +1,387 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as config$0 from "../config/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../time/models.js"; + +/** + * Capability represents a plugin capability as a string type. + * Using strings allows direct matching with YAML/JSON config values + * and makes adding new capabilities non-breaking. + */ +export enum Capability { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + CapabilityResource = "resource", + CapabilityExec = "exec", + CapabilityNetworker = "networker", + CapabilityLog = "log", + CapabilityMetric = "metric", + CapabilitySettings = "settings", + CapabilityUI = "ui", +}; + +/** + * Connection holds the current state (and configuration data) for an + * connection target for a plugin (e.g. a Kubernetes cluster, a cloud role, etc) + * + * This will be passed within the PluginContext so that it may be used across all requests, + * and data here not within the sensitiveStore will be exposed to the user in the UI for the + * plugin. + */ +export class Connection { + /** + * LastRefresh is the time when the auth context was last refreshed + * +optional + */ + "last_refresh": time$0.Time; + + /** + * Data is an optional map of arbitrary data that can be used to store additional information about the connection, + * such as credential file locations, etc. + * + * This data is exposed to the user in the UI under the settings panel for the namespace. If the data is sensitive, + * it should be stored in the SensitiveData field. + * +optional + */ + "data": { [_ in string]?: any }; + + /** + * Labels is a map of arbitrary key-value pairs that can be used to store additional information about the connection. + * Users will likely use and modify these labels to help organize and categorize their connections. + */ + "labels": { [_ in string]?: any }; + + /** + * Lifecycle contains IDE-managed lifecycle behavior for the connection. + * This is used by the host to orchestrate behaviors like auto-connect. + */ + "lifecycle": ConnectionLifecycle; + + /** + * ID is the unique identifier for the connection that makes sense to the plugin implementation. + * +required + */ + "id": string; + + /** + * UID is an autogenerated unique identifier for the connection that the IDE will use to identify and track. + */ + "uid": string; + + /** + * Name is the readable name of the connection. Editable by the user. + * +required + */ + "name": string; + + /** + * Description is an optional description of the connection. This is primarily for the user to customize + * the visual representation of the connection. + * +optional + */ + "description": string; + + /** + * Avatar is an optional image that can be used to represent the connection. This is primarily for the user to customize + * the visual representation of the connection in the UI. + * +optional + */ + "avatar": string; + + /** + * ExpiryTime is the amount of time before the connection expires. + * +optional + */ + "expiry_time": time$0.Duration; + + /** + * Client is a client structure that should be populated when the connection is created and used for connections + */ + "Client": any; + + /** Creates a new Connection instance. */ + constructor($$source: Partial = {}) { + if (!("last_refresh" in $$source)) { + this["last_refresh"] = null; + } + if (!("data" in $$source)) { + this["data"] = {}; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + if (!("lifecycle" in $$source)) { + this["lifecycle"] = (new ConnectionLifecycle()); + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("uid" in $$source)) { + this["uid"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("avatar" in $$source)) { + this["avatar"] = ""; + } + if (!("expiry_time" in $$source)) { + this["expiry_time"] = time$0.Duration.$zero; + } + if (!("Client" in $$source)) { + this["Client"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Connection instance from a string or object. + */ + static createFrom($$source: any = {}): Connection { + const $$createField1_0 = $$createType0; + const $$createField2_0 = $$createType0; + const $$createField3_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("data" in $$parsedSource) { + $$parsedSource["data"] = $$createField1_0($$parsedSource["data"]); + } + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField2_0($$parsedSource["labels"]); + } + if ("lifecycle" in $$parsedSource) { + $$parsedSource["lifecycle"] = $$createField3_0($$parsedSource["lifecycle"]); + } + return new Connection($$parsedSource as Partial); + } +} + +export class ConnectionAutoConnect { + "enabled": boolean; + "triggers": ConnectionAutoConnectTrigger[]; + "retry": ConnectionAutoConnectRetry; + + /** Creates a new ConnectionAutoConnect instance. */ + constructor($$source: Partial = {}) { + if (!("enabled" in $$source)) { + this["enabled"] = false; + } + if (!("triggers" in $$source)) { + this["triggers"] = []; + } + if (!("retry" in $$source)) { + this["retry"] = ConnectionAutoConnectRetry.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ConnectionAutoConnect instance from a string or object. + */ + static createFrom($$source: any = {}): ConnectionAutoConnect { + const $$createField1_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("triggers" in $$parsedSource) { + $$parsedSource["triggers"] = $$createField1_0($$parsedSource["triggers"]); + } + return new ConnectionAutoConnect($$parsedSource as Partial); + } +} + +export enum ConnectionAutoConnectRetry { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + ConnectionAutoConnectRetryNone = "NONE", + ConnectionAutoConnectRetryOnChange = "ON_CHANGE", +}; + +export enum ConnectionAutoConnectTrigger { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + ConnectionAutoConnectTriggerPluginStart = "PLUGIN_START", + ConnectionAutoConnectTriggerConnectionDiscovered = "CONNECTION_DISCOVERED", +}; + +export class ConnectionLifecycle { + "auto_connect"?: ConnectionAutoConnect | null; + + /** Creates a new ConnectionLifecycle instance. */ + constructor($$source: Partial = {}) { + + Object.assign(this, $$source); + } + + /** + * Creates a new ConnectionLifecycle instance from a string or object. + */ + static createFrom($$source: any = {}): ConnectionLifecycle { + const $$createField0_0 = $$createType4; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("auto_connect" in $$parsedSource) { + $$parsedSource["auto_connect"] = $$createField0_0($$parsedSource["auto_connect"]); + } + return new ConnectionLifecycle($$parsedSource as Partial); + } +} + +export class ConnectionStatus { + /** + * Connection is the connection that the status is for. + */ + "connection": Connection | null; + + /** + * StatusCode is the status code of the connection status. + */ + "status": ConnectionStatusCode; + + /** + * Error is the error that occurred when checking the connection status. + */ + "error": string; + + /** + * Message is a human readable message that describes the status. + */ + "details": string; + + /** Creates a new ConnectionStatus instance. */ + constructor($$source: Partial = {}) { + if (!("connection" in $$source)) { + this["connection"] = null; + } + if (!("status" in $$source)) { + this["status"] = ConnectionStatusCode.$zero; + } + if (!("error" in $$source)) { + this["error"] = ""; + } + if (!("details" in $$source)) { + this["details"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ConnectionStatus instance from a string or object. + */ + static createFrom($$source: any = {}): ConnectionStatus { + const $$createField0_0 = $$createType6; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("connection" in $$parsedSource) { + $$parsedSource["connection"] = $$createField0_0($$parsedSource["connection"]); + } + return new ConnectionStatus($$parsedSource as Partial); + } +} + +export enum ConnectionStatusCode { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + ConnectionStatusUnknown = "UNKNOWN", + ConnectionStatusConnected = "CONNECTED", + ConnectionStatusDisconnected = "DISCONNECTED", + ConnectionStatusPending = "PENDING", + ConnectionStatusFailed = "FAILED", + ConnectionStatusError = "ERROR", + ConnectionStatusUnauthorized = "UNAUTHORIZED", + ConnectionStatusForbidden = "FORBIDDEN", + ConnectionStatusBadRequest = "BAD_REQUEST", + ConnectionStatusNotFound = "NOT_FOUND", + ConnectionStatusTimeout = "TIMEOUT", + ConnectionStatusUnavailable = "UNAVAILABLE", + ConnectionStatusRequestEntityTooLarge = "REQUEST_ENTITY_TOO_LARGE", +}; + +/** + * PluginInfo represents the display/API-facing view of a plugin. + * This type is safe to serialize to JSON for the frontend. + * Runtime fields (RPCClient, PluginClient) live in the host-only PluginRecord. + */ +export class PluginInfo { + "id": string; + "metadata": config$0.PluginMeta; + "phase": string; + "enabled": boolean; + "devMode": boolean; + "devPath"?: string; + "capabilities": Capability[]; + "lastError"?: string; + + /** Creates a new PluginInfo instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("metadata" in $$source)) { + this["metadata"] = (new config$0.PluginMeta()); + } + if (!("phase" in $$source)) { + this["phase"] = ""; + } + if (!("enabled" in $$source)) { + this["enabled"] = false; + } + if (!("devMode" in $$source)) { + this["devMode"] = false; + } + if (!("capabilities" in $$source)) { + this["capabilities"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PluginInfo instance from a string or object. + */ + static createFrom($$source: any = {}): PluginInfo { + const $$createField1_0 = $$createType7; + const $$createField6_0 = $$createType8; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("metadata" in $$parsedSource) { + $$parsedSource["metadata"] = $$createField1_0($$parsedSource["metadata"]); + } + if ("capabilities" in $$parsedSource) { + $$parsedSource["capabilities"] = $$createField6_0($$parsedSource["capabilities"]); + } + return new PluginInfo($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = $Create.Map($Create.Any, $Create.Any); +const $$createType1 = ConnectionLifecycle.createFrom; +const $$createType2 = $Create.Array($Create.Any); +const $$createType3 = ConnectionAutoConnect.createFrom; +const $$createType4 = $Create.Nullable($$createType3); +const $$createType5 = Connection.createFrom; +const $$createType6 = $Create.Nullable($$createType5); +const $$createType7 = config$0.PluginMeta.createFrom; +const $$createType8 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/index.ts new file mode 100644 index 00000000..c84b477f --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/index.ts @@ -0,0 +1,9 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + ActionTargetBuilder, + Handler, + Session, + SessionOptions +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/models.ts new file mode 100644 index 00000000..35df6e1c --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/models.ts @@ -0,0 +1,229 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * ActionTargetBuilder builds a dynamic list of targets for an action. + */ +export class ActionTargetBuilder { + "label": string; + "label_selector": string; + "paths": string[]; + "selectors": { [_ in string]?: string }; + + /** Creates a new ActionTargetBuilder instance. */ + constructor($$source: Partial = {}) { + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("label_selector" in $$source)) { + this["label_selector"] = ""; + } + if (!("paths" in $$source)) { + this["paths"] = []; + } + if (!("selectors" in $$source)) { + this["selectors"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActionTargetBuilder instance from a string or object. + */ + static createFrom($$source: any = {}): ActionTargetBuilder { + const $$createField2_0 = $$createType0; + const $$createField3_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("paths" in $$parsedSource) { + $$parsedSource["paths"] = $$createField2_0($$parsedSource["paths"]); + } + if ("selectors" in $$parsedSource) { + $$parsedSource["selectors"] = $$createField3_0($$parsedSource["selectors"]); + } + return new ActionTargetBuilder($$parsedSource as Partial); + } +} + +/** + * Handler handles running commands and creating sessions for a resource. + */ +export class Handler { + "plugin": string; + "resource": string; + "target_builder": ActionTargetBuilder; + "default_command": string[]; + + /** Creates a new Handler instance. */ + constructor($$source: Partial = {}) { + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("resource" in $$source)) { + this["resource"] = ""; + } + if (!("target_builder" in $$source)) { + this["target_builder"] = (new ActionTargetBuilder()); + } + if (!("default_command" in $$source)) { + this["default_command"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Handler instance from a string or object. + */ + static createFrom($$source: any = {}): Handler { + const $$createField2_0 = $$createType2; + const $$createField3_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("target_builder" in $$parsedSource) { + $$parsedSource["target_builder"] = $$createField2_0($$parsedSource["target_builder"]); + } + if ("default_command" in $$parsedSource) { + $$parsedSource["default_command"] = $$createField3_0($$parsedSource["default_command"]); + } + return new Handler($$parsedSource as Partial); + } +} + +/** + * Session is a snapshot value type — safe for concurrent reads, returned by + * the public API. It carries no mutable internal state. + */ +export class Session { + "created_at": time$0.Time; + "labels": { [_ in string]?: string }; + "params": { [_ in string]?: string }; + "id": string; + "command": string[]; + "attached": boolean; + + /** Creates a new Session instance. */ + constructor($$source: Partial = {}) { + if (!("created_at" in $$source)) { + this["created_at"] = null; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + if (!("params" in $$source)) { + this["params"] = {}; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("command" in $$source)) { + this["command"] = []; + } + if (!("attached" in $$source)) { + this["attached"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Session instance from a string or object. + */ + static createFrom($$source: any = {}): Session { + const $$createField1_0 = $$createType1; + const $$createField2_0 = $$createType1; + const $$createField4_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField1_0($$parsedSource["labels"]); + } + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField2_0($$parsedSource["params"]); + } + if ("command" in $$parsedSource) { + $$parsedSource["command"] = $$createField4_0($$parsedSource["command"]); + } + return new Session($$parsedSource as Partial); + } +} + +/** + * SessionOptions contains options for creating a new terminal session. + */ +export class SessionOptions { + "params": { [_ in string]?: string }; + "labels": { [_ in string]?: string }; + "id": string; + "resource_plugin": string; + "resource_key": string; + "resource_data": { [_ in string]?: any }; + "command": string[]; + "tty": boolean; + + /** Creates a new SessionOptions instance. */ + constructor($$source: Partial = {}) { + if (!("params" in $$source)) { + this["params"] = {}; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("resource_plugin" in $$source)) { + this["resource_plugin"] = ""; + } + if (!("resource_key" in $$source)) { + this["resource_key"] = ""; + } + if (!("resource_data" in $$source)) { + this["resource_data"] = {}; + } + if (!("command" in $$source)) { + this["command"] = []; + } + if (!("tty" in $$source)) { + this["tty"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SessionOptions instance from a string or object. + */ + static createFrom($$source: any = {}): SessionOptions { + const $$createField0_0 = $$createType1; + const $$createField1_0 = $$createType1; + const $$createField5_0 = $$createType3; + const $$createField6_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField0_0($$parsedSource["params"]); + } + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField1_0($$parsedSource["labels"]); + } + if ("resource_data" in $$parsedSource) { + $$parsedSource["resource_data"] = $$createField5_0($$parsedSource["resource_data"]); + } + if ("command" in $$parsedSource) { + $$parsedSource["command"] = $$createField6_0($$parsedSource["command"]); + } + return new SessionOptions($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = $Create.Array($Create.Any); +const $$createType1 = $Create.Map($Create.Any, $Create.Any); +const $$createType2 = ActionTargetBuilder.createFrom; +const $$createType3 = $Create.Map($Create.Any, $Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/index.ts new file mode 100644 index 00000000..560c9781 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/index.ts @@ -0,0 +1,13 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + ActionTargetBuilder, + CreateSessionOptions, + Handler, + LogSession, + LogSessionOptions, + LogSessionStatus, + LogSource, + LogStreamCommand +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/models.ts new file mode 100644 index 00000000..d17161ed --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/models.ts @@ -0,0 +1,331 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * ActionTargetBuilder builds a dynamic list of targets for an action. + */ +export class ActionTargetBuilder { + "label": string; + "label_selector": string; + "paths": string[]; + "selectors": { [_ in string]?: string }; + + /** Creates a new ActionTargetBuilder instance. */ + constructor($$source: Partial = {}) { + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("label_selector" in $$source)) { + this["label_selector"] = ""; + } + if (!("paths" in $$source)) { + this["paths"] = []; + } + if (!("selectors" in $$source)) { + this["selectors"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActionTargetBuilder instance from a string or object. + */ + static createFrom($$source: any = {}): ActionTargetBuilder { + const $$createField2_0 = $$createType0; + const $$createField3_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("paths" in $$parsedSource) { + $$parsedSource["paths"] = $$createField2_0($$parsedSource["paths"]); + } + if ("selectors" in $$parsedSource) { + $$parsedSource["selectors"] = $$createField3_0($$parsedSource["selectors"]); + } + return new ActionTargetBuilder($$parsedSource as Partial); + } +} + +/** + * CreateSessionOptions contains everything needed to create a log session. + */ +export class CreateSessionOptions { + "resource_key": string; + "resource_id": string; + "resource_data": { [_ in string]?: any }; + "options": LogSessionOptions; + + /** Creates a new CreateSessionOptions instance. */ + constructor($$source: Partial = {}) { + if (!("resource_key" in $$source)) { + this["resource_key"] = ""; + } + if (!("resource_id" in $$source)) { + this["resource_id"] = ""; + } + if (!("resource_data" in $$source)) { + this["resource_data"] = {}; + } + if (!("options" in $$source)) { + this["options"] = (new LogSessionOptions()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new CreateSessionOptions instance from a string or object. + */ + static createFrom($$source: any = {}): CreateSessionOptions { + const $$createField2_0 = $$createType2; + const $$createField3_0 = $$createType3; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resource_data" in $$parsedSource) { + $$parsedSource["resource_data"] = $$createField2_0($$parsedSource["resource_data"]); + } + if ("options" in $$parsedSource) { + $$parsedSource["options"] = $$createField3_0($$parsedSource["options"]); + } + return new CreateSessionOptions($$parsedSource as Partial); + } +} + +/** + * Handler describes a log handler for a specific resource type. + */ +export class Handler { + "plugin": string; + "resource": string; + "target_builder": ActionTargetBuilder; + + /** Creates a new Handler instance. */ + constructor($$source: Partial = {}) { + if (!("plugin" in $$source)) { + this["plugin"] = ""; + } + if (!("resource" in $$source)) { + this["resource"] = ""; + } + if (!("target_builder" in $$source)) { + this["target_builder"] = (new ActionTargetBuilder()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Handler instance from a string or object. + */ + static createFrom($$source: any = {}): Handler { + const $$createField2_0 = $$createType4; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("target_builder" in $$parsedSource) { + $$parsedSource["target_builder"] = $$createField2_0($$parsedSource["target_builder"]); + } + return new Handler($$parsedSource as Partial); + } +} + +/** + * LogSession represents an active log viewing session. + */ +export class LogSession { + "id": string; + "plugin_id": string; + "connection_id": string; + "resource_key": string; + "resource_id": string; + "options": LogSessionOptions; + "status": LogSessionStatus; + "active_sources": LogSource[]; + "created_at": time$0.Time; + + /** Creates a new LogSession instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("plugin_id" in $$source)) { + this["plugin_id"] = ""; + } + if (!("connection_id" in $$source)) { + this["connection_id"] = ""; + } + if (!("resource_key" in $$source)) { + this["resource_key"] = ""; + } + if (!("resource_id" in $$source)) { + this["resource_id"] = ""; + } + if (!("options" in $$source)) { + this["options"] = (new LogSessionOptions()); + } + if (!("status" in $$source)) { + this["status"] = LogSessionStatus.$zero; + } + if (!("active_sources" in $$source)) { + this["active_sources"] = []; + } + if (!("created_at" in $$source)) { + this["created_at"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogSession instance from a string or object. + */ + static createFrom($$source: any = {}): LogSession { + const $$createField5_0 = $$createType3; + const $$createField7_0 = $$createType6; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("options" in $$parsedSource) { + $$parsedSource["options"] = $$createField5_0($$parsedSource["options"]); + } + if ("active_sources" in $$parsedSource) { + $$parsedSource["active_sources"] = $$createField7_0($$parsedSource["active_sources"]); + } + return new LogSession($$parsedSource as Partial); + } +} + +/** + * LogSessionOptions contains options for creating or updating a log session. + */ +export class LogSessionOptions { + "target": string; + "follow": boolean; + "include_previous": boolean; + "include_timestamps": boolean; + "tail_lines": number; + "since_seconds": number; + "since_time"?: time$0.Time | null; + "limit_bytes": number; + "include_source_events": boolean; + "params": { [_ in string]?: string }; + + /** Creates a new LogSessionOptions instance. */ + constructor($$source: Partial = {}) { + if (!("target" in $$source)) { + this["target"] = ""; + } + if (!("follow" in $$source)) { + this["follow"] = false; + } + if (!("include_previous" in $$source)) { + this["include_previous"] = false; + } + if (!("include_timestamps" in $$source)) { + this["include_timestamps"] = false; + } + if (!("tail_lines" in $$source)) { + this["tail_lines"] = 0; + } + if (!("since_seconds" in $$source)) { + this["since_seconds"] = 0; + } + if (!("limit_bytes" in $$source)) { + this["limit_bytes"] = 0; + } + if (!("include_source_events" in $$source)) { + this["include_source_events"] = false; + } + if (!("params" in $$source)) { + this["params"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogSessionOptions instance from a string or object. + */ + static createFrom($$source: any = {}): LogSessionOptions { + const $$createField9_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField9_0($$parsedSource["params"]); + } + return new LogSessionOptions($$parsedSource as Partial); + } +} + +/** + * LogSessionStatus represents the status of a log session. + */ +export enum LogSessionStatus { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + LogSessionStatusActive = 0, + LogSessionStatusPaused = 1, + LogSessionStatusClosed = 2, + LogSessionStatusError = 3, + LogSessionStatusConnecting = 4, + LogSessionStatusInitializing = 5, +}; + +/** + * LogSource is a generic log-producing entity. + */ +export class LogSource { + "id": string; + "labels": { [_ in string]?: string }; + + /** Creates a new LogSource instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new LogSource instance from a string or object. + */ + static createFrom($$source: any = {}): LogSource { + const $$createField1_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField1_0($$parsedSource["labels"]); + } + return new LogSource($$parsedSource as Partial); + } +} + +/** + * LogStreamCommand represents a command from the client to control the stream. + */ +export enum LogStreamCommand { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + StreamCommandPause = 0, + StreamCommandResume = 1, + StreamCommandClose = 2, +}; + +// Private type creation functions +const $$createType0 = $Create.Array($Create.Any); +const $$createType1 = $Create.Map($Create.Any, $Create.Any); +const $$createType2 = $Create.Map($Create.Any, $Create.Any); +const $$createType3 = LogSessionOptions.createFrom; +const $$createType4 = ActionTargetBuilder.createFrom; +const $$createType5 = LogSource.createFrom; +const $$createType6 = $Create.Array($$createType5); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/index.ts new file mode 100644 index 00000000..fb1e40c5 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/index.ts @@ -0,0 +1,17 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + AggregateValue, + ColorRange, + CurrentValue, + DataPoint, + Handler, + MetricDescriptor, + MetricResult, + MetricShape, + MetricUnit, + QueryRequest, + QueryResponse, + TimeSeries +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models.ts new file mode 100644 index 00000000..33b6c9f5 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models.ts @@ -0,0 +1,519 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * AggregateValue represents aggregated metric data over a window. + */ +export class AggregateValue { + "metric_id": string; + "min": number; + "max": number; + "avg": number; + "sum": number; + "p50": number; + "p90": number; + "p99": number; + "count": number; + "window": time$0.Duration; + "labels": { [_ in string]?: string }; + + /** Creates a new AggregateValue instance. */ + constructor($$source: Partial = {}) { + if (!("metric_id" in $$source)) { + this["metric_id"] = ""; + } + if (!("min" in $$source)) { + this["min"] = 0; + } + if (!("max" in $$source)) { + this["max"] = 0; + } + if (!("avg" in $$source)) { + this["avg"] = 0; + } + if (!("sum" in $$source)) { + this["sum"] = 0; + } + if (!("p50" in $$source)) { + this["p50"] = 0; + } + if (!("p90" in $$source)) { + this["p90"] = 0; + } + if (!("p99" in $$source)) { + this["p99"] = 0; + } + if (!("count" in $$source)) { + this["count"] = 0; + } + if (!("window" in $$source)) { + this["window"] = time$0.Duration.$zero; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new AggregateValue instance from a string or object. + */ + static createFrom($$source: any = {}): AggregateValue { + const $$createField10_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField10_0($$parsedSource["labels"]); + } + return new AggregateValue($$parsedSource as Partial); + } +} + +/** + * ColorRange defines a color to use for a range of metric values. + */ +export class ColorRange { + "min": number; + "max": number; + "color": string; + + /** Creates a new ColorRange instance. */ + constructor($$source: Partial = {}) { + if (!("min" in $$source)) { + this["min"] = 0; + } + if (!("max" in $$source)) { + this["max"] = 0; + } + if (!("color" in $$source)) { + this["color"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ColorRange instance from a string or object. + */ + static createFrom($$source: any = {}): ColorRange { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ColorRange($$parsedSource as Partial); + } +} + +/** + * CurrentValue represents the current value of a metric. + */ +export class CurrentValue { + "metric_id": string; + "value": number; + "timestamp": time$0.Time; + "labels": { [_ in string]?: string }; + + /** Creates a new CurrentValue instance. */ + constructor($$source: Partial = {}) { + if (!("metric_id" in $$source)) { + this["metric_id"] = ""; + } + if (!("value" in $$source)) { + this["value"] = 0; + } + if (!("timestamp" in $$source)) { + this["timestamp"] = null; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new CurrentValue instance from a string or object. + */ + static createFrom($$source: any = {}): CurrentValue { + const $$createField3_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField3_0($$parsedSource["labels"]); + } + return new CurrentValue($$parsedSource as Partial); + } +} + +/** + * DataPoint represents a single data point in a time series. + */ +export class DataPoint { + "timestamp": time$0.Time; + "value": number; + "labels": { [_ in string]?: string }; + + /** Creates a new DataPoint instance. */ + constructor($$source: Partial = {}) { + if (!("timestamp" in $$source)) { + this["timestamp"] = null; + } + if (!("value" in $$source)) { + this["value"] = 0; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DataPoint instance from a string or object. + */ + static createFrom($$source: any = {}): DataPoint { + const $$createField2_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField2_0($$parsedSource["labels"]); + } + return new DataPoint($$parsedSource as Partial); + } +} + +/** + * Handler maps a resource key to its available metrics. + */ +export class Handler { + "resource": string; + "metrics": MetricDescriptor[]; + + /** Creates a new Handler instance. */ + constructor($$source: Partial = {}) { + if (!("resource" in $$source)) { + this["resource"] = ""; + } + if (!("metrics" in $$source)) { + this["metrics"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Handler instance from a string or object. + */ + static createFrom($$source: any = {}): Handler { + const $$createField1_0 = $$createType2; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("metrics" in $$parsedSource) { + $$parsedSource["metrics"] = $$createField1_0($$parsedSource["metrics"]); + } + return new Handler($$parsedSource as Partial); + } +} + +/** + * MetricDescriptor describes a single metric. + */ +export class MetricDescriptor { + "id": string; + "name": string; + "unit": MetricUnit; + "icon": string; + "color_ranges": ColorRange[]; + "format_string": string; + "supported_shapes": MetricShape[]; + "chart_group": string; + + /** Creates a new MetricDescriptor instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("unit" in $$source)) { + this["unit"] = MetricUnit.$zero; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("color_ranges" in $$source)) { + this["color_ranges"] = []; + } + if (!("format_string" in $$source)) { + this["format_string"] = ""; + } + if (!("supported_shapes" in $$source)) { + this["supported_shapes"] = []; + } + if (!("chart_group" in $$source)) { + this["chart_group"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new MetricDescriptor instance from a string or object. + */ + static createFrom($$source: any = {}): MetricDescriptor { + const $$createField4_0 = $$createType4; + const $$createField6_0 = $$createType5; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("color_ranges" in $$parsedSource) { + $$parsedSource["color_ranges"] = $$createField4_0($$parsedSource["color_ranges"]); + } + if ("supported_shapes" in $$parsedSource) { + $$parsedSource["supported_shapes"] = $$createField6_0($$parsedSource["supported_shapes"]); + } + return new MetricDescriptor($$parsedSource as Partial); + } +} + +/** + * MetricResult wraps one of the possible metric result types. + */ +export class MetricResult { + "time_series"?: TimeSeries | null; + "current_value"?: CurrentValue | null; + "aggregate_value"?: AggregateValue | null; + + /** Creates a new MetricResult instance. */ + constructor($$source: Partial = {}) { + + Object.assign(this, $$source); + } + + /** + * Creates a new MetricResult instance from a string or object. + */ + static createFrom($$source: any = {}): MetricResult { + const $$createField0_0 = $$createType7; + const $$createField1_0 = $$createType9; + const $$createField2_0 = $$createType11; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("time_series" in $$parsedSource) { + $$parsedSource["time_series"] = $$createField0_0($$parsedSource["time_series"]); + } + if ("current_value" in $$parsedSource) { + $$parsedSource["current_value"] = $$createField1_0($$parsedSource["current_value"]); + } + if ("aggregate_value" in $$parsedSource) { + $$parsedSource["aggregate_value"] = $$createField2_0($$parsedSource["aggregate_value"]); + } + return new MetricResult($$parsedSource as Partial); + } +} + +/** + * MetricShape indicates the type of metric data. + */ +export enum MetricShape { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + ShapeCurrent = 0, + ShapeTimeseries = 1, + ShapeAggregate = 2, +}; + +/** + * MetricUnit represents the unit of a metric value. + */ +export enum MetricUnit { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + UnitNone = 0, + UnitBytes = 1, + UnitKB = 2, + UnitMB = 3, + UnitGB = 4, + UnitPercentage = 5, + UnitMillis = 6, + UnitSeconds = 7, + UnitCount = 8, + UnitOpsPerSec = 9, + UnitBytesPerSec = 10, + UnitMillicores = 11, + UnitCores = 12, +}; + +/** + * QueryRequest is the Go-side representation of a metric query. + */ +export class QueryRequest { + "resource_key": string; + "resource_id": string; + "resource_namespace": string; + "resource_data": { [_ in string]?: any }; + "metric_ids": string[]; + "shape": MetricShape; + "start_time": time$0.Time; + "end_time": time$0.Time; + "step": time$0.Duration; + "params": { [_ in string]?: string }; + + /** Creates a new QueryRequest instance. */ + constructor($$source: Partial = {}) { + if (!("resource_key" in $$source)) { + this["resource_key"] = ""; + } + if (!("resource_id" in $$source)) { + this["resource_id"] = ""; + } + if (!("resource_namespace" in $$source)) { + this["resource_namespace"] = ""; + } + if (!("resource_data" in $$source)) { + this["resource_data"] = {}; + } + if (!("metric_ids" in $$source)) { + this["metric_ids"] = []; + } + if (!("shape" in $$source)) { + this["shape"] = MetricShape.$zero; + } + if (!("start_time" in $$source)) { + this["start_time"] = null; + } + if (!("end_time" in $$source)) { + this["end_time"] = null; + } + if (!("step" in $$source)) { + this["step"] = time$0.Duration.$zero; + } + if (!("params" in $$source)) { + this["params"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new QueryRequest instance from a string or object. + */ + static createFrom($$source: any = {}): QueryRequest { + const $$createField3_0 = $$createType12; + const $$createField4_0 = $$createType13; + const $$createField9_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resource_data" in $$parsedSource) { + $$parsedSource["resource_data"] = $$createField3_0($$parsedSource["resource_data"]); + } + if ("metric_ids" in $$parsedSource) { + $$parsedSource["metric_ids"] = $$createField4_0($$parsedSource["metric_ids"]); + } + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField9_0($$parsedSource["params"]); + } + return new QueryRequest($$parsedSource as Partial); + } +} + +/** + * QueryResponse is the Go-side representation of a metric query response. + */ +export class QueryResponse { + "success": boolean; + "results": MetricResult[]; + "error": string; + + /** Creates a new QueryResponse instance. */ + constructor($$source: Partial = {}) { + if (!("success" in $$source)) { + this["success"] = false; + } + if (!("results" in $$source)) { + this["results"] = []; + } + if (!("error" in $$source)) { + this["error"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new QueryResponse instance from a string or object. + */ + static createFrom($$source: any = {}): QueryResponse { + const $$createField1_0 = $$createType15; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("results" in $$parsedSource) { + $$parsedSource["results"] = $$createField1_0($$parsedSource["results"]); + } + return new QueryResponse($$parsedSource as Partial); + } +} + +/** + * TimeSeries represents a series of data points for a metric. + */ +export class TimeSeries { + "metric_id": string; + "data_points": DataPoint[]; + "labels": { [_ in string]?: string }; + + /** Creates a new TimeSeries instance. */ + constructor($$source: Partial = {}) { + if (!("metric_id" in $$source)) { + this["metric_id"] = ""; + } + if (!("data_points" in $$source)) { + this["data_points"] = []; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new TimeSeries instance from a string or object. + */ + static createFrom($$source: any = {}): TimeSeries { + const $$createField1_0 = $$createType17; + const $$createField2_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("data_points" in $$parsedSource) { + $$parsedSource["data_points"] = $$createField1_0($$parsedSource["data_points"]); + } + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField2_0($$parsedSource["labels"]); + } + return new TimeSeries($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = $Create.Map($Create.Any, $Create.Any); +const $$createType1 = MetricDescriptor.createFrom; +const $$createType2 = $Create.Array($$createType1); +const $$createType3 = ColorRange.createFrom; +const $$createType4 = $Create.Array($$createType3); +const $$createType5 = $Create.Array($Create.Any); +const $$createType6 = TimeSeries.createFrom; +const $$createType7 = $Create.Nullable($$createType6); +const $$createType8 = CurrentValue.createFrom; +const $$createType9 = $Create.Nullable($$createType8); +const $$createType10 = AggregateValue.createFrom; +const $$createType11 = $Create.Nullable($$createType10); +const $$createType12 = $Create.Map($Create.Any, $Create.Any); +const $$createType13 = $Create.Array($Create.Any); +const $$createType14 = MetricResult.createFrom; +const $$createType15 = $Create.Array($$createType14); +const $$createType16 = DataPoint.createFrom; +const $$createType17 = $Create.Array($$createType16); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/index.ts new file mode 100644 index 00000000..4a9ce51c --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/index.ts @@ -0,0 +1,16 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + FindPortForwardSessionRequest, + PortForwardConnectionType, + PortForwardProtocol, + PortForwardSession, + PortForwardSessionEncryption, + PortForwardSessionOptions, + SessionState +} from "./models.js"; + +export type { + Connection +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models.ts new file mode 100644 index 00000000..a0c28dc0 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models.ts @@ -0,0 +1,239 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * Connection is implemented by PortForwardResourceConnection and + * PortForwardStaticConnection. The unexported method seals the interface. + */ +export type Connection = any; + +export class FindPortForwardSessionRequest { + "resource_id": string; + "connection_id": string; + + /** Creates a new FindPortForwardSessionRequest instance. */ + constructor($$source: Partial = {}) { + if (!("resource_id" in $$source)) { + this["resource_id"] = ""; + } + if (!("connection_id" in $$source)) { + this["connection_id"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FindPortForwardSessionRequest instance from a string or object. + */ + static createFrom($$source: any = {}): FindPortForwardSessionRequest { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new FindPortForwardSessionRequest($$parsedSource as Partial); + } +} + +export enum PortForwardConnectionType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + PortForwardConnectionTypeResource = "RESOURCE", + PortForwardConnectionTypeStatic = "STATIC", +}; + +export enum PortForwardProtocol { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + PortForwardProtocolTCP = "TCP", + PortForwardProtocolUDP = "UDP", +}; + +/** + * PortForwardSession represents a session between a forwarding target and the host. + */ +export class PortForwardSession { + "created_at": time$0.Time; + "updated_at": time$0.Time; + "connection": Connection; + "labels": { [_ in string]?: string }; + "id": string; + "protocol": PortForwardProtocol; + "state": SessionState; + "connection_type": PortForwardConnectionType; + "encryption": PortForwardSessionEncryption; + "local_port": number; + "remote_port": number; + + /** Creates a new PortForwardSession instance. */ + constructor($$source: Partial = {}) { + if (!("created_at" in $$source)) { + this["created_at"] = null; + } + if (!("updated_at" in $$source)) { + this["updated_at"] = null; + } + if (!("connection" in $$source)) { + this["connection"] = null; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("protocol" in $$source)) { + this["protocol"] = PortForwardProtocol.$zero; + } + if (!("state" in $$source)) { + this["state"] = SessionState.$zero; + } + if (!("connection_type" in $$source)) { + this["connection_type"] = PortForwardConnectionType.$zero; + } + if (!("encryption" in $$source)) { + this["encryption"] = (new PortForwardSessionEncryption()); + } + if (!("local_port" in $$source)) { + this["local_port"] = 0; + } + if (!("remote_port" in $$source)) { + this["remote_port"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PortForwardSession instance from a string or object. + */ + static createFrom($$source: any = {}): PortForwardSession { + const $$createField3_0 = $$createType0; + const $$createField8_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField3_0($$parsedSource["labels"]); + } + if ("encryption" in $$parsedSource) { + $$parsedSource["encryption"] = $$createField8_0($$parsedSource["encryption"]); + } + return new PortForwardSession($$parsedSource as Partial); + } +} + +export class PortForwardSessionEncryption { + "algorithm": string; + "key": string; + "enabled": boolean; + + /** Creates a new PortForwardSessionEncryption instance. */ + constructor($$source: Partial = {}) { + if (!("algorithm" in $$source)) { + this["algorithm"] = ""; + } + if (!("key" in $$source)) { + this["key"] = ""; + } + if (!("enabled" in $$source)) { + this["enabled"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PortForwardSessionEncryption instance from a string or object. + */ + static createFrom($$source: any = {}): PortForwardSessionEncryption { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PortForwardSessionEncryption($$parsedSource as Partial); + } +} + +export class PortForwardSessionOptions { + "connection": Connection; + "labels": { [_ in string]?: string }; + "params": { [_ in string]?: string }; + "protocol": PortForwardProtocol; + "connection_type": PortForwardConnectionType; + "encryption": PortForwardSessionEncryption; + "local_port": number; + "remote_port": number; + + /** Creates a new PortForwardSessionOptions instance. */ + constructor($$source: Partial = {}) { + if (!("connection" in $$source)) { + this["connection"] = null; + } + if (!("labels" in $$source)) { + this["labels"] = {}; + } + if (!("params" in $$source)) { + this["params"] = {}; + } + if (!("protocol" in $$source)) { + this["protocol"] = PortForwardProtocol.$zero; + } + if (!("connection_type" in $$source)) { + this["connection_type"] = PortForwardConnectionType.$zero; + } + if (!("encryption" in $$source)) { + this["encryption"] = (new PortForwardSessionEncryption()); + } + if (!("local_port" in $$source)) { + this["local_port"] = 0; + } + if (!("remote_port" in $$source)) { + this["remote_port"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PortForwardSessionOptions instance from a string or object. + */ + static createFrom($$source: any = {}): PortForwardSessionOptions { + const $$createField1_0 = $$createType0; + const $$createField2_0 = $$createType0; + const $$createField5_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labels" in $$parsedSource) { + $$parsedSource["labels"] = $$createField1_0($$parsedSource["labels"]); + } + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField2_0($$parsedSource["params"]); + } + if ("encryption" in $$parsedSource) { + $$parsedSource["encryption"] = $$createField5_0($$parsedSource["encryption"]); + } + return new PortForwardSessionOptions($$parsedSource as Partial); + } +} + +export enum SessionState { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + SessionStateActive = "ACTIVE", + SessionStatePaused = "PAUSED", + SessionStateStopped = "STOPPED", + SessionStateFailed = "FAILED", +}; + +// Private type creation functions +const $$createType0 = $Create.Map($Create.Any, $Create.Any); +const $$createType1 = PortForwardSessionEncryption.createFrom; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/index.ts new file mode 100644 index 00000000..8b430735 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/index.ts @@ -0,0 +1,57 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + ActionDescriptor, + ActionInput, + ActionResult, + ActionScope, + ColumnDefinition, + CreateInput, + CreateResult, + DeleteInput, + DeleteResult, + EdgeDirection, + EditorSchema, + EventSeverity, + FilterExpression, + FilterField, + FilterFieldType, + FilterLogic, + FilterOperator, + FilterPredicate, + FindInput, + FindResult, + GetInput, + GetResult, + HealthCondition, + HealthStatus, + ListInput, + ListResult, + OrderField, + PaginationParams, + RelationshipDescriptor, + RelationshipExtractor, + RelationshipType, + ResolvedRelationship, + ResourceCapabilities, + ResourceDefinition, + ResourceEvent, + ResourceGroup, + ResourceHealth, + ResourceLink, + ResourceMeta, + ResourceRef, + ScaleHint, + ScaleLevel, + UpdateInput, + UpdateResult, + WatchConnectionSummary, + WatchScope, + WatchState, + WatchStateEvent +} from "./models.js"; + +export type { + Schema +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models.ts new file mode 100644 index 00000000..be519d49 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models.ts @@ -0,0 +1,2178 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as json$0 from "../../../../../../encoding/json/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as time$0 from "../../../../../../time/models.js"; + +/** + * ActionDescriptor describes an available action on a resource type. + */ +export class ActionDescriptor { + "id": string; + "label": string; + "description": string; + "icon": string; + "scope": ActionScope; + "streaming": boolean; + + /** + * ParamsSchema describes the action's input parameters as a typed JSON Schema. + * Serialized to JSON Schema bytes for gRPC and MCP tool generators. + */ + "paramsSchema"?: Schema | null; + + /** + * OutputSchema describes the action's result structure as a typed JSON Schema. + * Serialized to JSON Schema bytes for gRPC and MCP tool generators. + */ + "outputSchema"?: Schema | null; + + /** + * Dangerous indicates this action has destructive side effects. + * AI agents should confirm before executing. + */ + "dangerous"?: boolean; + + /** Creates a new ActionDescriptor instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("scope" in $$source)) { + this["scope"] = ActionScope.$zero; + } + if (!("streaming" in $$source)) { + this["streaming"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActionDescriptor instance from a string or object. + */ + static createFrom($$source: any = {}): ActionDescriptor { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ActionDescriptor($$parsedSource as Partial); + } +} + +/** + * ActionInput contains the parameters for executing an action. + */ +export class ActionInput { + "id": string; + "namespace": string; + "params": { [_ in string]?: any }; + + /** Creates a new ActionInput instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("namespace" in $$source)) { + this["namespace"] = ""; + } + if (!("params" in $$source)) { + this["params"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActionInput instance from a string or object. + */ + static createFrom($$source: any = {}): ActionInput { + const $$createField2_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("params" in $$parsedSource) { + $$parsedSource["params"] = $$createField2_0($$parsedSource["params"]); + } + return new ActionInput($$parsedSource as Partial); + } +} + +/** + * ActionResult contains the result of executing an action. + */ +export class ActionResult { + "success": boolean; + "data": { [_ in string]?: any }; + "message": string; + + /** Creates a new ActionResult instance. */ + constructor($$source: Partial = {}) { + if (!("success" in $$source)) { + this["success"] = false; + } + if (!("data" in $$source)) { + this["data"] = {}; + } + if (!("message" in $$source)) { + this["message"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ActionResult instance from a string or object. + */ + static createFrom($$source: any = {}): ActionResult { + const $$createField1_0 = $$createType0; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("data" in $$parsedSource) { + $$parsedSource["data"] = $$createField1_0($$parsedSource["data"]); + } + return new ActionResult($$parsedSource as Partial); + } +} + +/** + * ActionScope defines whether an action operates on a specific resource + * instance or on the resource type as a whole. + */ +export enum ActionScope { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + ActionScopeInstance = "instance", + ActionScopeType = "type", +}; + +/** + * ColumnDefinition describes a single table column for resource display. + */ +export class ColumnDefinition { + /** + * ID is the unique identifier for this column. + */ + "id": string; + + /** + * Header is the display header text. + */ + "header": string; + + /** + * Accessors is a comma-separated list of JSON path accessors. + */ + "accessor": string; + + /** + * AccessorPriority controls which value to return when multiple + * accessors match. Values: "ALL", "FIRST", "LAST". + */ + "accessorPriority"?: string; + + /** + * ColorMap maps cell values to color variants. + */ + "colorMap"?: { [_ in string]?: string }; + + /** + * Color is the default color variant for the cell. + */ + "color"?: string; + + /** + * Alignment is the column alignment: "LEFT", "CENTER", "RIGHT". + */ + "align"?: string; + + /** + * Hidden controls whether the column is visible by default. + */ + "hidden"?: boolean; + + /** + * Width is the column width in pixels. 0 means auto-size. + */ + "width"?: number; + + /** + * Formatter is the value formatter: "NONE", "BYTES", "DURATION", "AGE", etc. + */ + "formatter"?: string; + + /** + * Component is the cell renderer component name. + */ + "component"?: string; + + /** + * ComponentParams are parameters passed to the cell component. + */ + "componentParams"?: any; + + /** + * ResourceLink creates a link to another resource. + */ + "resourceLink"?: ResourceLink | null; + + /** + * ValueMap maps values via regex replacement. + */ + "valueMap"?: { [_ in string]?: string }; + + /** Creates a new ColumnDefinition instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("header" in $$source)) { + this["header"] = ""; + } + if (!("accessor" in $$source)) { + this["accessor"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ColumnDefinition instance from a string or object. + */ + static createFrom($$source: any = {}): ColumnDefinition { + const $$createField4_0 = $$createType1; + const $$createField12_0 = $$createType3; + const $$createField13_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("colorMap" in $$parsedSource) { + $$parsedSource["colorMap"] = $$createField4_0($$parsedSource["colorMap"]); + } + if ("resourceLink" in $$parsedSource) { + $$parsedSource["resourceLink"] = $$createField12_0($$parsedSource["resourceLink"]); + } + if ("valueMap" in $$parsedSource) { + $$parsedSource["valueMap"] = $$createField13_0($$parsedSource["valueMap"]); + } + return new ColumnDefinition($$parsedSource as Partial); + } +} + +/** + * CreateInput is the input to the Create operation. + */ +export class CreateInput { + /** + * Input is the resource data to create. + */ + "input": json$0.RawMessage; + + /** + * Namespace is an optional namespace for the new resource. + */ + "namespace": string; + + /** Creates a new CreateInput instance. */ + constructor($$source: Partial = {}) { + if (!("input" in $$source)) { + this["input"] = null; + } + if (!("namespace" in $$source)) { + this["namespace"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new CreateInput instance from a string or object. + */ + static createFrom($$source: any = {}): CreateInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new CreateInput($$parsedSource as Partial); + } +} + +/** + * CreateResult is the result of a Create operation. + */ +export class CreateResult { + /** + * Result is the created resource as pre-serialized JSON. + */ + "result": json$0.RawMessage; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** Creates a new CreateResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = null; + } + if (!("success" in $$source)) { + this["success"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new CreateResult instance from a string or object. + */ + static createFrom($$source: any = {}): CreateResult { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new CreateResult($$parsedSource as Partial); + } +} + +/** + * DeleteInput is the input to the Delete operation. + */ +export class DeleteInput { + /** + * ID is the unique identifier of the resource to delete. + */ + "id": string; + + /** + * Namespace is an optional namespace identifier. + */ + "namespace": string; + + /** + * GracePeriodSeconds is an optional grace period before deletion. + * nil means use the default. + */ + "gracePeriodSeconds"?: number | null; + + /** Creates a new DeleteInput instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("namespace" in $$source)) { + this["namespace"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DeleteInput instance from a string or object. + */ + static createFrom($$source: any = {}): DeleteInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DeleteInput($$parsedSource as Partial); + } +} + +/** + * DeleteResult is the result of a Delete operation. + */ +export class DeleteResult { + /** + * Result is the deleted resource as pre-serialized JSON (if available). + */ + "result": json$0.RawMessage; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** Creates a new DeleteResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = null; + } + if (!("success" in $$source)) { + this["success"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new DeleteResult instance from a string or object. + */ + static createFrom($$source: any = {}): DeleteResult { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new DeleteResult($$parsedSource as Partial); + } +} + +/** + * EdgeDirection controls whether an extracted edge points from the declaring + * resource to the target (outgoing) or from the target back to the declaring + * resource (incoming). Incoming is used for ownership edges where the child + * declares its parent (e.g., Pod ownerRef → ReplicaSet). + */ +export enum EdgeDirection { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * EdgeOutgoing is the default: declaring resource → extracted target. + */ + EdgeOutgoing = "", + + /** + * EdgeIncoming reverses the edge: extracted target → declaring resource. + */ + EdgeIncoming = "incoming", +}; + +/** + * EditorSchema provides schema information for Monaco editor validation. + */ +export class EditorSchema { + "resourceKey": string; + "fileMatch": string; + "uri": string; + "url"?: string; + "content"?: string; + "language": string; + + /** Creates a new EditorSchema instance. */ + constructor($$source: Partial = {}) { + if (!("resourceKey" in $$source)) { + this["resourceKey"] = ""; + } + if (!("fileMatch" in $$source)) { + this["fileMatch"] = ""; + } + if (!("uri" in $$source)) { + this["uri"] = ""; + } + if (!("language" in $$source)) { + this["language"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new EditorSchema instance from a string or object. + */ + static createFrom($$source: any = {}): EditorSchema { + const $$createField4_0 = $Create.ByteSlice; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("content" in $$parsedSource) { + $$parsedSource["content"] = $$createField4_0($$parsedSource["content"]); + } + return new EditorSchema($$parsedSource as Partial); + } +} + +/** + * EventSeverity classifies diagnostic events. + */ +export enum EventSeverity { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + SeverityNormal = "normal", + SeverityWarning = "warning", + SeverityError = "error", +}; + +/** + * FilterExpression combines predicates with a logical operator. + * Supports one level of nesting (AND of ORs, or OR of ANDs). + */ +export class FilterExpression { + "logic"?: FilterLogic; + "predicates"?: FilterPredicate[]; + "groups"?: FilterExpression[]; + + /** Creates a new FilterExpression instance. */ + constructor($$source: Partial = {}) { + + Object.assign(this, $$source); + } + + /** + * Creates a new FilterExpression instance from a string or object. + */ + static createFrom($$source: any = {}): FilterExpression { + const $$createField1_0 = $$createType5; + const $$createField2_0 = $$createType7; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("predicates" in $$parsedSource) { + $$parsedSource["predicates"] = $$createField1_0($$parsedSource["predicates"]); + } + if ("groups" in $$parsedSource) { + $$parsedSource["groups"] = $$createField2_0($$parsedSource["groups"]); + } + return new FilterExpression($$parsedSource as Partial); + } +} + +/** + * FilterField declares a field that can be used in filter predicates. + * This is the introspection/discovery type for AI agents and MCP tool generators. + */ +export class FilterField { + /** + * Path is the dot-separated field path (e.g., "metadata.name", "status.phase"). + */ + "path": string; + + /** + * DisplayName is the human-readable name for UI and MCP tool descriptions. + */ + "displayName": string; + + /** + * Description explains what this field represents. + */ + "description": string; + + /** + * Type declares the value type. + */ + "type": FilterFieldType; + + /** + * Operators lists valid comparison operators for this field. + * If empty, defaults to [OpEqual, OpNotEqual]. + */ + "operators": FilterOperator[]; + + /** + * AllowedValues is the fixed set of valid values (only for FilterFieldEnum). + */ + "allowedValues"?: string[]; + + /** + * Required indicates this field must be provided in filter queries. + */ + "required"?: boolean; + + /** Creates a new FilterField instance. */ + constructor($$source: Partial = {}) { + if (!("path" in $$source)) { + this["path"] = ""; + } + if (!("displayName" in $$source)) { + this["displayName"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("type" in $$source)) { + this["type"] = FilterFieldType.$zero; + } + if (!("operators" in $$source)) { + this["operators"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FilterField instance from a string or object. + */ + static createFrom($$source: any = {}): FilterField { + const $$createField4_0 = $$createType8; + const $$createField5_0 = $$createType9; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("operators" in $$parsedSource) { + $$parsedSource["operators"] = $$createField4_0($$parsedSource["operators"]); + } + if ("allowedValues" in $$parsedSource) { + $$parsedSource["allowedValues"] = $$createField5_0($$parsedSource["allowedValues"]); + } + return new FilterField($$parsedSource as Partial); + } +} + +/** + * FilterFieldType declares the value type for a filterable field. + */ +export enum FilterFieldType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + FilterFieldString = "string", + FilterFieldInt = "integer", + FilterFieldFloat = "number", + FilterFieldBool = "boolean", + FilterFieldTime = "datetime", + FilterFieldEnum = "enum", + FilterFieldMap = "map", +}; + +/** + * FilterLogic is the logical operator for combining predicates. + */ +export enum FilterLogic { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + FilterAnd = "and", + FilterOr = "or", +}; + +/** + * FilterOperator is a comparison operator for filter predicates. + */ +export enum FilterOperator { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * Equality. + */ + OpEqual = "eq", + OpNotEqual = "neq", + + /** + * Comparison (numeric, time). + */ + OpGreaterThan = "gt", + OpGreaterOrEqual = "gte", + OpLessThan = "lt", + OpLessOrEqual = "lte", + + /** + * String matching. + */ + OpContains = "contains", + OpPrefix = "prefix", + OpSuffix = "suffix", + OpRegex = "regex", + + /** + * Set membership. + */ + OpIn = "in", + OpNotIn = "notin", + + /** + * Existence. + */ + OpExists = "exists", + OpNotExists = "notexists", + + /** + * Map/label-specific. + */ + OpHasKey = "haskey", +}; + +/** + * FilterPredicate is a single condition in a query. + */ +export class FilterPredicate { + /** + * Field is the filter field path (must match a FilterField.Path). + */ + "field": string; + + /** + * Operator is the comparison operator. + */ + "operator": FilterOperator; + + /** + * Value is the comparison value. Type depends on field and operator: + * - OpIn/OpNotIn: []string + * - OpExists/OpNotExists: ignored (nil) + * - All others: scalar matching the field's FilterFieldType + */ + "value"?: any; + + /** Creates a new FilterPredicate instance. */ + constructor($$source: Partial = {}) { + if (!("field" in $$source)) { + this["field"] = ""; + } + if (!("operator" in $$source)) { + this["operator"] = FilterOperator.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FilterPredicate instance from a string or object. + */ + static createFrom($$source: any = {}): FilterPredicate { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new FilterPredicate($$parsedSource as Partial); + } +} + +/** + * FindInput is the input to the Find operation. + */ +export class FindInput { + /** + * Filters is a typed filter expression replacing the old untyped Conditions. + */ + "filters"?: FilterExpression | null; + + /** + * TextQuery is a free-text search string. + */ + "textQuery"?: string; + + /** + * Namespaces limits the search scope. + */ + "namespaces": string[]; + + /** + * Order specifies multi-field ordering. + */ + "order": OrderField[]; + + /** + * Pagination controls pagination. + */ + "pagination": PaginationParams; + + /** Creates a new FindInput instance. */ + constructor($$source: Partial = {}) { + if (!("namespaces" in $$source)) { + this["namespaces"] = []; + } + if (!("order" in $$source)) { + this["order"] = []; + } + if (!("pagination" in $$source)) { + this["pagination"] = (new PaginationParams()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FindInput instance from a string or object. + */ + static createFrom($$source: any = {}): FindInput { + const $$createField0_0 = $$createType10; + const $$createField2_0 = $$createType9; + const $$createField3_0 = $$createType12; + const $$createField4_0 = $$createType13; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("filters" in $$parsedSource) { + $$parsedSource["filters"] = $$createField0_0($$parsedSource["filters"]); + } + if ("namespaces" in $$parsedSource) { + $$parsedSource["namespaces"] = $$createField2_0($$parsedSource["namespaces"]); + } + if ("order" in $$parsedSource) { + $$parsedSource["order"] = $$createField3_0($$parsedSource["order"]); + } + if ("pagination" in $$parsedSource) { + $$parsedSource["pagination"] = $$createField4_0($$parsedSource["pagination"]); + } + return new FindInput($$parsedSource as Partial); + } +} + +/** + * FindResult is the result of a Find operation. + */ +export class FindResult { + /** + * Result is the list of matching resources as pre-serialized JSON. + */ + "result": json$0.RawMessage[]; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** + * TotalCount is the total number of matching resources. + * -1 if unknown. + */ + "totalCount": number; + + /** + * NextCursor is the continuation token for cursor-based pagination. + */ + "nextCursor"?: string; + + /** Creates a new FindResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = []; + } + if (!("success" in $$source)) { + this["success"] = false; + } + if (!("totalCount" in $$source)) { + this["totalCount"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new FindResult instance from a string or object. + */ + static createFrom($$source: any = {}): FindResult { + const $$createField0_0 = $$createType14; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("result" in $$parsedSource) { + $$parsedSource["result"] = $$createField0_0($$parsedSource["result"]); + } + return new FindResult($$parsedSource as Partial); + } +} + +/** + * GetInput is the input to the Get operation. + */ +export class GetInput { + /** + * ID is the unique identifier of the resource. + */ + "id": string; + + /** + * Namespace is an optional namespace identifier. + */ + "namespace": string; + + /** Creates a new GetInput instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("namespace" in $$source)) { + this["namespace"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetInput instance from a string or object. + */ + static createFrom($$source: any = {}): GetInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetInput($$parsedSource as Partial); + } +} + +/** + * GetResult is the result of a Get operation. + */ +export class GetResult { + /** + * Result is the resource data as pre-serialized JSON. + */ + "result": json$0.RawMessage; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** Creates a new GetResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = null; + } + if (!("success" in $$source)) { + this["success"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new GetResult instance from a string or object. + */ + static createFrom($$source: any = {}): GetResult { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new GetResult($$parsedSource as Partial); + } +} + +/** + * HealthCondition represents a single condition (Ready, Scheduled, etc.). + */ +export class HealthCondition { + "type": string; + "status": string; + "reason"?: string; + "message"?: string; + "lastProbeTime"?: time$0.Time | null; + "lastTransitionTime"?: time$0.Time | null; + + /** Creates a new HealthCondition instance. */ + constructor($$source: Partial = {}) { + if (!("type" in $$source)) { + this["type"] = ""; + } + if (!("status" in $$source)) { + this["status"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new HealthCondition instance from a string or object. + */ + static createFrom($$source: any = {}): HealthCondition { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new HealthCondition($$parsedSource as Partial); + } +} + +/** + * HealthStatus represents the normalized health of a resource. + */ +export enum HealthStatus { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + HealthHealthy = "healthy", + HealthDegraded = "degraded", + HealthUnhealthy = "unhealthy", + HealthPending = "pending", + HealthUnknown = "unknown", +}; + +/** + * ListInput is the input to the List operation. + */ +export class ListInput { + /** + * Namespaces limits listing to these namespaces. + * Empty means all namespaces. + */ + "namespaces": string[]; + + /** + * Order specifies multi-field ordering. + */ + "order": OrderField[]; + + /** + * Pagination controls pagination. + */ + "pagination": PaginationParams; + + /** Creates a new ListInput instance. */ + constructor($$source: Partial = {}) { + if (!("namespaces" in $$source)) { + this["namespaces"] = []; + } + if (!("order" in $$source)) { + this["order"] = []; + } + if (!("pagination" in $$source)) { + this["pagination"] = (new PaginationParams()); + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ListInput instance from a string or object. + */ + static createFrom($$source: any = {}): ListInput { + const $$createField0_0 = $$createType9; + const $$createField1_0 = $$createType12; + const $$createField2_0 = $$createType13; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("namespaces" in $$parsedSource) { + $$parsedSource["namespaces"] = $$createField0_0($$parsedSource["namespaces"]); + } + if ("order" in $$parsedSource) { + $$parsedSource["order"] = $$createField1_0($$parsedSource["order"]); + } + if ("pagination" in $$parsedSource) { + $$parsedSource["pagination"] = $$createField2_0($$parsedSource["pagination"]); + } + return new ListInput($$parsedSource as Partial); + } +} + +/** + * ListResult is the result of a List operation. + */ +export class ListResult { + /** + * Result is the list of resources as pre-serialized JSON. + */ + "result": json$0.RawMessage[]; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** + * TotalCount is the total number of resources (for pagination). + * -1 if unknown. + */ + "totalCount": number; + + /** + * NextCursor is the continuation token for cursor-based pagination. + */ + "nextCursor"?: string; + + /** Creates a new ListResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = []; + } + if (!("success" in $$source)) { + this["success"] = false; + } + if (!("totalCount" in $$source)) { + this["totalCount"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ListResult instance from a string or object. + */ + static createFrom($$source: any = {}): ListResult { + const $$createField0_0 = $$createType14; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("result" in $$parsedSource) { + $$parsedSource["result"] = $$createField0_0($$parsedSource["result"]); + } + return new ListResult($$parsedSource as Partial); + } +} + +/** + * OrderField specifies a single field in a multi-field ordering clause. + */ +export class OrderField { + /** + * Field is the dot-separated path to the field to order by. + */ + "field": string; + + /** + * Descending controls sort direction. false = ascending (default). + */ + "descending": boolean; + + /** Creates a new OrderField instance. */ + constructor($$source: Partial = {}) { + if (!("field" in $$source)) { + this["field"] = ""; + } + if (!("descending" in $$source)) { + this["descending"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new OrderField instance from a string or object. + */ + static createFrom($$source: any = {}): OrderField { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new OrderField($$parsedSource as Partial); + } +} + +/** + * PaginationParams controls pagination for List and Find operations. + */ +export class PaginationParams { + /** + * Page is the 1-based page number (for page-based pagination). + */ + "page": number; + + /** + * PageSize is the maximum number of results per page. + * 0 means return all results. + */ + "pageSize": number; + + /** + * Cursor is the continuation token from a previous response + * (for cursor-based pagination). Mutually exclusive with Page. + */ + "cursor"?: string; + + /** Creates a new PaginationParams instance. */ + constructor($$source: Partial = {}) { + if (!("page" in $$source)) { + this["page"] = 0; + } + if (!("pageSize" in $$source)) { + this["pageSize"] = 0; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new PaginationParams instance from a string or object. + */ + static createFrom($$source: any = {}): PaginationParams { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new PaginationParams($$parsedSource as Partial); + } +} + +/** + * RelationshipDescriptor declares a relationship from one resource type to another. + */ +export class RelationshipDescriptor { + "type": RelationshipType; + "targetResourceKey": string; + "label": string; + "inverseLabel"?: string; + "cardinality"?: string; + "direction"?: EdgeDirection; + "extractor"?: RelationshipExtractor | null; + + /** + * TargetNamespaced is a tri-state flag: nil = default to namespaced (common case), + * true = explicitly namespaced, false = cluster-scoped target (e.g., Node, PV, + * StorageClass). Pointer type distinguishes "unspecified" from explicit values; + * callers must check for nil before dereferencing. + */ + "targetNamespaced"?: boolean | null; + + /** Creates a new RelationshipDescriptor instance. */ + constructor($$source: Partial = {}) { + if (!("type" in $$source)) { + this["type"] = RelationshipType.$zero; + } + if (!("targetResourceKey" in $$source)) { + this["targetResourceKey"] = ""; + } + if (!("label" in $$source)) { + this["label"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new RelationshipDescriptor instance from a string or object. + */ + static createFrom($$source: any = {}): RelationshipDescriptor { + const $$createField6_0 = $$createType16; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("extractor" in $$parsedSource) { + $$parsedSource["extractor"] = $$createField6_0($$parsedSource["extractor"]); + } + return new RelationshipDescriptor($$parsedSource as Partial); + } +} + +/** + * RelationshipExtractor defines how to find related resource IDs from source data. + */ +export class RelationshipExtractor { + "method": string; + "fieldPath"?: string; + "labelSelector"?: { [_ in string]?: string }; + + /** Creates a new RelationshipExtractor instance. */ + constructor($$source: Partial = {}) { + if (!("method" in $$source)) { + this["method"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new RelationshipExtractor instance from a string or object. + */ + static createFrom($$source: any = {}): RelationshipExtractor { + const $$createField2_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("labelSelector" in $$parsedSource) { + $$parsedSource["labelSelector"] = $$createField2_0($$parsedSource["labelSelector"]); + } + return new RelationshipExtractor($$parsedSource as Partial); + } +} + +/** + * RelationshipType classifies the kind of relationship between resources. + */ +export enum RelationshipType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + RelOwns = "owns", + RelRunsOn = "runs_on", + RelUses = "uses", + RelExposes = "exposes", + RelManages = "manages", + RelMemberOf = "member_of", + RelSelects = "selects", +}; + +/** + * ResolvedRelationship holds actual relationship instances for a resource. + */ +export class ResolvedRelationship { + "descriptor": RelationshipDescriptor; + "targets": ResourceRef[]; + + /** Creates a new ResolvedRelationship instance. */ + constructor($$source: Partial = {}) { + if (!("descriptor" in $$source)) { + this["descriptor"] = (new RelationshipDescriptor()); + } + if (!("targets" in $$source)) { + this["targets"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResolvedRelationship instance from a string or object. + */ + static createFrom($$source: any = {}): ResolvedRelationship { + const $$createField0_0 = $$createType17; + const $$createField1_0 = $$createType19; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("descriptor" in $$parsedSource) { + $$parsedSource["descriptor"] = $$createField0_0($$parsedSource["descriptor"]); + } + if ("targets" in $$parsedSource) { + $$parsedSource["targets"] = $$createField1_0($$parsedSource["targets"]); + } + return new ResolvedRelationship($$parsedSource as Partial); + } +} + +/** + * ResourceCapabilities describes what operations and features a resource + * type supports. Auto-derived by the SDK from type assertions on registered + * Resourcers at registration time. + */ +export class ResourceCapabilities { + /** + * CRUD flags. + */ + "canGet": boolean; + "canList": boolean; + "canFind": boolean; + "canCreate": boolean; + "canUpdate": boolean; + "canDelete": boolean; + + /** + * Extended capabilities. + */ + "watchable": boolean; + "filterable": boolean; + "searchable": boolean; + "hasActions": boolean; + "hasSchema": boolean; + "namespaceScoped": boolean; + "hasRelationships": boolean; + "hasHealth": boolean; + "hasEvents": boolean; + + /** + * ScaleHint indicates expected cardinality. + */ + "scaleHint"?: ScaleHint | null; + + /** Creates a new ResourceCapabilities instance. */ + constructor($$source: Partial = {}) { + if (!("canGet" in $$source)) { + this["canGet"] = false; + } + if (!("canList" in $$source)) { + this["canList"] = false; + } + if (!("canFind" in $$source)) { + this["canFind"] = false; + } + if (!("canCreate" in $$source)) { + this["canCreate"] = false; + } + if (!("canUpdate" in $$source)) { + this["canUpdate"] = false; + } + if (!("canDelete" in $$source)) { + this["canDelete"] = false; + } + if (!("watchable" in $$source)) { + this["watchable"] = false; + } + if (!("filterable" in $$source)) { + this["filterable"] = false; + } + if (!("searchable" in $$source)) { + this["searchable"] = false; + } + if (!("hasActions" in $$source)) { + this["hasActions"] = false; + } + if (!("hasSchema" in $$source)) { + this["hasSchema"] = false; + } + if (!("namespaceScoped" in $$source)) { + this["namespaceScoped"] = false; + } + if (!("hasRelationships" in $$source)) { + this["hasRelationships"] = false; + } + if (!("hasHealth" in $$source)) { + this["hasHealth"] = false; + } + if (!("hasEvents" in $$source)) { + this["hasEvents"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceCapabilities instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceCapabilities { + const $$createField15_0 = $$createType21; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("scaleHint" in $$parsedSource) { + $$parsedSource["scaleHint"] = $$createField15_0($$parsedSource["scaleHint"]); + } + return new ResourceCapabilities($$parsedSource as Partial); + } +} + +/** + * ResourceDefinition describes the table rendering configuration for a resource type. + */ +export class ResourceDefinition { + /** + * IDAccessor is the JSON path to extract the resource ID. + */ + "id_accessor": string; + + /** + * NamespaceAccessor is the JSON path to extract the namespace. + */ + "namespace_accessor": string; + + /** + * MemoizerAccessor is the JSON path to extract a memoization key. + */ + "memoizer_accessor": string; + + /** + * ColumnDefs defines the table columns for this resource type. + */ + "columnDefs": ColumnDefinition[]; + + /** Creates a new ResourceDefinition instance. */ + constructor($$source: Partial = {}) { + if (!("id_accessor" in $$source)) { + this["id_accessor"] = ""; + } + if (!("namespace_accessor" in $$source)) { + this["namespace_accessor"] = ""; + } + if (!("memoizer_accessor" in $$source)) { + this["memoizer_accessor"] = ""; + } + if (!("columnDefs" in $$source)) { + this["columnDefs"] = []; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceDefinition instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceDefinition { + const $$createField3_0 = $$createType23; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("columnDefs" in $$parsedSource) { + $$parsedSource["columnDefs"] = $$createField3_0($$parsedSource["columnDefs"]); + } + return new ResourceDefinition($$parsedSource as Partial); + } +} + +/** + * ResourceEvent is a diagnostic event associated with a resource. + */ +export class ResourceEvent { + "type": EventSeverity; + "reason": string; + "message": string; + "source"?: string; + "count"?: number; + "firstSeen": time$0.Time; + "lastSeen": time$0.Time; + + /** Creates a new ResourceEvent instance. */ + constructor($$source: Partial = {}) { + if (!("type" in $$source)) { + this["type"] = EventSeverity.$zero; + } + if (!("reason" in $$source)) { + this["reason"] = ""; + } + if (!("message" in $$source)) { + this["message"] = ""; + } + if (!("firstSeen" in $$source)) { + this["firstSeen"] = null; + } + if (!("lastSeen" in $$source)) { + this["lastSeen"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceEvent instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceEvent { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ResourceEvent($$parsedSource as Partial); + } +} + +/** + * ResourceGroup is a categorization of resources within a plugin. + */ +export class ResourceGroup { + /** + * ID is the unique identifier of the resource group. + */ + "id": string; + + /** + * Name is the display name of the resource group. + */ + "name": string; + + /** + * Description is a human-readable description. + */ + "description": string; + + /** + * Icon is an optional icon for the resource group. + */ + "icon": string; + + /** + * Resources is a map of resource versions to the resources in that version. + */ + "resources": { [_ in string]?: ResourceMeta[] }; + + /** Creates a new ResourceGroup instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("name" in $$source)) { + this["name"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("resources" in $$source)) { + this["resources"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceGroup instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceGroup { + const $$createField4_0 = $$createType26; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resources" in $$parsedSource) { + $$parsedSource["resources"] = $$createField4_0($$parsedSource["resources"]); + } + return new ResourceGroup($$parsedSource as Partial); + } +} + +/** + * ResourceHealth is a normalized health assessment for a resource. + */ +export class ResourceHealth { + "status": HealthStatus; + "reason"?: string; + "message"?: string; + "since"?: time$0.Time | null; + "conditions"?: HealthCondition[]; + + /** Creates a new ResourceHealth instance. */ + constructor($$source: Partial = {}) { + if (!("status" in $$source)) { + this["status"] = HealthStatus.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceHealth instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceHealth { + const $$createField4_0 = $$createType28; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("conditions" in $$parsedSource) { + $$parsedSource["conditions"] = $$createField4_0($$parsedSource["conditions"]); + } + return new ResourceHealth($$parsedSource as Partial); + } +} + +/** + * ResourceLink creates links to other resources from table cells. + */ +export class ResourceLink { + "idAccessor": string; + "namespaceAccessor": string; + "namespaced": boolean; + "resourceKey": string; + "keyAccessor": string; + "keyMap": { [_ in string]?: string }; + "detailExtractors": { [_ in string]?: string }; + "displayId": boolean; + + /** Creates a new ResourceLink instance. */ + constructor($$source: Partial = {}) { + if (!("idAccessor" in $$source)) { + this["idAccessor"] = ""; + } + if (!("namespaceAccessor" in $$source)) { + this["namespaceAccessor"] = ""; + } + if (!("namespaced" in $$source)) { + this["namespaced"] = false; + } + if (!("resourceKey" in $$source)) { + this["resourceKey"] = ""; + } + if (!("keyAccessor" in $$source)) { + this["keyAccessor"] = ""; + } + if (!("keyMap" in $$source)) { + this["keyMap"] = {}; + } + if (!("detailExtractors" in $$source)) { + this["detailExtractors"] = {}; + } + if (!("displayId" in $$source)) { + this["displayId"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceLink instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceLink { + const $$createField5_0 = $$createType1; + const $$createField6_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("keyMap" in $$parsedSource) { + $$parsedSource["keyMap"] = $$createField5_0($$parsedSource["keyMap"]); + } + if ("detailExtractors" in $$parsedSource) { + $$parsedSource["detailExtractors"] = $$createField6_0($$parsedSource["detailExtractors"]); + } + return new ResourceLink($$parsedSource as Partial); + } +} + +/** + * ResourceMeta contains information about the categorization of a resource. + * Used to identify resource types across plugins and route operations to the + * correct Resourcer implementation. + */ +export class ResourceMeta { + /** + * Group is the group of the resource (e.g., "core", "apps", "ec2"). + */ + "group": string; + + /** + * Version is the version of the resource (e.g., "v1", "v1beta1"). + */ + "version": string; + + /** + * Kind is the kind of the resource (e.g., "Pod", "Deployment", "EC2Instance"). + */ + "kind": string; + + /** + * Label is a human-readable label. Defaults to Kind if not provided. + */ + "label": string; + + /** + * Icon is an optional icon (icon name, data URI, or URL). + */ + "icon": string; + + /** + * Description is a human-readable description of the resource. + */ + "description": string; + + /** + * Category is the category for grouping (e.g., "Workloads", "Networking"). + * Defaults to "Uncategorized" if empty. + */ + "category": string; + + /** Creates a new ResourceMeta instance. */ + constructor($$source: Partial = {}) { + if (!("group" in $$source)) { + this["group"] = ""; + } + if (!("version" in $$source)) { + this["version"] = ""; + } + if (!("kind" in $$source)) { + this["kind"] = ""; + } + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("category" in $$source)) { + this["category"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceMeta instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceMeta { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ResourceMeta($$parsedSource as Partial); + } +} + +/** + * ResourceRef is a reference to a specific resource instance. + */ +export class ResourceRef { + "pluginId"?: string; + "connectionId": string; + "resourceKey": string; + "id": string; + "namespace"?: string; + "displayName"?: string; + + /** Creates a new ResourceRef instance. */ + constructor($$source: Partial = {}) { + if (!("connectionId" in $$source)) { + this["connectionId"] = ""; + } + if (!("resourceKey" in $$source)) { + this["resourceKey"] = ""; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ResourceRef instance from a string or object. + */ + static createFrom($$source: any = {}): ResourceRef { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ResourceRef($$parsedSource as Partial); + } +} + +/** + * ScaleHint indicates the expected cardinality of a resource type. + */ +export class ScaleHint { + /** + * Level is the expected scale: "few", "moderate", "many". + */ + "level": ScaleLevel; + + /** + * ExpectedCount is the approximate expected count (optional). + */ + "expectedCount"?: number; + + /** + * DefaultPageSize is the recommended page size for this resource. + */ + "defaultPageSize"?: number; + + /** Creates a new ScaleHint instance. */ + constructor($$source: Partial = {}) { + if (!("level" in $$source)) { + this["level"] = ScaleLevel.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new ScaleHint instance from a string or object. + */ + static createFrom($$source: any = {}): ScaleHint { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new ScaleHint($$parsedSource as Partial); + } +} + +/** + * ScaleLevel represents expected resource cardinality. + */ +export enum ScaleLevel { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * ScaleFew means <100 resources (list-all is fine). + */ + ScaleFew = "few", + + /** + * ScaleModerate means 100-10K resources (pagination recommended). + */ + ScaleModerate = "moderate", + + /** + * ScaleMany means 10K+ resources (filter-first approach required). + */ + ScaleMany = "many", +}; + +/** + * Schema describes the shape of an action's parameters or output. + * Always serializes as a JSON Schema object with "type":"object". + */ +export type Schema = any; + +/** + * UpdateInput is the input to the Update operation. + */ +export class UpdateInput { + /** + * Input is the updated resource data. + */ + "input": json$0.RawMessage; + + /** + * ID is the unique identifier of the resource to update. + */ + "id": string; + + /** + * Namespace is an optional namespace identifier. + */ + "namespace": string; + + /** Creates a new UpdateInput instance. */ + constructor($$source: Partial = {}) { + if (!("input" in $$source)) { + this["input"] = null; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("namespace" in $$source)) { + this["namespace"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateInput instance from a string or object. + */ + static createFrom($$source: any = {}): UpdateInput { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateInput($$parsedSource as Partial); + } +} + +/** + * UpdateResult is the result of an Update operation. + */ +export class UpdateResult { + /** + * Result is the updated resource as pre-serialized JSON. + */ + "result": json$0.RawMessage; + + /** + * Success indicates whether the operation succeeded. + */ + "success": boolean; + + /** Creates a new UpdateResult instance. */ + constructor($$source: Partial = {}) { + if (!("result" in $$source)) { + this["result"] = null; + } + if (!("success" in $$source)) { + this["success"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new UpdateResult instance from a string or object. + */ + static createFrom($$source: any = {}): UpdateResult { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new UpdateResult($$parsedSource as Partial); + } +} + +/** + * WatchConnectionSummary provides a snapshot of all watch states for a connection. + */ +export class WatchConnectionSummary { + "connectionId": string; + "resources": { [_ in string]?: WatchState }; + "resourceCounts": { [_ in string]?: number }; + "scope"?: WatchScope | null; + + /** Creates a new WatchConnectionSummary instance. */ + constructor($$source: Partial = {}) { + if (!("connectionId" in $$source)) { + this["connectionId"] = ""; + } + if (!("resources" in $$source)) { + this["resources"] = {}; + } + if (!("resourceCounts" in $$source)) { + this["resourceCounts"] = {}; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new WatchConnectionSummary instance from a string or object. + */ + static createFrom($$source: any = {}): WatchConnectionSummary { + const $$createField1_0 = $$createType29; + const $$createField2_0 = $$createType30; + const $$createField3_0 = $$createType32; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("resources" in $$parsedSource) { + $$parsedSource["resources"] = $$createField1_0($$parsedSource["resources"]); + } + if ("resourceCounts" in $$parsedSource) { + $$parsedSource["resourceCounts"] = $$createField2_0($$parsedSource["resourceCounts"]); + } + if ("scope" in $$parsedSource) { + $$parsedSource["scope"] = $$createField3_0($$parsedSource["scope"]); + } + return new WatchConnectionSummary($$parsedSource as Partial); + } +} + +/** + * WatchScope configures the scope/partitioning of a Watch invocation. + * Passed via context so the Watcher[ClientT] interface doesn't change. + * + * "Partitions" are backend-defined divisions of the resource space. + * K8s: partitions = namespaces. AWS: partitions = regions. GCP: partitions = projects. + */ +export class WatchScope { + /** + * empty = unscoped + */ + "partitions"?: string[]; + + /** Creates a new WatchScope instance. */ + constructor($$source: Partial = {}) { + + Object.assign(this, $$source); + } + + /** + * Creates a new WatchScope instance from a string or object. + */ + static createFrom($$source: any = {}): WatchScope { + const $$createField0_0 = $$createType9; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("partitions" in $$parsedSource) { + $$parsedSource["partitions"] = $$createField0_0($$parsedSource["partitions"]); + } + return new WatchScope($$parsedSource as Partial); + } +} + +/** + * WatchState represents the current state of a watch. + * + * State Machine: + * + * ┌─────────────────────────────┐ + * │ │ + * Idle ──► Syncing ──► Synced ──► Error ──► Syncing │ (retry) + * │ │ │ + * │ ▼ │ + * │ Failed │ (terminal: max retries) + * │ │ + * ▼ │ + * Error ──────────────────────────────────►│ + * │ + * ▼ + * Stopped (terminal: context cancelled) + * + * Transition rules: + * - Idle → Syncing: StartConnectionWatch or EnsureResourceWatch is called. + * - Syncing → Synced: Initial list completed and cache populated. ResourceCount is set. + * - Syncing → Error: Initial list or informer setup failed. Error and Message are set. + * - Synced → Error: Watch stream returned an error during live operation. + * - Error → Syncing: Automatic retry after backoff (if retries remain). + * - Error → Failed: Max retry attempts exhausted. Terminal state. + * - Error → Stopped: Context cancelled during backoff. Terminal state. + * - Any → Stopped: Context cancelled (explicit StopConnectionWatch or shutdown). + * - Idle → Forbidden: Backend detects 401/403 on initial sync. Terminal — no retry. + * - Idle → Skipped: Resource excluded by scope configuration. Terminal. + */ +export enum WatchState { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + /** + * WatchStateIdle means the watch is registered but not started. + * Entered: on registration. Exited: when watch startup begins (→ Syncing). + * Not terminal. + */ + WatchStateIdle = 0, + + /** + * WatchStateSyncing means the watch is running but initial sync is in progress. + * Entered: on first startup or retry. Exited: cache sync completes (→ Synced) + * or fails (→ Error). + * WatchStateEvent.ResourceCount is not yet meaningful in this state. + * Not terminal. + */ + WatchStateSyncing = 1, + + /** + * WatchStateSynced means the watch is running and the cache is fully populated. + * Entered: when cache sync completes successfully. + * Exited: watch stream error (→ Error) or context cancelled (→ Stopped). + * WatchStateEvent.ResourceCount is set to the number of resources observed. + * Not terminal. + */ + WatchStateSynced = 2, + + /** + * WatchStateError means an error occurred during watching. + * Entered: when the watch stream or initial list returns an error. + * Exited: automatic retry (→ Syncing), max retries (→ Failed), or + * context cancelled (→ Stopped). + * WatchStateEvent.Error and Message are set. + * Not terminal. + */ + WatchStateError = 3, + + /** + * WatchStateStopped means the watch was explicitly stopped. + * Entered: when context is cancelled (user-initiated stop or shutdown). + * Terminal — no further transitions occur. + */ + WatchStateStopped = 4, + + /** + * WatchStateFailed means the watch failed after exhausting retry attempts. + * Entered: when max retries are exhausted after repeated errors. + * WatchStateEvent.Error and Message are set. + * Terminal — requires explicit restart via RestartResourceWatch. + */ + WatchStateFailed = 5, + + /** + * WatchStateForbidden means the watch was denied due to 401/403 permissions. + * Entered: when the backend detects a permission error (e.g., K8s 403 on List/Watch). + * Terminal — stable, no auto-retry. User must fix permissions and reconnect. + */ + WatchStateForbidden = 6, + + /** + * WatchStateSkipped means the watch was intentionally not started. + * Entered: when the resource is excluded by scope configuration or other policy. + * Terminal — no further transitions occur unless scope changes. + */ + WatchStateSkipped = 7, +}; + +/** + * WatchStateEvent represents a state change in a watch. + */ +export class WatchStateEvent { + /** + * PluginID identifies the source plugin. + */ + "pluginId": string; + + /** + * Connection is the connection ID that produced this event. + */ + "connection": string; + + /** + * ResourceKey is the resource type key (e.g., "core::v1::Pod"). + */ + "resourceKey": string; + + /** + * State is the new watch state. + */ + "state": WatchState; + + /** + * Message is a human-readable description of the state change. + */ + "message"?: string; + + /** + * ResourceCount is the number of resources observed (if known). + */ + "resourceCount"?: number; + + /** + * ErrorCode is a machine-readable error classification (e.g., "FORBIDDEN", "TIMEOUT"). + * Only set when State is WatchStateError, WatchStateFailed, or WatchStateForbidden. + */ + "errorCode"?: string; + + /** Creates a new WatchStateEvent instance. */ + constructor($$source: Partial = {}) { + if (!("pluginId" in $$source)) { + this["pluginId"] = ""; + } + if (!("connection" in $$source)) { + this["connection"] = ""; + } + if (!("resourceKey" in $$source)) { + this["resourceKey"] = ""; + } + if (!("state" in $$source)) { + this["state"] = WatchState.$zero; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new WatchStateEvent instance from a string or object. + */ + static createFrom($$source: any = {}): WatchStateEvent { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new WatchStateEvent($$parsedSource as Partial); + } +} + +// Private type creation functions +const $$createType0 = $Create.Map($Create.Any, $Create.Any); +const $$createType1 = $Create.Map($Create.Any, $Create.Any); +const $$createType2 = ResourceLink.createFrom; +const $$createType3 = $Create.Nullable($$createType2); +const $$createType4 = FilterPredicate.createFrom; +const $$createType5 = $Create.Array($$createType4); +const $$createType6 = FilterExpression.createFrom; +const $$createType7 = $Create.Array($$createType6); +const $$createType8 = $Create.Array($Create.Any); +const $$createType9 = $Create.Array($Create.Any); +const $$createType10 = $Create.Nullable($$createType6); +const $$createType11 = OrderField.createFrom; +const $$createType12 = $Create.Array($$createType11); +const $$createType13 = PaginationParams.createFrom; +const $$createType14 = $Create.Array($Create.Any); +const $$createType15 = RelationshipExtractor.createFrom; +const $$createType16 = $Create.Nullable($$createType15); +const $$createType17 = RelationshipDescriptor.createFrom; +const $$createType18 = ResourceRef.createFrom; +const $$createType19 = $Create.Array($$createType18); +const $$createType20 = ScaleHint.createFrom; +const $$createType21 = $Create.Nullable($$createType20); +const $$createType22 = ColumnDefinition.createFrom; +const $$createType23 = $Create.Array($$createType22); +const $$createType24 = ResourceMeta.createFrom; +const $$createType25 = $Create.Array($$createType24); +const $$createType26 = $Create.Map($Create.Any, $$createType25); +const $$createType27 = HealthCondition.createFrom; +const $$createType28 = $Create.Array($$createType27); +const $$createType29 = $Create.Map($Create.Any, $Create.Any); +const $$createType30 = $Create.Map($Create.Any, $Create.Any); +const $$createType31 = WatchScope.createFrom; +const $$createType32 = $Create.Nullable($$createType31); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/index.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/index.ts new file mode 100644 index 00000000..040880f0 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/index.ts @@ -0,0 +1,14 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + Category, + Setting, + SettingFileSelection, + SettingOption, + SettingType +} from "./models.js"; + +export type { + Store +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/models.ts b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/models.ts new file mode 100644 index 00000000..f16a22d9 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/omniviewdev/plugin-sdk/settings/models.ts @@ -0,0 +1,331 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * Category is a group of settings. This is used to group settings together in the UI. + */ +export class Category { + "settings": { [_ in string]?: Setting }; + "id": string; + "label": string; + "description": string; + "icon": string; + + /** Creates a new Category instance. */ + constructor($$source: Partial = {}) { + if (!("settings" in $$source)) { + this["settings"] = {}; + } + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("icon" in $$source)) { + this["icon"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Category instance from a string or object. + */ + static createFrom($$source: any = {}): Category { + const $$createField0_0 = $$createType1; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("settings" in $$parsedSource) { + $$parsedSource["settings"] = $$createField0_0($$parsedSource["settings"]); + } + return new Category($$parsedSource as Partial); + } +} + +export class Setting { + /** + * ID is the unique identifier of the setting + */ + "id": string; + + /** + * Label is the human readable label of the setting + */ + "label": string; + + /** + * Description is the human readable description of the setting + */ + "description": string; + + /** + * Type is the type of the setting + */ + "type": SettingType; + + /** + * Value is the value of the setting + */ + "value": any; + + /** + * Default is the default value of the setting + */ + "default": any; + + /** + * Options is an optional list of options for a select setting + */ + "options": SettingOption[]; + + /** + * FileSelection is an optional setting for file selection + */ + "fileSelection": SettingFileSelection | null; + + /** + * Sensitive is a flag to indicate if the setting is sensitive and should not be + * shown in the UI, nor allowed to be used by any other plugin. + */ + "sensitive": boolean; + + /** + * DevOnly indicates the setting should only be visible when dev mode is active. + */ + "devOnly": boolean; + + /** Creates a new Setting instance. */ + constructor($$source: Partial = {}) { + if (!("id" in $$source)) { + this["id"] = ""; + } + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("type" in $$source)) { + this["type"] = SettingType.$zero; + } + if (!("value" in $$source)) { + this["value"] = null; + } + if (!("default" in $$source)) { + this["default"] = null; + } + if (!("options" in $$source)) { + this["options"] = []; + } + if (!("fileSelection" in $$source)) { + this["fileSelection"] = null; + } + if (!("sensitive" in $$source)) { + this["sensitive"] = false; + } + if (!("devOnly" in $$source)) { + this["devOnly"] = false; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new Setting instance from a string or object. + */ + static createFrom($$source: any = {}): Setting { + const $$createField6_0 = $$createType3; + const $$createField7_0 = $$createType5; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("options" in $$parsedSource) { + $$parsedSource["options"] = $$createField6_0($$parsedSource["options"]); + } + if ("fileSelection" in $$parsedSource) { + $$parsedSource["fileSelection"] = $$createField7_0($$parsedSource["fileSelection"]); + } + return new Setting($$parsedSource as Partial); + } +} + +export class SettingFileSelection { + /** + * Whether file selection should be allowed. + */ + "enabled": boolean; + + /** + * Allow the selection of folders. + */ + "allowFolders": boolean; + + /** + * The allowed extensions that should be selectable. + */ + "extensions": string[]; + + /** + * Multiple files can be selected. + */ + "multiple": boolean; + + /** + * Whether the file selection should be saved as a relative path. + */ + "relative": boolean; + + /** + * DefaultPath is the default path for the file selection. + */ + "defaultPath": string; + + /** Creates a new SettingFileSelection instance. */ + constructor($$source: Partial = {}) { + if (!("enabled" in $$source)) { + this["enabled"] = false; + } + if (!("allowFolders" in $$source)) { + this["allowFolders"] = false; + } + if (!("extensions" in $$source)) { + this["extensions"] = []; + } + if (!("multiple" in $$source)) { + this["multiple"] = false; + } + if (!("relative" in $$source)) { + this["relative"] = false; + } + if (!("defaultPath" in $$source)) { + this["defaultPath"] = ""; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SettingFileSelection instance from a string or object. + */ + static createFrom($$source: any = {}): SettingFileSelection { + const $$createField2_0 = $$createType6; + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + if ("extensions" in $$parsedSource) { + $$parsedSource["extensions"] = $$createField2_0($$parsedSource["extensions"]); + } + return new SettingFileSelection($$parsedSource as Partial); + } +} + +export class SettingOption { + /** + * Label is the human readable label of the option + */ + "label": string; + + /** + * Description is an optional human readable description of the option + */ + "description": string; + + /** + * Value is the value of the option + */ + "value": any; + + /** Creates a new SettingOption instance. */ + constructor($$source: Partial = {}) { + if (!("label" in $$source)) { + this["label"] = ""; + } + if (!("description" in $$source)) { + this["description"] = ""; + } + if (!("value" in $$source)) { + this["value"] = null; + } + + Object.assign(this, $$source); + } + + /** + * Creates a new SettingOption instance from a string or object. + */ + static createFrom($$source: any = {}): SettingOption { + let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source; + return new SettingOption($$parsedSource as Partial); + } +} + +export enum SettingType { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = "", + + /** + * Text is the type for a text field entry. + */ + Text = "text", + + /** + * Select is the type for a single-select field entry. + */ + Select = "select", + + /** + * MultiSelect is the type for a multi-select field entry. + */ + MultiSelect = "multiselect", + + /** + * Integer is the type for an integer field entry. + */ + Integer = "integer", + + /** + * Float is the type for a float field entry. + */ + Float = "float", + + /** + * Toggle is the type for a toggle field entry. + */ + Toggle = "toggle", + + /** + * Color is the type for a color field entry. + */ + Color = "color", + + /** + * DateTime is the type for a date time field entry. + */ + DateTime = "datetime", + + /** + * SettingTypePassword is the type for a password field entry. + */ + Password = "password", +}; + +/** + * The settings store is a map of maps. The first map is the category of the settings, and the second + * map is the settings themselves. The key of the first map is the category name, and the key of the + * second map is the setting ID. + */ +export type Store = { [_ in string]?: Category }; + +// Private type creation functions +const $$createType0 = Setting.createFrom; +const $$createType1 = $Create.Map($Create.Any, $$createType0); +const $$createType2 = SettingOption.createFrom; +const $$createType3 = $Create.Array($$createType2); +const $$createType4 = SettingFileSelection.createFrom; +const $$createType5 = $Create.Nullable($$createType4); +const $$createType6 = $Create.Array($Create.Any); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts new file mode 100644 index 00000000..8f2037d5 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts @@ -0,0 +1,61 @@ +//@ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as plugin$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as devserver$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/devserver/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as pluginlog$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/pluginlog/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as resource$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/resource/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as networker$0 from "../../../../omniviewdev/plugin-sdk/pkg/v1/networker/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as resource$1 from "../../../../omniviewdev/plugin-sdk/pkg/v1/resource/models.js"; + +function configure() { + Object.freeze(Object.assign($Create.Events, { + "connection/status": $$createType0, + "core/networker/portforward/closed": $$createType2, + "core/networker/portforward/created": $$createType2, + "plugin/deprecated_protocol": $$createType3, + "plugin/devserver/error": $$createType4, + "plugin/devserver/log": $$createType6, + "plugin/devserver/status": $$createType7, + "plugin/process/log": $$createType8, + "plugin/state_change": $$createType9, + "plugin/update_complete": $$createType10, + "plugin/update_error": $$createType11, + "plugin/update_started": $$createType10, + "watch/STATE": $$createType12, + })); +} + +// Private type creation functions +const $$createType0 = resource$0.ConnectionStatusPayload.createFrom; +const $$createType1 = networker$0.PortForwardSession.createFrom; +const $$createType2 = $Create.Nullable($$createType1); +const $$createType3 = plugin$0.DeprecatedProtocolPayload.createFrom; +const $$createType4 = devserver$0.DevServerErrorPayload.createFrom; +const $$createType5 = devserver$0.LogEntry.createFrom; +const $$createType6 = $Create.Array($$createType5); +const $$createType7 = devserver$0.DevServerState.createFrom; +const $$createType8 = pluginlog$0.LogEntry.createFrom; +const $$createType9 = plugin$0.StateChangePayload.createFrom; +const $$createType10 = plugin$0.UpdatePayload.createFrom; +const $$createType11 = plugin$0.UpdateErrorPayload.createFrom; +const $$createType12 = resource$1.WatchStateEvent.createFrom; + +configure(); diff --git a/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts new file mode 100644 index 00000000..f879bc6e --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts @@ -0,0 +1,64 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type { Events } from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as plugin$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as devserver$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/devserver/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as pluginlog$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/pluginlog/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as resource$0 from "../../../../omniviewdev/omniview/backend/pkg/plugin/resource/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as networker$0 from "../../../../omniviewdev/plugin-sdk/pkg/v1/networker/models.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import type * as resource$1 from "../../../../omniviewdev/plugin-sdk/pkg/v1/resource/models.js"; + +declare module "@wailsio/runtime" { + namespace Events { + interface CustomEvents { + "connection/status": resource$0.ConnectionStatusPayload; + "core/networker/portforward/closed": networker$0.PortForwardSession | null; + "core/networker/portforward/created": networker$0.PortForwardSession | null; + "menu/context/drawer-tab/close": string; + "menu/context/drawer-tab/close-others": string; + "menu/view/bottomdrawer/fullscreen": void; + "menu/view/bottomdrawer/minimize": void; + "menu/view/sidebar/minimize": void; + "menu/view/terminal/create": void; + "plugin/crash_recovery_failed": void; + "plugin/deprecated_protocol": plugin$0.DeprecatedProtocolPayload; + "plugin/dev_install_complete": void; + "plugin/dev_install_error": void; + "plugin/dev_install_start": void; + "plugin/dev_reload_complete": void; + "plugin/dev_reload_error": void; + "plugin/dev_reload_start": void; + "plugin/devserver/error": devserver$0.DevServerErrorPayload; + "plugin/devserver/log": devserver$0.LogEntry[]; + "plugin/devserver/status": devserver$0.DevServerState; + "plugin/init_complete": void; + "plugin/install_error": void; + "plugin/install_finished": void; + "plugin/install_started": void; + "plugin/process/log": pluginlog$0.LogEntry; + "plugin/recovered": void; + "plugin/state_change": plugin$0.StateChangePayload; + "plugin/state_write_error": void; + "plugin/update_complete": plugin$0.UpdatePayload; + "plugin/update_error": plugin$0.UpdateErrorPayload; + "plugin/update_started": plugin$0.UpdatePayload; + "watch/STATE": resource$1.WatchStateEvent; + } + } +} diff --git a/packages/omniviewdev-runtime/src/bindings/time/index.ts b/packages/omniviewdev-runtime/src/bindings/time/index.ts new file mode 100644 index 00000000..698b92d8 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/time/index.ts @@ -0,0 +1,10 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export { + Duration +} from "./models.js"; + +export type { + Time +} from "./models.js"; diff --git a/packages/omniviewdev-runtime/src/bindings/time/models.ts b/packages/omniviewdev-runtime/src/bindings/time/models.ts new file mode 100644 index 00000000..842669a9 --- /dev/null +++ b/packages/omniviewdev-runtime/src/bindings/time/models.ts @@ -0,0 +1,87 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Create as $Create } from "@wailsio/runtime"; + +/** + * A Duration represents the elapsed time between two instants + * as an int64 nanosecond count. The representation limits the + * largest representable duration to approximately 290 years. + */ +export enum Duration { + /** + * The Go zero value for the underlying type of the enum. + */ + $zero = 0, + + minDuration = -9223372036854775808, + maxDuration = 9223372036854775807, + + /** + * Common durations. There is no definition for units of Day or larger + * to avoid confusion across daylight savings time zone transitions. + * + * To count the number of units in a [Duration], divide: + * + * second := time.Second + * fmt.Print(int64(second/time.Millisecond)) // prints 1000 + * + * To convert an integer number of units to a Duration, multiply: + * + * seconds := 10 + * fmt.Print(time.Duration(seconds)*time.Second) // prints 10s + */ + Nanosecond = 1, + Microsecond = 1000, + Millisecond = 1000000, + Second = 1000000000, + Minute = 60000000000, + Hour = 3600000000000, +}; + +/** + * A Time represents an instant in time with nanosecond precision. + * + * Programs using times should typically store and pass them as values, + * not pointers. That is, time variables and struct fields should be of + * type [time.Time], not *time.Time. + * + * A Time value can be used by multiple goroutines simultaneously except + * that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and + * [Time.UnmarshalText] are not concurrency-safe. + * + * Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods. + * The [Time.Sub] method subtracts two instants, producing a [Duration]. + * The [Time.Add] method adds a Time and a Duration, producing a Time. + * + * The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. + * As this time is unlikely to come up in practice, the [Time.IsZero] method gives + * a simple way of detecting a time that has not been initialized explicitly. + * + * Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a + * Time with a specific Location. Changing the Location of a Time value with + * these methods does not change the actual instant it represents, only the time + * zone in which to interpret it. + * + * Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], [Time.AppendBinary], + * [Time.MarshalJSON], [Time.MarshalText] and [Time.AppendText] methods store the [Time.Location]'s offset, + * but not the location name. They therefore lose information about Daylight Saving Time. + * + * In addition to the required “wall clock” reading, a Time may contain an optional + * reading of the current process's monotonic clock, to provide additional precision + * for comparison or subtraction. + * See the “Monotonic Clocks” section in the package documentation for details. + * + * Note that the Go == operator compares not just the time instant but also the + * Location and the monotonic clock reading. Therefore, Time values should not + * be used as map or database keys without first guaranteeing that the + * identical Location has been set for all values, which can be achieved + * through use of the UTC or Local method, and that the monotonic clock reading + * has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) + * to t == u, since t.Equal uses the most accurate comparison available and + * correctly handles the case when only one of its arguments has a monotonic + * clock reading. + */ +export type Time = any; diff --git a/packages/omniviewdev-runtime/src/context/plugins/PluginContext.tsx b/packages/omniviewdev-runtime/src/context/plugins/PluginContext.tsx index 4d161c3c..fcc2bca5 100644 --- a/packages/omniviewdev-runtime/src/context/plugins/PluginContext.tsx +++ b/packages/omniviewdev-runtime/src/context/plugins/PluginContext.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { type config } from '../../wailsjs/go/models'; +import type { PluginMeta } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models'; export interface PluginContextType { /** The runtime instance ID for this plugin (e.g. "kubernetes-dev" or "kubernetes"). */ pluginId: string; - meta: config.PluginMeta + meta: PluginMeta settings: Record; } diff --git a/packages/omniviewdev-runtime/src/context/plugins/PluginContextProvider.tsx b/packages/omniviewdev-runtime/src/context/plugins/PluginContextProvider.tsx index 36e85250..b209e2c4 100644 --- a/packages/omniviewdev-runtime/src/context/plugins/PluginContextProvider.tsx +++ b/packages/omniviewdev-runtime/src/context/plugins/PluginContextProvider.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { PluginContext } from './PluginContext'; -import { PluginValues } from '../../wailsjs/go/settings/Client'; -import { config } from '../../wailsjs/go/models'; -import { GetPluginMeta } from '../../wailsjs/go/plugin/pluginManager'; +import { PluginValues } from '../../bindings/github.com/omniviewdev/omniview/settingscontrollerservice'; +import { PluginMeta } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models'; +import { GetPluginMeta } from '../../bindings/github.com/omniviewdev/omniview/pluginmanagerservice'; import { parseAppError } from '../../errors/parseAppError'; export type PluginContextProviderProps = { @@ -13,7 +13,7 @@ export type PluginContextProviderProps = { export function PluginContextProvider(props: React.PropsWithChildren): React.ReactElement { const { children, pluginId } = props; const [settings, setSettings] = React.useState>({}); - const [meta, setMeta] = React.useState(new config.PluginMeta); + const [meta, setMeta] = React.useState(new PluginMeta); const [metaLoaded, setMetaLoaded] = React.useState(false); const [metaError, setMetaError] = React.useState(null); diff --git a/packages/omniviewdev-runtime/src/context/settings/SettingsContext.tsx b/packages/omniviewdev-runtime/src/context/settings/SettingsContext.tsx index b3defdc8..936f84f5 100644 --- a/packages/omniviewdev-runtime/src/context/settings/SettingsContext.tsx +++ b/packages/omniviewdev-runtime/src/context/settings/SettingsContext.tsx @@ -1,5 +1,5 @@ import React, { createContext, useState } from 'react'; -import { Values } from '../../wailsjs/go/settings/provider'; +import { Values } from '../../bindings/github.com/omniviewdev/omniview/settingsproviderservice'; // Define the context type export interface SettingsContextType { diff --git a/packages/omniviewdev-runtime/src/hooks/connection/useConnection.tsx b/packages/omniviewdev-runtime/src/hooks/connection/useConnection.tsx index 114bae55..2829801a 100644 --- a/packages/omniviewdev-runtime/src/hooks/connection/useConnection.tsx +++ b/packages/omniviewdev-runtime/src/hooks/connection/useConnection.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { GetConnection, UpdateConnection, RemoveConnection, StartConnection, StopConnection } from '../../wailsjs/go/resource/Client'; -import { type types } from '../../wailsjs/go/models'; +import { GetConnection, UpdateConnection, RemoveConnection, StartConnection, StopConnection } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import type { Connection } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { createErrorHandler } from '../../errors/parseAppError'; import { useResolvedPluginId } from '../useResolvedPluginId'; @@ -51,14 +51,14 @@ export const useConnection = ({ pluginID: explicitPluginID, connectionID }: UseC }); const { mutateAsync: updateConnection } = useMutation({ - mutationFn: async (conn: types.Connection) => UpdateConnection(pluginID, conn), + mutationFn: async (conn: Connection) => UpdateConnection(pluginID, conn), onSuccess(data, { name }) { showSnackbar({ message: `Connection ${name} successfully updated`, status: 'success' }); // Update the list and detail queryClient.setQueryData(queryKey, connection); queryClient.setQueriesData( { queryKey: [pluginID, 'connection', 'list'] }, - (previous: types.Connection[] | undefined) => previous?.map(conn => conn.id === connectionID ? data : conn), + (previous: Connection[] | undefined) => previous?.map(conn => conn.id === connectionID ? data : conn), ); }, onError: createErrorHandler(showSnackbar, 'Failed to update connection'), @@ -72,7 +72,7 @@ export const useConnection = ({ pluginID: explicitPluginID, connectionID }: UseC queryClient.setQueryData(queryKey, undefined); queryClient.setQueriesData( { queryKey: [pluginID, 'connection', 'list'] }, - (previous: types.Connection[] | undefined) => previous?.filter(conn => conn.id !== connectionID), + (previous: Connection[] | undefined) => previous?.filter(conn => conn.id !== connectionID), ); }, onError: createErrorHandler(showSnackbar, 'Failed to remove connection'), diff --git a/packages/omniviewdev-runtime/src/hooks/connection/useConnectionNamespaces.ts b/packages/omniviewdev-runtime/src/hooks/connection/useConnectionNamespaces.ts index 2adda689..426061ee 100644 --- a/packages/omniviewdev-runtime/src/hooks/connection/useConnectionNamespaces.ts +++ b/packages/omniviewdev-runtime/src/hooks/connection/useConnectionNamespaces.ts @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import { GetConnectionNamespaces } from '../../wailsjs/go/resource/Client'; +import { GetConnectionNamespaces } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseConnectionOptions = { diff --git a/packages/omniviewdev-runtime/src/hooks/connection/useConnectionStatus.ts b/packages/omniviewdev-runtime/src/hooks/connection/useConnectionStatus.ts index a88b852a..4cb425c9 100644 --- a/packages/omniviewdev-runtime/src/hooks/connection/useConnectionStatus.ts +++ b/packages/omniviewdev-runtime/src/hooks/connection/useConnectionStatus.ts @@ -1,13 +1,13 @@ import { useEffect, useState, useCallback, useRef } from 'react'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { Events } from '@wailsio/runtime'; import { ListAllConnections, GetAllConnectionStates, StopConnection, StartConnectionWatch, -} from '../../wailsjs/go/resource/Client'; -import { RetryFailedPlugin } from '../../wailsjs/go/plugin/pluginManager'; -import type { types } from '../../wailsjs/go/models'; +} from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import { RetryFailedPlugin } from '../../bindings/github.com/omniviewdev/omniview/pluginmanagerservice'; +import type { Connection } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models'; import { WatchState } from '../../types/watch'; import type { WatchStateEvent } from '../../types/watch'; import { @@ -21,21 +21,6 @@ import { updateTracker, } from '../../utils/activeSyncAggregator'; -/** - * Mirrors backend resource.ConnectionState. - * Locally declared until Wails v3 model generation handles cross-package types. - */ -interface ConnectionStateResponse { - connection: types.Connection; - started: boolean; - resources: Record; - resourceCounts: Record; - totalResources: number; - syncedCount: number; - errorCount: number; - lastSyncTime?: string; -} - export interface ConnectionStatusEntry { pluginID: string; connectionID: string; @@ -76,7 +61,7 @@ export function useConnectionStatus(): ConnectionStatusSummary { // Set of "pluginID/connectionID" keys for started connections const [startedKeys, setStartedKeys] = useState>(new Set()); // Connection metadata from ListAllConnections - const [allConnections, setAllConnections] = useState>({}); + const [allConnections, setAllConnections] = useState>({}); // Sync state per connection const [syncs, setSyncs] = useState>(new Map()); const trackersRef = useRef>(new Map()); @@ -86,7 +71,8 @@ export function useConnectionStatus(): ConnectionStatusSummary { // Listen for plugin crash recovery events useEffect(() => { - const cancelCrash = EventsOn('plugin/crash_recovery_failed', (data: { pluginID?: string; error?: string }) => { + const cancelCrash = Events.On('plugin/crash_recovery_failed', (ev) => { + const data = ev.data as unknown as { pluginID?: string; error?: string }; const pluginID = data?.pluginID; if (!pluginID) return; setFailedPlugins((prev) => { @@ -96,7 +82,8 @@ export function useConnectionStatus(): ConnectionStatusSummary { }); }); - const cancelRecovered = EventsOn('plugin/recovered', (data: { pluginID?: string }) => { + const cancelRecovered = Events.On('plugin/recovered', (ev) => { + const data = ev.data as unknown as { pluginID?: string }; const pluginID = data?.pluginID; if (!pluginID) return; setFailedPlugins((prev) => { @@ -116,14 +103,15 @@ export function useConnectionStatus(): ConnectionStatusSummary { // Hydrate full connection + watch state on mount useEffect(() => { GetAllConnectionStates() - .then((result: Record) => { + .then((result) => { if (!result) return; - const conns: Record = {}; + const conns: Record = {}; const keys = new Set(); const newSyncs = new Map(); for (const [pluginID, states] of Object.entries(result)) { + if (!states) continue; conns[pluginID] = states.map((s) => s.connection); for (const s of states) { @@ -159,12 +147,8 @@ export function useConnectionStatus(): ConnectionStatusSummary { // Listen for connection/status events useEffect(() => { - const cancel = EventsOn('connection/status', (event: { - pluginID: string; - connectionID: string; - status: string; - name: string; - }) => { + const cancel = Events.On('connection/status', (ev) => { + const event = ev.data; const key = `${event.pluginID}/${event.connectionID}`; if (event.status === 'DISCONNECTED') { @@ -191,8 +175,13 @@ export function useConnectionStatus(): ConnectionStatusSummary { // Re-fetch connections to get latest metadata ListAllConnections() - .then((result: Record) => { - if (result) setAllConnections(result); + .then((result) => { + if (!result) return; + const filtered: Record = {}; + for (const [k, v] of Object.entries(result)) { + if (v != null) filtered[k] = v; + } + setAllConnections(filtered); }) .catch(() => {}); }); @@ -201,7 +190,8 @@ export function useConnectionStatus(): ConnectionStatusSummary { }, []); // Listen for watch/STATE events - const handleWatchEvent = useCallback((event: WatchStateEvent) => { + const handleWatchEvent = useCallback((ev: Events.WailsEvent) => { + const event = ev.data as WatchStateEvent; const key = trackerKey(event); // If we get watch events for a connection, it's started @@ -223,7 +213,7 @@ export function useConnectionStatus(): ConnectionStatusSummary { }, []); useEffect(() => { - const cancel = EventsOn('watch/STATE', handleWatchEvent); + const cancel = Events.On('watch/STATE', handleWatchEvent); return cancel; }, [handleWatchEvent]); diff --git a/packages/omniviewdev-runtime/src/hooks/connection/useConnections.ts b/packages/omniviewdev-runtime/src/hooks/connection/useConnections.ts index 5f26abdd..5f094b4a 100644 --- a/packages/omniviewdev-runtime/src/hooks/connection/useConnections.ts +++ b/packages/omniviewdev-runtime/src/hooks/connection/useConnections.ts @@ -1,9 +1,9 @@ import { useMutation, useQuery, useQueryClient, keepPreviousData } from '@tanstack/react-query'; -import { ListConnections, StartConnectionWatch, StopConnectionWatch } from '../../wailsjs/go/resource/Client'; -import { type types } from '../../wailsjs/go/models'; +import { ListConnections, StartConnectionWatch, StopConnectionWatch } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import type { Connection } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { createErrorHandler } from '../../errors/parseAppError'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { Events } from '@wailsio/runtime'; import React from 'react'; import { useResolvedPluginId } from '../useResolvedPluginId'; @@ -29,26 +29,27 @@ export const useConnections = ({ plugin: explicitPlugin }: UseConnectionsOptions // === Mutations === // const { mutateAsync: startWatch } = useMutation({ - mutationFn: async (conn: types.Connection) => StartConnectionWatch(plugin, conn.id), + mutationFn: async (conn: Connection) => StartConnectionWatch(plugin, conn.id), onError: createErrorHandler(showSnackbar, 'Failed to start connection watch'), }); const { mutateAsync: stopWatch } = useMutation({ - mutationFn: async (conn: types.Connection) => StopConnectionWatch(plugin, conn.id), + mutationFn: async (conn: Connection) => StopConnectionWatch(plugin, conn.id), onError: createErrorHandler(showSnackbar, 'Failed to stop connection watch'), }); /** * Handle sync of connections from the backend */ - const onConnectionSync = React.useCallback((connections: types.Connection[]) => { + const onConnectionSync = React.useCallback((ev: Events.WailsEvent) => { + const connections = ev.data as Connection[]; console.log("got update to connections", connections) queryClient.setQueryData(queryKey, connections) }, []); // *Only on mount*, we want subscribe to new resources, updates and deletes React.useEffect(() => { - const syncCloser = EventsOn(`${plugin}/connection/sync`, onConnectionSync); + const syncCloser = Events.On(`${plugin}/connection/sync`, onConnectionSync); return () => { syncCloser() diff --git a/packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts b/packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts index be5aee0b..4e927481 100644 --- a/packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts +++ b/packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts @@ -1,5 +1,5 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import { Get, Set } from '../../wailsjs/go/data/Client'; +import { Get, Set } from '../../bindings/github.com/omniviewdev/omniview/datacontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UsePluginDataResult = { diff --git a/packages/omniviewdev-runtime/src/hooks/exec/useExecSession.ts b/packages/omniviewdev-runtime/src/hooks/exec/useExecSession.ts index fc68c0db..d1f41711 100644 --- a/packages/omniviewdev-runtime/src/hooks/exec/useExecSession.ts +++ b/packages/omniviewdev-runtime/src/hooks/exec/useExecSession.ts @@ -1,8 +1,8 @@ import { useMutation } from '@tanstack/react-query'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { parseAppError, showAppError } from '../../errors/parseAppError'; -import { exec } from '../../wailsjs/go/models'; -import { CreateSession } from '../../wailsjs/go/exec/Client'; +import { SessionOptions } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/models'; +import { CreateSession } from '../../bindings/github.com/omniviewdev/omniview/execcontrollerservice'; import { useBottomDrawer } from '../drawer'; import { useResolvedPluginId } from '../useResolvedPluginId'; @@ -19,7 +19,7 @@ type CreateSessionOptions = { connectionID: string; icon?: string | React.ReactNode; label?: string; - opts: Partial + opts: Partial } /** @@ -48,7 +48,7 @@ export const useExec = ({ pluginID: explicitPluginID }: UseResourceMutationsOpti }, }); - const sessionOpts = exec.SessionOptions.createFrom({ + const sessionOpts = SessionOptions.createFrom({ command: ['/bin/bash'], tty: true, ...opts, @@ -56,6 +56,7 @@ export const useExec = ({ pluginID: explicitPluginID }: UseResourceMutationsOpti try { const session = await CreateSession(pluginID, connectionID, sessionOpts); + if (!session) throw new Error('Failed to create session: null response'); // Replace temp ID with real session ID and mark connected updateTab( { id: tempId }, diff --git a/packages/omniviewdev-runtime/src/hooks/logs/useLogSession.ts b/packages/omniviewdev-runtime/src/hooks/logs/useLogSession.ts index 2014ebaf..27142a7d 100644 --- a/packages/omniviewdev-runtime/src/hooks/logs/useLogSession.ts +++ b/packages/omniviewdev-runtime/src/hooks/logs/useLogSession.ts @@ -1,8 +1,8 @@ import { useMutation } from '@tanstack/react-query'; import { useSnackbar } from '../snackbar/useSnackbar'; import { createErrorHandler } from '../../errors/parseAppError'; -import { CreateSession, CloseSession } from '../../wailsjs/go/logs/Client'; -import { logs } from '../../wailsjs/go/models'; +import { CreateSession, CloseSession } from '../../bindings/github.com/omniviewdev/omniview/logscontrollerservice'; +import { CreateSessionOptions, LogSessionOptions } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/models'; import { useBottomDrawer } from '../drawer'; import { useResolvedPluginId } from '../useResolvedPluginId'; @@ -41,11 +41,11 @@ export const useLogs = ({ pluginID: explicitPluginID }: UseLogSessionOptions) => tailLines = 1000, params, }: CreateLogSessionArgs) => { - const opts = logs.CreateSessionOptions.createFrom({ + const opts = CreateSessionOptions.createFrom({ resource_key: resourceKey, resource_id: resourceID, resource_data: resourceData, - options: logs.LogSessionOptions.createFrom({ + options: LogSessionOptions.createFrom({ target: target ?? '', follow, include_previous: false, @@ -59,6 +59,7 @@ export const useLogs = ({ pluginID: explicitPluginID }: UseLogSessionOptions) => }); const session = await CreateSession(pluginID, connectionID, opts); + if (!session) throw new Error('Failed to create log session: null response'); createTab({ id: session.id, title: label ?? `Logs ${session.id.substring(0, 8)}`, diff --git a/packages/omniviewdev-runtime/src/hooks/metric/useMetricProviders.ts b/packages/omniviewdev-runtime/src/hooks/metric/useMetricProviders.ts index a6e55a03..078f053f 100644 --- a/packages/omniviewdev-runtime/src/hooks/metric/useMetricProviders.ts +++ b/packages/omniviewdev-runtime/src/hooks/metric/useMetricProviders.ts @@ -2,14 +2,14 @@ import { useQuery } from '@tanstack/react-query'; import { GetProviders, GetProvidersForResource, -} from '../../wailsjs/go/metric/Client'; -import type { metric } from '../../wailsjs/go/models'; +} from '../../bindings/github.com/omniviewdev/omniview/metriccontrollerservice'; +import type { MetricProviderSummary } from '../../bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/models'; /** * Hook to get all available metric providers. */ export const useMetricProviders = () => { - return useQuery({ + return useQuery({ queryKey: ['metric', 'providers'], queryFn: GetProviders, staleTime: 30_000, @@ -20,7 +20,7 @@ export const useMetricProviders = () => { * Hook to get metric providers that support a specific resource type. */ export const useMetricProvidersForResource = (resourceKey: string) => { - return useQuery({ + return useQuery({ queryKey: ['metric', 'providers', resourceKey], queryFn: () => GetProvidersForResource(resourceKey), enabled: !!resourceKey, diff --git a/packages/omniviewdev-runtime/src/hooks/metric/useMetricStream.ts b/packages/omniviewdev-runtime/src/hooks/metric/useMetricStream.ts index bd8dbef6..c3ebc365 100644 --- a/packages/omniviewdev-runtime/src/hooks/metric/useMetricStream.ts +++ b/packages/omniviewdev-runtime/src/hooks/metric/useMetricStream.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; -import { Subscribe, Unsubscribe } from '../../wailsjs/go/metric/Client'; -import type { metric } from '../../wailsjs/go/models'; +import { Events } from '@wailsio/runtime'; +import { Subscribe, Unsubscribe } from '../../bindings/github.com/omniviewdev/omniview/metriccontrollerservice'; +import type { MetricResult } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models'; import { useResolvedPluginId } from '../useResolvedPluginId'; export type UseMetricStreamOptions = { @@ -27,7 +27,7 @@ export type UseMetricStreamOptions = { export type UseMetricStreamResult = { /** The latest stream output */ - data: metric.MetricResult[] | null; + data: MetricResult[] | null; /** The subscription ID */ subscriptionID: string | null; /** Whether the stream is active */ @@ -60,7 +60,7 @@ export const useMetricStream = ( } = opts; const pluginID = useResolvedPluginId(explicitPluginID); - const [data, setData] = useState(null); + const [data, setData] = useState(null); const [subscriptionID, setSubscriptionID] = useState(null); const [isStreaming, setIsStreaming] = useState(false); const [error, setError] = useState(null); @@ -86,7 +86,8 @@ export const useMetricStream = ( setError(null); // Listen for data events - const dataCleanup = EventsOn(`core/metrics/data/${subID}`, (rawData: string) => { + const dataCleanup = Events.On(`core/metrics/data/${subID}`, (ev) => { + const rawData = ev.data as string; try { const output = JSON.parse(rawData); if (output.results) { @@ -98,7 +99,8 @@ export const useMetricStream = ( }); // Listen for error events - const errorCleanup = EventsOn(`core/metrics/error/${subID}`, (rawData: string) => { + const errorCleanup = Events.On(`core/metrics/error/${subID}`, (ev) => { + const rawData = ev.data as string; try { const output = JSON.parse(rawData); setError(output.error || 'Unknown error'); diff --git a/packages/omniviewdev-runtime/src/hooks/metric/useResourceMetrics.ts b/packages/omniviewdev-runtime/src/hooks/metric/useResourceMetrics.ts index caf8cca0..150e0297 100644 --- a/packages/omniviewdev-runtime/src/hooks/metric/useResourceMetrics.ts +++ b/packages/omniviewdev-runtime/src/hooks/metric/useResourceMetrics.ts @@ -1,6 +1,7 @@ import { useQuery, keepPreviousData } from '@tanstack/react-query'; -import { QueryAll } from '../../wailsjs/go/metric/Client'; -import type { metric } from '../../wailsjs/go/models'; +import { QueryAll } from '../../bindings/github.com/omniviewdev/omniview/metriccontrollerservice'; +import type { QueryResponse } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models'; +import type { MetricProviderSummary } from '../../bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/metric/models'; import { useMetricProvidersForResource } from './useMetricProviders'; export type UseResourceMetricsOptions = { @@ -30,9 +31,9 @@ export type UseResourceMetricsOptions = { export type UseResourceMetricsResult = { /** Metric results keyed by provider plugin ID */ - data: Record | undefined; + data: Record | undefined; /** Available metric providers for this resource type */ - providers: metric.MetricProviderSummary[]; + providers: MetricProviderSummary[]; /** Whether any query is currently loading */ isLoading: boolean; /** Error from the query, if any */ @@ -79,7 +80,7 @@ export const useResourceMetrics = ( ) * 1_000_000 : 0; - const metricsQuery = useQuery>({ + const metricsQuery = useQuery>({ queryKey: [ 'metric', 'query', @@ -92,8 +93,8 @@ export const useResourceMetrics = ( timeRange?.start?.getTime(), timeRange?.end?.getTime(), ], - queryFn: () => - QueryAll( + queryFn: async () => { + const raw = await QueryAll( connectionID, resourceKey, resourceID, @@ -104,7 +105,13 @@ export const useResourceMetrics = ( timeRange?.start ?? new Date(0), timeRange?.end ?? new Date(0), stepNs, - ), + ); + const filtered: Record = {}; + for (const [k, v] of Object.entries(raw)) { + if (v != null) filtered[k] = v; + } + return filtered; + }, enabled: enabled && !!connectionID && !!resourceKey && (resourceKey.startsWith('cluster::') || !!resourceID) && providers.length > 0, refetchInterval: refreshInterval > 0 ? refreshInterval : undefined, staleTime: 5_000, diff --git a/packages/omniviewdev-runtime/src/hooks/networker/types.ts b/packages/omniviewdev-runtime/src/hooks/networker/types.ts index 39d28ff2..ef407938 100644 --- a/packages/omniviewdev-runtime/src/hooks/networker/types.ts +++ b/packages/omniviewdev-runtime/src/hooks/networker/types.ts @@ -1,4 +1,4 @@ -import { networker } from "../../models"; +import type { PortForwardSession } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models'; export type PortForwardResourceOpts = { /** @@ -44,10 +44,10 @@ export type PortForwardResourceOpts = { labels?: Record; }; -export type PortForwardResourceFunction = (opts: PortForwardResourceOpts) => Promise; +export type PortForwardResourceFunction = (opts: PortForwardResourceOpts) => Promise; export type ResourcePortForwarder = { - sessions: networker.PortForwardSession[]; + sessions: PortForwardSession[]; forward: PortForwardResourceFunction; close: (sessionId: string) => Promise; }; diff --git a/packages/omniviewdev-runtime/src/hooks/networker/usePortForwardSessions.ts b/packages/omniviewdev-runtime/src/hooks/networker/usePortForwardSessions.ts index e7fe694a..2512a801 100644 --- a/packages/omniviewdev-runtime/src/hooks/networker/usePortForwardSessions.ts +++ b/packages/omniviewdev-runtime/src/hooks/networker/usePortForwardSessions.ts @@ -3,8 +3,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { ClosePortForwardSession, ListAllPortForwardSessions, -} from '../../wailsjs/go/networker/Client'; -import { BrowserOpenURL, EventsOn } from '../../wailsjs/runtime/runtime'; +} from '../../bindings/github.com/omniviewdev/omniview/networkercontrollerservice'; +import { Browser, Events } from '@wailsio/runtime'; import { useSnackbar } from '../snackbar'; import { createErrorHandler, parseAppError } from '../../errors/parseAppError'; @@ -32,10 +32,10 @@ export function usePortForwardSessions() { // Listen for session lifecycle events from the Go backend and invalidate the query cache. useEffect(() => { - const cancelCreated = EventsOn('core/networker/portforward/created', () => { + const cancelCreated = Events.On('core/networker/portforward/created', () => { queryClient.invalidateQueries({ queryKey: [...ALL_SESSIONS_KEY] }); }); - const cancelClosed = EventsOn('core/networker/portforward/closed', () => { + const cancelClosed = Events.On('core/networker/portforward/closed', () => { queryClient.invalidateQueries({ queryKey: [...ALL_SESSIONS_KEY] }); }); @@ -63,7 +63,7 @@ export function usePortForwardSessions() { sessions, activeSessions, closeSession: closeMutation.mutateAsync, - openInBrowser: (localPort: number) => BrowserOpenURL(`http://localhost:${localPort}`), + openInBrowser: (localPort: number) => Browser.OpenURL(`http://localhost:${localPort}`), }; } diff --git a/packages/omniviewdev-runtime/src/hooks/networker/useResourcePortForwarder.tsx b/packages/omniviewdev-runtime/src/hooks/networker/useResourcePortForwarder.tsx index ff028ea1..9572c120 100644 --- a/packages/omniviewdev-runtime/src/hooks/networker/useResourcePortForwarder.tsx +++ b/packages/omniviewdev-runtime/src/hooks/networker/useResourcePortForwarder.tsx @@ -1,12 +1,12 @@ import { PortForwardResourceOpts } from './types'; import { ALL_SESSIONS_KEY } from './usePortForwardSessions'; -import { networker } from '../../wailsjs/go/models'; -import { BrowserOpenURL } from '../../wailsjs/runtime/runtime'; +import { FindPortForwardSessionRequest, PortForwardSessionOptions } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models'; +import { Browser } from '@wailsio/runtime'; import { ClosePortForwardSession, FindPortForwardSessions, StartResourcePortForwardingSession, -} from '../../wailsjs/go/networker/Client'; +} from '../../bindings/github.com/omniviewdev/omniview/networkercontrollerservice'; import { useSnackbar } from '../snackbar'; import { createErrorHandler, parseAppError } from '../../errors/parseAppError'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; @@ -24,7 +24,7 @@ export function useResourcePortForwarder({ pluginID: explicitPluginID, connectio const sessions = useQuery({ queryKey, - queryFn: async () => FindPortForwardSessions(pluginID, connectionID, networker.FindPortForwardSessionRequest.createFrom({ + queryFn: async () => FindPortForwardSessions(pluginID, connectionID, FindPortForwardSessionRequest.createFrom({ resource_id: resourceID, connection_id: connectionID, })).catch((e: unknown) => { @@ -41,7 +41,7 @@ export function useResourcePortForwarder({ pluginID: explicitPluginID, connectio const forwardMutation = useMutation({ mutationFn: async ({ opts }: { opts: Partial }) => { - const sessionOpts = networker.PortForwardSessionOptions.createFrom({ + const sessionOpts = PortForwardSessionOptions.createFrom({ local_port: opts.localPort || 0, remote_port: opts.remotePort, protocol: opts.protocol || 'TCP', @@ -58,8 +58,9 @@ export function useResourcePortForwarder({ pluginID: explicitPluginID, connectio }); const result = await StartResourcePortForwardingSession(pluginID, connectionID, sessionOpts); + if (!result) throw new Error('Failed to start port forwarding: null response'); if (opts.openInBrowser) { - BrowserOpenURL(`http://localhost:${result.local_port}`); + Browser.OpenURL(`http://localhost:${result.local_port}`); } return result }, @@ -73,7 +74,7 @@ export function useResourcePortForwarder({ pluginID: explicitPluginID, connectio }); // const forward: PortForwardResourceFunction = React.useCallback(async (opts) => { - // const sessionOpts = networker.PortForwardSessionOptions.createFrom({ + // const sessionOpts = PortForwardSessionOptions.createFrom({ // local_port: opts.localPort || 0, // remote_port: opts.remotePort, // protocol: opts.protocol || 'TCP', diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useActiveSyncs.ts b/packages/omniviewdev-runtime/src/hooks/resource/useActiveSyncs.ts index ed7c1de1..1e289b44 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useActiveSyncs.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useActiveSyncs.ts @@ -1,5 +1,5 @@ import { useEffect, useState, useCallback, useRef } from 'react'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { Events } from '@wailsio/runtime'; import type { WatchStateEvent } from '../../types/watch'; import { type ActiveSync, @@ -23,7 +23,8 @@ export const useActiveSyncs = () => { const trackersRef = useRef>(new Map()); const removalTimers = useRef>>(new Map()); - const handleEvent = useCallback((event: WatchStateEvent) => { + const handleEvent = useCallback((ev: Events.WailsEvent) => { + const event = ev.data as WatchStateEvent; const key = trackerKey(event); const tracker = updateTracker(trackersRef.current, event); const activeSync = computeActiveSync(tracker); @@ -56,7 +57,7 @@ export const useActiveSyncs = () => { }, []); useEffect(() => { - const cancel = EventsOn('watch/STATE', handleEvent); + const cancel = Events.On('watch/STATE', handleEvent); return () => { cancel(); for (const timer of removalTimers.current.values()) { diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useEditorSchemas.ts b/packages/omniviewdev-runtime/src/hooks/resource/useEditorSchemas.ts index 02ded5b1..6419a539 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useEditorSchemas.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useEditorSchemas.ts @@ -1,5 +1,5 @@ import { useQuery } from '@tanstack/react-query'; -import { GetEditorSchemas } from '../../wailsjs/go/resource/Client'; +import { GetEditorSchemas } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseEditorSchemasOptions = { diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResource.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResource.ts index 02323378..c1223eb9 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResource.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResource.ts @@ -1,8 +1,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { createErrorHandler } from '../../errors/parseAppError'; -import { resource } from '../../wailsjs/go/models'; -import { Get, Update, Delete } from '../../wailsjs/go/resource/Client'; +import { UpdateInput, DeleteInput, GetInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; +import { Get, Update, Delete } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceOptions = { @@ -62,7 +62,7 @@ export const useResource = ({ // === Mutations === // const { mutateAsync: update } = useMutation({ - mutationFn: async (opts: { input?: any }) => Update(pluginID, connectionID, resourceKey, resource.ClientUpdateInput.createFrom({ + mutationFn: async (opts: { input?: any }) => Update(pluginID, connectionID, resourceKey, UpdateInput.createFrom({ input: opts.input, id: resourceID, namespace, @@ -75,7 +75,7 @@ export const useResource = ({ }); const { mutateAsync: remove } = useMutation({ - mutationFn: async (opts: { gracePeriodSeconds?: number } = {}) => Delete(pluginID, connectionID, resourceKey, resource.DeleteInput.createFrom({ + mutationFn: async (opts: { gracePeriodSeconds?: number } = {}) => Delete(pluginID, connectionID, resourceKey, DeleteInput.createFrom({ id: resourceID, namespace, gracePeriodSeconds: opts.gracePeriodSeconds, @@ -89,7 +89,7 @@ export const useResource = ({ const resourceQuery = useQuery({ queryKey, - queryFn: async () => Get(pluginID, connectionID, resourceKey, resource.GetInput.createFrom({ + queryFn: async () => Get(pluginID, connectionID, resourceKey, GetInput.createFrom({ id: resourceID, namespace, })), diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceActions.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceActions.ts index c62e7928..57806803 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceActions.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceActions.ts @@ -1,8 +1,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { showAppError } from '../../errors/parseAppError'; -import { resource } from '../../wailsjs/go/models'; -import { GetActions, ExecuteAction } from '../../wailsjs/go/resource/Client'; +import { ActionInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; +import { GetActions, ExecuteAction } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceActionsOptions = { @@ -107,10 +107,10 @@ export const useExecuteAction = ({ connectionID, resourceKey, actionID, - resource.ActionInput.createFrom({ id, namespace, params }), + ActionInput.createFrom({ id, namespace, params }), ), onSuccess: (result) => { - if (result.message) { + if (result?.message) { showSnackbar(result.message, 'success'); } // Invalidate the resource list cache so tables refresh after actions like upgrade/rollback diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceAreaComponent.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceAreaComponent.ts index ef8a8156..82dbf95a 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceAreaComponent.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceAreaComponent.ts @@ -1,9 +1,9 @@ import { useQuery } from '@tanstack/react-query'; -import { GetResourceAreaComponent } from '../../wailsjs/go/ui/Client'; -import { type ui } from '../../wailsjs/go/models'; +import { GetResourceAreaComponent } from '../../bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/servicewrapper'; +import type { GetResourceAreaComponentInput } from '../../bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/models'; -export const useResourceAreaComponent = (params: ui.GetResourceAreaComponentInput) => { +export const useResourceAreaComponent = (params: GetResourceAreaComponentInput) => { const queryKey = ['component', params.plugin, params.resource, params.area]; const component = useQuery({ diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceGroups.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceGroups.ts index ed44cba9..2cd9444b 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceGroups.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceGroups.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; // Underlying client -import { GetResourceGroups } from '../../wailsjs/go/resource/Client'; +import { GetResourceGroups } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceGroupsOptions = { diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceMutations.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceMutations.ts index c408943d..c97b1283 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceMutations.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceMutations.ts @@ -1,8 +1,8 @@ import { useMutation } from '@tanstack/react-query'; import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { showAppError } from '../../errors/parseAppError'; -import { resource } from '../../wailsjs/go/models'; -import { Create, Update, Delete } from '../../wailsjs/go/resource/Client'; +import { CreateInput, UpdateInput, DeleteInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; +import { Create, Update, Delete } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type ResourceMutationOptions = { @@ -65,7 +65,7 @@ export const useResourceMutations = ({ pluginID: explicitPluginID }: UseResource pluginID, opts.connectionID, opts.resourceKey, - resource.ClientCreateInput.createFrom({ + CreateInput.createFrom({ input: input.input, namespace: input.namespace ?? opts.namespace ?? '', }) @@ -84,7 +84,7 @@ export const useResourceMutations = ({ pluginID: explicitPluginID }: UseResource pluginID, opts.connectionID, opts.resourceKey, - resource.ClientUpdateInput.createFrom({ + UpdateInput.createFrom({ input: input.input, id: opts.resourceID, namespace: opts.namespace ?? '', @@ -104,7 +104,7 @@ export const useResourceMutations = ({ pluginID: explicitPluginID }: UseResource pluginID, opts.connectionID, opts.resourceKey, - resource.DeleteInput.createFrom({ + DeleteInput.createFrom({ id: opts.resourceID, namespace: opts.namespace ?? '', gracePeriodSeconds: input.gracePeriodSeconds, diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceSearch.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceSearch.ts index b41a8278..a293e15b 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceSearch.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceSearch.ts @@ -1,8 +1,8 @@ import { useQueries } from '@tanstack/react-query'; // Types -import { resource } from '../../wailsjs/go/models'; -import { List } from '../../wailsjs/go/resource/Client'; +import { ListInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; +import { List } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceSearchOptions = { @@ -62,11 +62,12 @@ export const useResourceSearch = ({ const results = useQueries({ queries: searches.map(search => ({ queryKey: getQueryKey(search), - queryFn: async () => List(pluginID, connectionID, search.key, resource.ListInput.createFrom({ + queryFn: async () => List(pluginID, connectionID, search.key, ListInput.createFrom({ order: [{ field: 'name', descending: false }], pagination: { page: 1, pageSize: 200 }, namespaces: search.namespaces, })).then((data) => { + if (!data) return []; console.log(data.result); if (data.result && search.postFilter) { return Object.values(data.result).filter(search.postFilter); diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceType.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceType.ts index 66648997..c742f605 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceType.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceType.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; // Underlying client -import { GetResourceType } from '../../wailsjs/go/resource/Client'; +import { GetResourceType } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceTypesOptions = { diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResourceTypes.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResourceTypes.ts index 72ab06fb..56a860ab 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResourceTypes.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResourceTypes.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; // Underlying client -import { GetResourceTypes } from '../../wailsjs/go/resource/Client'; +import { GetResourceTypes } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseResourceTypesOptions = { diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useResources.ts b/packages/omniviewdev-runtime/src/hooks/resource/useResources.ts index abffb0bd..a3bd2b10 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useResources.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useResources.ts @@ -4,13 +4,13 @@ import { useSnackbar } from '../../hooks/snackbar/useSnackbar'; import { createErrorHandler } from '../../errors/parseAppError'; // Types -import { resource as resourceModels } from '../../wailsjs/go/models'; +import { CreateInput, ListInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; import { WatchState } from '../../types/watch'; import type { WatchStateEvent } from '../../types/watch'; // Underlying client -import { List, Create, SubscribeResource, UnsubscribeResource } from '../../wailsjs/go/resource/Client'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { List, Create, SubscribeResource, UnsubscribeResource } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import { Events } from '@wailsio/runtime'; import { useResolvedPluginId } from '../useResolvedPluginId'; import { useEventBatcher } from './useEventBatcher'; import type { AddPayload, UpdatePayload, DeletePayload } from './useEventBatcher'; @@ -82,12 +82,12 @@ export const useResources = ({ // === Mutations === // const { mutateAsync: create } = useMutation({ - mutationFn: async (opts: { input?: any; namespace?: string }) => Create(pluginID, connectionID, resourceKey, resourceModels.ClientCreateInput.createFrom({ + mutationFn: async (opts: { input?: any; namespace?: string }) => Create(pluginID, connectionID, resourceKey, CreateInput.createFrom({ input: opts.input, namespace: opts.namespace ?? (stableNamespaces.length === 1 ? stableNamespaces[0] : ''), })), onSuccess: async (data) => { - const result = data.result as any; + const result = data?.result as any; let foundID = ''; // Attempt to find an ID based on some common patterns @@ -113,7 +113,7 @@ export const useResources = ({ const resourceQuery = useQuery({ queryKey, - queryFn: async () => List(pluginID, connectionID, resourceKey, resourceModels.ListInput.createFrom({ + queryFn: async () => List(pluginID, connectionID, resourceKey, ListInput.createFrom({ order: [{ field: 'name', descending: false }], pagination: { page: 1, pageSize: 200 }, namespaces: stableNamespaces, @@ -126,13 +126,14 @@ export const useResources = ({ // === Watch State === // const [watchState, setWatchState] = React.useState( - WatchState.IDLE + WatchState.WatchStateIdle ); React.useEffect(() => { - const cancel = EventsOn( + const cancel = Events.On( `${pluginID}/${connectionID}/watch/STATE`, - (event: WatchStateEvent) => { + (ev) => { + const event = ev.data as WatchStateEvent; if (event.resourceKey === resourceKey) { setWatchState(event.state); } @@ -159,17 +160,17 @@ export const useResources = ({ // point forward — no need to re-List after subscribing. SubscribeResource(pluginID, connectionID, resourceKey); - const addCloser = EventsOn( + const addCloser = Events.On( `${pluginID}/${connectionID}/${resourceKey}/ADD`, - (payload: AddPayload) => enqueue({ type: 'ADD', payload }), + (ev) => enqueue({ type: 'ADD', payload: ev.data as AddPayload }), ); - const updateCloser = EventsOn( + const updateCloser = Events.On( `${pluginID}/${connectionID}/${resourceKey}/UPDATE`, - (payload: UpdatePayload) => enqueue({ type: 'UPDATE', payload }), + (ev) => enqueue({ type: 'UPDATE', payload: ev.data as UpdatePayload }), ); - const deleteCloser = EventsOn( + const deleteCloser = Events.On( `${pluginID}/${connectionID}/${resourceKey}/DELETE`, - (payload: DeletePayload) => enqueue({ type: 'DELETE', payload }), + (ev) => enqueue({ type: 'DELETE', payload: ev.data as DeletePayload }), ); return () => { @@ -201,12 +202,12 @@ export const useResources = ({ watchState, /** Whether the watch is currently syncing */ - isSyncing: watchState === WatchState.SYNCING, + isSyncing: watchState === WatchState.WatchStateSyncing, /** Whether the watch has fully synced */ - isSynced: watchState === WatchState.SYNCED, + isSynced: watchState === WatchState.WatchStateSynced, /** Whether the watch encountered an error */ - watchError: watchState === WatchState.ERROR, + watchError: watchState === WatchState.WatchStateError, }; }; diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useStreamAction.ts b/packages/omniviewdev-runtime/src/hooks/resource/useStreamAction.ts index 9dbfda56..887a5a1d 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useStreamAction.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useStreamAction.ts @@ -2,9 +2,9 @@ import React from 'react'; import { useSnackbar } from '../snackbar/useSnackbar'; import { showAppError } from '../../errors/parseAppError'; import { useOperations } from '../operations/useOperations'; -import { resource } from '../../wailsjs/go/models'; -import { StreamAction } from '../../wailsjs/go/resource/Client'; -import { EventsOn, EventsOff } from '../../wailsjs/runtime/runtime'; +import { ActionInput } from '../../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; +import { StreamAction } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import { Events } from '@wailsio/runtime'; import { useResolvedPluginId } from '../useResolvedPluginId'; type UseStreamActionOptions = { @@ -56,7 +56,7 @@ export const useStreamAction = ({ connectionID, resourceKey, actionID, - resource.ActionInput.createFrom({ id, namespace, params }), + ActionInput.createFrom({ id, namespace, params }), ); addOperation({ @@ -71,7 +71,8 @@ export const useStreamAction = ({ }); const eventKey = `action/stream/${operationID}`; - const cancel = EventsOn(eventKey, (event: ActionEvent) => { + const cancel = Events.On(eventKey, (ev) => { + const event = ev.data as ActionEvent; switch (event.type) { case 'progress': { const data = event.data ?? {}; @@ -91,7 +92,7 @@ export const useStreamAction = ({ completedAt: Date.now(), }); showSnackbar((event.data?.message as string) ?? label + ' completed', 'success'); - EventsOff(eventKey); + Events.Off(eventKey); break; case 'error': updateOperation(operationID, { @@ -100,14 +101,14 @@ export const useStreamAction = ({ completedAt: Date.now(), }); showSnackbar((event.data?.message as string) ?? label + ' failed', 'error'); - EventsOff(eventKey); + Events.Off(eventKey); break; } }); cleanupRef.current.push(() => { cancel(); - EventsOff(eventKey); + Events.Off(eventKey); }); return operationID; diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.test.ts b/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.test.ts index 246f8021..6d691a78 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.test.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.test.ts @@ -14,16 +14,18 @@ vi.mock('../useResolvedPluginId', () => ({ // Mock GetWatchState — controlled via mockGetWatchState. let mockGetWatchState: vi.Mock; -vi.mock('../../wailsjs/go/resource/Client', () => ({ +vi.mock('../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice', () => ({ get GetWatchState() { return mockGetWatchState; }, })); -// Mock EventsOn — captures the callback so tests can simulate events. +// Mock Events.On — captures the callback so tests can simulate events. type EventCallback = (...data: any[]) => void; let eventListeners: Map; let mockEventsOn: vi.Mock; -vi.mock('../../wailsjs/runtime/runtime', () => ({ - get EventsOn() { return mockEventsOn; }, +vi.mock('@wailsio/runtime', () => ({ + Events: { + get On() { return mockEventsOn; }, + }, })); // Import after mocks @@ -62,12 +64,16 @@ function emitStateEvent(pluginID: string, connectionID: string, resourceKey: str const topic = `${pluginID}/${connectionID}/watch/STATE`; const listener = eventListeners.get(topic); if (!listener) throw new Error(`No listener for ${topic}`); + // v3: callback receives a WailsEvent with .data listener({ - pluginId: pluginID, - connection: connectionID, - resourceKey, - state, - resourceCount, + name: topic, + data: { + pluginId: pluginID, + connection: connectionID, + resourceKey, + state, + resourceCount, + }, }); } @@ -452,7 +458,7 @@ describe('useWatchState — key changes and disabled state', () => { // Should not fetch. expect(mockGetWatchState).not.toHaveBeenCalled(); - // Should not subscribe. + // Should not subscribe (Events.On should not have been called). expect(mockEventsOn).not.toHaveBeenCalled(); // Should return safe defaults. diff --git a/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.ts b/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.ts index d514daac..b24daf51 100644 --- a/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.ts +++ b/packages/omniviewdev-runtime/src/hooks/resource/useWatchState.ts @@ -2,8 +2,8 @@ import { useCallback, useEffect, useRef } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { produce } from 'immer'; -import { GetWatchState } from '../../wailsjs/go/resource/Client'; -import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { GetWatchState } from '../../bindings/github.com/omniviewdev/omniview/resourcecontrollerservice'; +import { Events } from '@wailsio/runtime'; import { useResolvedPluginId } from '../useResolvedPluginId'; import type { WatchConnectionSummary, @@ -51,8 +51,8 @@ export const useWatchState = ({ let synced = 0; let errors = 0; for (const state of Object.values(draft.resources)) { - if (state === WatchState.SYNCED) synced++; - if (state === WatchState.ERROR || state === WatchState.FAILED) errors++; + if (state === WatchState.WatchStateSynced) synced++; + if (state === WatchState.WatchStateError || state === WatchState.WatchStateFailed) errors++; } draft.syncedCount = synced; draft.errorCount = errors; @@ -65,18 +65,21 @@ export const useWatchState = ({ queryKey, queryFn: async () => { const result = await GetWatchState(pluginID, connectionID); + if (!result) throw new Error('Failed to get watch state: null response'); const resources: Record = {}; let syncedCount = 0; let errorCount = 0; for (const [key, state] of Object.entries(result.resources ?? {})) { + if (state == null) continue; resources[key] = state as WatchState; - if (state === WatchState.SYNCED) syncedCount++; - if (state === WatchState.ERROR) errorCount++; + if (state === WatchState.WatchStateSynced) syncedCount++; + if (state === WatchState.WatchStateError) errorCount++; } const resourceCounts: Record = {}; for (const [key, count] of Object.entries(result.resourceCounts ?? {})) { + if (count == null) continue; resourceCounts[key] = count; } @@ -98,12 +101,12 @@ export const useWatchState = ({ let terminalCount = 0; for (const state of Object.values(data.resources)) { if ( - state === WatchState.SYNCED || - state === WatchState.ERROR || - state === WatchState.STOPPED || - state === WatchState.FAILED || - state === WatchState.FORBIDDEN || - state === WatchState.SKIPPED + state === WatchState.WatchStateSynced || + state === WatchState.WatchStateError || + state === WatchState.WatchStateStopped || + state === WatchState.WatchStateFailed || + state === WatchState.WatchStateForbidden || + state === WatchState.WatchStateSkipped ) { terminalCount++; } @@ -135,9 +138,10 @@ export const useWatchState = ({ dataLoadedRef.current = false; pendingEventsRef.current = []; - const cancel = EventsOn( + const cancel = Events.On( `${pluginID}/${connectionID}/watch/STATE`, - (event: WatchStateEvent) => { + (ev) => { + const event = ev.data as WatchStateEvent; if (!dataLoadedRef.current) { pendingEventsRef.current.push(event); } else { @@ -160,12 +164,12 @@ export const useWatchState = ({ if (data?.resources) { for (const state of Object.values(data.resources)) { if ( - state === WatchState.SYNCED || - state === WatchState.ERROR || - state === WatchState.STOPPED || - state === WatchState.FAILED || - state === WatchState.FORBIDDEN || - state === WatchState.SKIPPED + state === WatchState.WatchStateSynced || + state === WatchState.WatchStateError || + state === WatchState.WatchStateStopped || + state === WatchState.WatchStateFailed || + state === WatchState.WatchStateForbidden || + state === WatchState.WatchStateSkipped ) { terminalCount++; } diff --git a/packages/omniviewdev-runtime/src/models.ts b/packages/omniviewdev-runtime/src/models.ts index a3069bf0..aaabe50c 100644 --- a/packages/omniviewdev-runtime/src/models.ts +++ b/packages/omniviewdev-runtime/src/models.ts @@ -1 +1,69 @@ -export * from './wailsjs/go/models' +export * from './bindings/github.com/omniviewdev/omniview/models'; +export * from './bindings/github.com/omniviewdev/plugin-sdk/pkg/types/models'; +export * from './bindings/github.com/omniviewdev/plugin-sdk/pkg/config/models'; +export * from './bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; + +// exec: selectively re-export to avoid Handler/ActionTargetBuilder collisions +// with logs and metric packages. The UI only uses exec's Handler. +export { + ActionTargetBuilder, + Handler, + Session, + SessionOptions, +} from './bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/exec/models'; + +// logs: re-export everything except Handler and ActionTargetBuilder (collide with exec) +export { + CreateSessionOptions, + LogSession, + LogSessionOptions, + LogSessionStatus, + LogSource, + LogStreamCommand, +} from './bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/logs/models'; + +// metric: re-export everything except Handler (collides with exec) +export { + AggregateValue, + ColorRange, + CurrentValue, + DataPoint, + MetricDescriptor, + MetricResult, + MetricShape, + MetricUnit, + QueryRequest, + QueryResponse, + TimeSeries, +} from './bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/metric/models'; + +// networker: re-export everything except Connection (collides with types) +export { + FindPortForwardSessionRequest, + PortForwardConnectionType, + PortForwardProtocol, + PortForwardSession, + PortForwardSessionEncryption, + PortForwardSessionOptions, + SessionState, +} from './bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/networker/models'; + +export * from './bindings/github.com/omniviewdev/plugin-sdk/settings/models'; + +// devserver: re-export everything except LogEntry (collides with pluginlog) +export { + BuildError, + DevInfoFile, + DevProcessStatus, + DevServerErrorPayload, + DevServerMode, + DevServerState, + LogEntry as DevServerLogEntry, +} from './bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/devserver/models'; + +// pluginlog: only LogEntry remains (re-aliased to avoid collision with devserver) +export { + LogEntry as PluginLogEntry, +} from './bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/pluginlog/models'; + +export * from './bindings/github.com/omniviewdev/omniview/backend/pkg/plugin/ui/models'; diff --git a/packages/omniviewdev-runtime/src/runtime.ts b/packages/omniviewdev-runtime/src/runtime.ts index 16813324..57681dde 100644 --- a/packages/omniviewdev-runtime/src/runtime.ts +++ b/packages/omniviewdev-runtime/src/runtime.ts @@ -1 +1,20 @@ -export * from './wailsjs/runtime/runtime'; +// Import generated event type augmentations and runtime constructors. +// eventdata.d.ts augments @wailsio/runtime's CustomEvents interface so +// Events.On("plugin/state_change", ...) has fully typed ev.data. +// eventcreate.ts registers runtime deserializers for event payloads. +import './bindings/github.com/wailsapp/wails/v3/internal/eventcreate'; +/// + +export { + Application, + Browser, + Call, + Clipboard, + Dialogs, + Events, + Flags, + Screens, + System, + Window, + WML, +} from '@wailsio/runtime'; diff --git a/packages/omniviewdev-runtime/src/types/watch.ts b/packages/omniviewdev-runtime/src/types/watch.ts index 84037706..e81fcbb5 100644 --- a/packages/omniviewdev-runtime/src/types/watch.ts +++ b/packages/omniviewdev-runtime/src/types/watch.ts @@ -1,15 +1,10 @@ /** * Re-export Wails-generated enums from Go source of truth. - * These are generated from AllWatchStates / AllSyncPolicies in - * plugin-sdk/pkg/v1/resource/watch.go via Wails EnumBind. + * These are generated from plugin-sdk/pkg/v1/resource via Wails v3 bindings. */ -import { resource } from '../wailsjs/go/models'; +import { WatchState } from '../bindings/github.com/omniviewdev/plugin-sdk/pkg/v1/resource/models'; -export type WatchState = resource.WatchState; -export const WatchState = resource.WatchState; - -export type SyncPolicy = resource.SyncPolicy; -export const SyncPolicy = resource.SyncPolicy; +export { WatchState }; /** * WatchStateEvent is emitted when a resource's watch state changes. diff --git a/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.test.ts b/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.test.ts index b8107db4..b0ced4c1 100644 --- a/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.test.ts +++ b/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.test.ts @@ -17,9 +17,9 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.SYNCED, - 'core::v1::Service': WatchState.SYNCED, - 'apps::v1::Deployment': WatchState.SYNCED, + 'core::v1::Pod': WatchState.WatchStateSynced, + 'core::v1::Service': WatchState.WatchStateSynced, + 'apps::v1::Deployment': WatchState.WatchStateSynced, }, }; @@ -36,10 +36,10 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.SYNCED, - 'core::v1::Service': WatchState.SYNCING, - 'apps::v1::Deployment': WatchState.ERROR, - 'core::v1::Secret': WatchState.IDLE, + 'core::v1::Pod': WatchState.WatchStateSynced, + 'core::v1::Service': WatchState.WatchStateSyncing, + 'apps::v1::Deployment': WatchState.WatchStateError, + 'core::v1::Secret': WatchState.WatchStateIdle, }, }; @@ -56,8 +56,8 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.SYNCED, - 'core::v1::Service': WatchState.ERROR, + 'core::v1::Pod': WatchState.WatchStateSynced, + 'core::v1::Service': WatchState.WatchStateError, }, }; @@ -73,8 +73,8 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.SYNCED, - 'core::v1::Service': WatchState.STOPPED, + 'core::v1::Pod': WatchState.WatchStateSynced, + 'core::v1::Service': WatchState.WatchStateStopped, }, }; @@ -103,8 +103,8 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.IDLE, - 'core::v1::Service': WatchState.IDLE, + 'core::v1::Pod': WatchState.WatchStateIdle, + 'core::v1::Service': WatchState.WatchStateIdle, }, }; @@ -121,11 +121,11 @@ describe('computeActiveSync', () => { pluginID: 'k8s', connectionID: 'cluster1', states: { - 'core::v1::Pod': WatchState.SYNCED, - 'core::v1::Service': WatchState.SYNCED, - 'resource::v1alpha3::DeviceClass': WatchState.SKIPPED, - 'resource::v1alpha3::ResourceClaim': WatchState.SKIPPED, - 'resource::v1alpha3::ResourceSlice': WatchState.SKIPPED, + 'core::v1::Pod': WatchState.WatchStateSynced, + 'core::v1::Service': WatchState.WatchStateSynced, + 'resource::v1alpha3::DeviceClass': WatchState.WatchStateSkipped, + 'resource::v1alpha3::ResourceClaim': WatchState.WatchStateSkipped, + 'resource::v1alpha3::ResourceSlice': WatchState.WatchStateSkipped, }, }; @@ -251,7 +251,7 @@ describe('trackerKey', () => { pluginId: 'kubernetes', connection: 'cluster-1', resourceKey: 'core::v1::Pod', - state: WatchState.SYNCING, + state: WatchState.WatchStateSyncing, resourceCount: 0, }; expect(trackerKey(event)).toBe('kubernetes/cluster-1'); @@ -265,14 +265,14 @@ describe('updateTracker', () => { pluginId: 'k8s', connection: 'c1', resourceKey: 'core::v1::Pod', - state: WatchState.SYNCING, + state: WatchState.WatchStateSyncing, resourceCount: 0, }; const tracker = updateTracker(trackers, event); expect(tracker.pluginID).toBe('k8s'); expect(tracker.connectionID).toBe('c1'); - expect(tracker.states['core::v1::Pod']).toBe(WatchState.SYNCING); + expect(tracker.states['core::v1::Pod']).toBe(WatchState.WatchStateSyncing); }); it('updates existing tracker state', () => { @@ -280,19 +280,19 @@ describe('updateTracker', () => { trackers.set('k8s/c1', { pluginID: 'k8s', connectionID: 'c1', - states: { 'core::v1::Pod': WatchState.SYNCING }, + states: { 'core::v1::Pod': WatchState.WatchStateSyncing }, }); const event: WatchStateEvent = { pluginId: 'k8s', connection: 'c1', resourceKey: 'core::v1::Pod', - state: WatchState.SYNCED, + state: WatchState.WatchStateSynced, resourceCount: 42, }; const tracker = updateTracker(trackers, event); - expect(tracker.states['core::v1::Pod']).toBe(WatchState.SYNCED); + expect(tracker.states['core::v1::Pod']).toBe(WatchState.WatchStateSynced); }); it('tracks multiple resources per connection', () => { @@ -300,15 +300,15 @@ describe('updateTracker', () => { updateTracker(trackers, { pluginId: 'k8s', connection: 'c1', resourceKey: 'core::v1::Pod', - state: WatchState.SYNCED, resourceCount: 10, + state: WatchState.WatchStateSynced, resourceCount: 10, }); const tracker = updateTracker(trackers, { pluginId: 'k8s', connection: 'c1', resourceKey: 'core::v1::Service', - state: WatchState.SYNCING, resourceCount: 0, + state: WatchState.WatchStateSyncing, resourceCount: 0, }); expect(Object.keys(tracker.states)).toHaveLength(2); - expect(tracker.states['core::v1::Pod']).toBe(WatchState.SYNCED); - expect(tracker.states['core::v1::Service']).toBe(WatchState.SYNCING); + expect(tracker.states['core::v1::Pod']).toBe(WatchState.WatchStateSynced); + expect(tracker.states['core::v1::Service']).toBe(WatchState.WatchStateSyncing); }); }); diff --git a/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.ts b/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.ts index 93ca0d6b..5ff6b238 100644 --- a/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.ts +++ b/packages/omniviewdev-runtime/src/utils/activeSyncAggregator.ts @@ -37,10 +37,10 @@ export function computeActiveSync(tracker: ResourceTracker): ActiveSync { let forbidden = 0; let skipped = 0; for (const s of states) { - if (s === WatchState.SYNCED) synced++; - if (s === WatchState.ERROR || s === WatchState.FAILED) errors++; - if (s === WatchState.FORBIDDEN) forbidden++; - if (s === WatchState.SKIPPED) skipped++; + if (s === WatchState.WatchStateSynced) synced++; + if (s === WatchState.WatchStateError || s === WatchState.WatchStateFailed) errors++; + if (s === WatchState.WatchStateForbidden) forbidden++; + if (s === WatchState.WatchStateSkipped) skipped++; } // Watched resources = total minus skipped @@ -48,8 +48,8 @@ export function computeActiveSync(tracker: ResourceTracker): ActiveSync { // A watched resource is "done" if it has reached a terminal state (excluding SKIPPED) const done = states.filter( - s => s === WatchState.SYNCED || s === WatchState.ERROR || s === WatchState.STOPPED || - s === WatchState.FAILED || s === WatchState.FORBIDDEN + s => s === WatchState.WatchStateSynced || s === WatchState.WatchStateError || s === WatchState.WatchStateStopped || + s === WatchState.WatchStateFailed || s === WatchState.WatchStateForbidden ).length; // Progress based on watched resources only diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.d.ts deleted file mode 100755 index b262e93b..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Delete(arg1:string,arg2:string):Promise; - -export function Get(arg1:string,arg2:string):Promise; - -export function Keys(arg1:string):Promise>; - -export function Set(arg1:string,arg2:string,arg3:any):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.js deleted file mode 100755 index a30c6784..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/data/Client.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Delete(arg1, arg2) { - return window['go']['data']['Client']['Delete'](arg1, arg2); -} - -export function Get(arg1, arg2) { - return window['go']['data']['Client']['Get'](arg1, arg2); -} - -export function Keys(arg1) { - return window['go']['data']['Client']['Keys'](arg1); -} - -export function Set(arg1, arg2, arg3) { - return window['go']['data']['Client']['Set'](arg1, arg2, arg3); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.d.ts deleted file mode 100755 index 9dba9dab..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {devserver} from '../models'; -import {context} from '../models'; - -export function GetDevServerLogs(arg1:string,arg2:number):Promise>; - -export function GetDevServerState(arg1:string):Promise; - -export function GetExternalPluginInfo(arg1:string):Promise; - -export function Initialize(arg1:context.Context):Promise; - -export function IsManaged(arg1:string):Promise; - -export function ListDevServerStates():Promise>; - -export function RebuildPlugin(arg1:string):Promise; - -export function RestartDevServer(arg1:string):Promise; - -export function Shutdown():Promise; - -export function StartDevServer(arg1:string):Promise; - -export function StartDevServerForPath(arg1:string,arg2:string):Promise; - -export function StopDevServer(arg1:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.js b/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.js deleted file mode 100755 index a54b4a6c..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/devserver/DevServerManager.js +++ /dev/null @@ -1,51 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetDevServerLogs(arg1, arg2) { - return window['go']['devserver']['DevServerManager']['GetDevServerLogs'](arg1, arg2); -} - -export function GetDevServerState(arg1) { - return window['go']['devserver']['DevServerManager']['GetDevServerState'](arg1); -} - -export function GetExternalPluginInfo(arg1) { - return window['go']['devserver']['DevServerManager']['GetExternalPluginInfo'](arg1); -} - -export function Initialize(arg1) { - return window['go']['devserver']['DevServerManager']['Initialize'](arg1); -} - -export function IsManaged(arg1) { - return window['go']['devserver']['DevServerManager']['IsManaged'](arg1); -} - -export function ListDevServerStates() { - return window['go']['devserver']['DevServerManager']['ListDevServerStates'](); -} - -export function RebuildPlugin(arg1) { - return window['go']['devserver']['DevServerManager']['RebuildPlugin'](arg1); -} - -export function RestartDevServer(arg1) { - return window['go']['devserver']['DevServerManager']['RestartDevServer'](arg1); -} - -export function Shutdown() { - return window['go']['devserver']['DevServerManager']['Shutdown'](); -} - -export function StartDevServer(arg1) { - return window['go']['devserver']['DevServerManager']['StartDevServer'](arg1); -} - -export function StartDevServerForPath(arg1, arg2) { - return window['go']['devserver']['DevServerManager']['StartDevServerForPath'](arg1, arg2); -} - -export function StopDevServer(arg1) { - return window['go']['devserver']['DevServerManager']['StopDevServer'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.d.ts deleted file mode 100755 index 395242a0..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Debug(arg1:string,arg2:Record):Promise; - -export function Error(arg1:string,arg2:Record):Promise; - -export function Info(arg1:string,arg2:Record):Promise; - -export function Log(arg1:string,arg2:string,arg3:Record):Promise; - -export function ReadLog(arg1:string):Promise; - -export function StartTail(arg1:string):Promise; - -export function StopTail(arg1:string):Promise; - -export function Warn(arg1:string,arg2:Record):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.js b/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.js deleted file mode 100755 index f6bf1729..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/diagnostics/DiagnosticsClient.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Debug(arg1, arg2) { - return window['go']['diagnostics']['DiagnosticsClient']['Debug'](arg1, arg2); -} - -export function Error(arg1, arg2) { - return window['go']['diagnostics']['DiagnosticsClient']['Error'](arg1, arg2); -} - -export function Info(arg1, arg2) { - return window['go']['diagnostics']['DiagnosticsClient']['Info'](arg1, arg2); -} - -export function Log(arg1, arg2, arg3) { - return window['go']['diagnostics']['DiagnosticsClient']['Log'](arg1, arg2, arg3); -} - -export function ReadLog(arg1) { - return window['go']['diagnostics']['DiagnosticsClient']['ReadLog'](arg1); -} - -export function StartTail(arg1) { - return window['go']['diagnostics']['DiagnosticsClient']['StartTail'](arg1); -} - -export function StopTail(arg1) { - return window['go']['diagnostics']['DiagnosticsClient']['StopTail'](arg1); -} - -export function Warn(arg1, arg2) { - return window['go']['diagnostics']['DiagnosticsClient']['Warn'](arg1, arg2); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.d.ts deleted file mode 100755 index a207f41f..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {exec} from '../models'; - -export function AttachSession(arg1:string):Promise; - -export function CloseSession(arg1:string):Promise; - -export function CreateSession(arg1:string,arg2:string,arg3:exec.SessionOptions):Promise; - -export function CreateTerminal(arg1:exec.CreateTerminalOptions):Promise; - -export function DetachSession(arg1:string):Promise; - -export function GetHandler(arg1:string,arg2:string):Promise; - -export function GetHandlers():Promise>>; - -export function GetPluginHandlers(arg1:string):Promise>; - -export function GetSession(arg1:string):Promise; - -export function ListPlugins():Promise>; - -export function ListSessions():Promise>; - -export function ResizeSession(arg1:string,arg2:number,arg3:number):Promise; - -export function WriteSession(arg1:string,arg2:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.js deleted file mode 100755 index 7777619c..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/exec/Client.js +++ /dev/null @@ -1,55 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function AttachSession(arg1) { - return window['go']['exec']['Client']['AttachSession'](arg1); -} - -export function CloseSession(arg1) { - return window['go']['exec']['Client']['CloseSession'](arg1); -} - -export function CreateSession(arg1, arg2, arg3) { - return window['go']['exec']['Client']['CreateSession'](arg1, arg2, arg3); -} - -export function CreateTerminal(arg1) { - return window['go']['exec']['Client']['CreateTerminal'](arg1); -} - -export function DetachSession(arg1) { - return window['go']['exec']['Client']['DetachSession'](arg1); -} - -export function GetHandler(arg1, arg2) { - return window['go']['exec']['Client']['GetHandler'](arg1, arg2); -} - -export function GetHandlers() { - return window['go']['exec']['Client']['GetHandlers'](); -} - -export function GetPluginHandlers(arg1) { - return window['go']['exec']['Client']['GetPluginHandlers'](arg1); -} - -export function GetSession(arg1) { - return window['go']['exec']['Client']['GetSession'](arg1); -} - -export function ListPlugins() { - return window['go']['exec']['Client']['ListPlugins'](); -} - -export function ListSessions() { - return window['go']['exec']['Client']['ListSessions'](); -} - -export function ResizeSession(arg1, arg2, arg3) { - return window['go']['exec']['Client']['ResizeSession'](arg1, arg2, arg3); -} - -export function WriteSession(arg1, arg2) { - return window['go']['exec']['Client']['WriteSession'](arg1, arg2); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.d.ts deleted file mode 100755 index 5cc69cc2..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {logs} from '../models'; - -export function CloseSession(arg1:string):Promise; - -export function CreateSession(arg1:string,arg2:string,arg3:logs.CreateSessionOptions):Promise; - -export function GetSession(arg1:string):Promise; - -export function GetSupportedResources(arg1:string):Promise>; - -export function ListSessions():Promise>; - -export function PauseSession(arg1:string):Promise; - -export function ResumeSession(arg1:string):Promise; - -export function UpdateSessionOptions(arg1:string,arg2:logs.LogSessionOptions):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.js deleted file mode 100755 index 8c432fdf..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/logs/Client.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function CloseSession(arg1) { - return window['go']['logs']['Client']['CloseSession'](arg1); -} - -export function CreateSession(arg1, arg2, arg3) { - return window['go']['logs']['Client']['CreateSession'](arg1, arg2, arg3); -} - -export function GetSession(arg1) { - return window['go']['logs']['Client']['GetSession'](arg1); -} - -export function GetSupportedResources(arg1) { - return window['go']['logs']['Client']['GetSupportedResources'](arg1); -} - -export function ListSessions() { - return window['go']['logs']['Client']['ListSessions'](); -} - -export function PauseSession(arg1) { - return window['go']['logs']['Client']['PauseSession'](arg1); -} - -export function ResumeSession(arg1) { - return window['go']['logs']['Client']['ResumeSession'](arg1); -} - -export function UpdateSessionOptions(arg1, arg2) { - return window['go']['logs']['Client']['UpdateSessionOptions'](arg1, arg2); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/main/App.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/main/App.d.ts deleted file mode 100755 index 73601cfd..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/main/App.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {main} from '../models'; - -export function GetOperatingSystem():Promise; - -export function OpenFileSelectionDialog(arg1:main.FileDialogOptions):Promise>; - -export function SaveFileDialog(arg1:main.FileDialogOptions):Promise; - -export function WriteFileContent(arg1:string,arg2:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/main/App.js b/packages/omniviewdev-runtime/src/wailsjs/go/main/App.js deleted file mode 100755 index a7df25fd..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/main/App.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetOperatingSystem() { - return window['go']['main']['App']['GetOperatingSystem'](); -} - -export function OpenFileSelectionDialog(arg1) { - return window['go']['main']['App']['OpenFileSelectionDialog'](arg1); -} - -export function SaveFileDialog(arg1) { - return window['go']['main']['App']['SaveFileDialog'](arg1); -} - -export function WriteFileContent(arg1, arg2) { - return window['go']['main']['App']['WriteFileContent'](arg1, arg2); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.d.ts deleted file mode 100755 index 6b465f54..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {metric} from '../models'; -import {time} from '../models'; - -export function GetProviders():Promise>; - -export function GetProvidersForResource(arg1:string):Promise>; - -export function Query(arg1:string,arg2:string,arg3:metric.QueryRequest):Promise; - -export function QueryAll(arg1:string,arg2:string,arg3:string,arg4:string,arg5:Record,arg6:Array,arg7:metric.MetricShape,arg8:time.Time,arg9:time.Time,arg10:time.Duration):Promise>; - -export function Subscribe(arg1:string,arg2:string,arg3:metric.SubscribeRequest):Promise; - -export function Unsubscribe(arg1:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.js deleted file mode 100755 index ba94d799..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/metric/Client.js +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetProviders() { - return window['go']['metric']['Client']['GetProviders'](); -} - -export function GetProvidersForResource(arg1) { - return window['go']['metric']['Client']['GetProvidersForResource'](arg1); -} - -export function Query(arg1, arg2, arg3) { - return window['go']['metric']['Client']['Query'](arg1, arg2, arg3); -} - -export function QueryAll(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) { - return window['go']['metric']['Client']['QueryAll'](arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); -} - -export function Subscribe(arg1, arg2, arg3) { - return window['go']['metric']['Client']['Subscribe'](arg1, arg2, arg3); -} - -export function Unsubscribe(arg1) { - return window['go']['metric']['Client']['Unsubscribe'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/models.ts b/packages/omniviewdev-runtime/src/wailsjs/go/models.ts deleted file mode 100755 index a3189c5c..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/models.ts +++ /dev/null @@ -1,3012 +0,0 @@ -export namespace config { - - export class PluginAuthor { - name: string; - email: string; - url: string; - - static createFrom(source: any = {}) { - return new PluginAuthor(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.email = source["email"]; - this.url = source["url"]; - } - } - export class PluginResourceComponent { - name: string; - plugin: string; - area: string; - resources: string[]; - extension: string; - - static createFrom(source: any = {}) { - return new PluginResourceComponent(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.plugin = source["plugin"]; - this.area = source["area"]; - this.resources = source["resources"]; - this.extension = source["extension"]; - } - } - export class PluginComponents { - resource: PluginResourceComponent[]; - - static createFrom(source: any = {}) { - return new PluginComponents(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource = this.convertValues(source["resource"], PluginResourceComponent); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class PluginMaintainer { - name: string; - email: string; - - static createFrom(source: any = {}) { - return new PluginMaintainer(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.name = source["name"]; - this.email = source["email"]; - } - } - export class PluginThemeColors { - primary: string; - secondary: string; - tertiary: string; - - static createFrom(source: any = {}) { - return new PluginThemeColors(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.primary = source["primary"]; - this.secondary = source["secondary"]; - this.tertiary = source["tertiary"]; - } - } - export class PluginTheme { - colors: PluginThemeColors; - - static createFrom(source: any = {}) { - return new PluginTheme(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.colors = this.convertValues(source["colors"], PluginThemeColors); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class PluginMeta { - id: string; - version: string; - name: string; - icon: string; - icon_url: string; - description: string; - repository: string; - website: string; - category: string; - license: string; - author?: PluginAuthor; - maintainers: PluginMaintainer[]; - tags: string[]; - dependencies: string[]; - capabilities: string[]; - theme: PluginTheme; - components: PluginComponents; - schema_version: number; - sdk_protocol_version: number; - - static createFrom(source: any = {}) { - return new PluginMeta(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.version = source["version"]; - this.name = source["name"]; - this.icon = source["icon"]; - this.icon_url = source["icon_url"]; - this.description = source["description"]; - this.repository = source["repository"]; - this.website = source["website"]; - this.category = source["category"]; - this.license = source["license"]; - this.author = this.convertValues(source["author"], PluginAuthor); - this.maintainers = this.convertValues(source["maintainers"], PluginMaintainer); - this.tags = source["tags"]; - this.dependencies = source["dependencies"]; - this.capabilities = source["capabilities"]; - this.theme = this.convertValues(source["theme"], PluginTheme); - this.components = this.convertValues(source["components"], PluginComponents); - this.schema_version = source["schema_version"]; - this.sdk_protocol_version = source["sdk_protocol_version"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - - -} - -export namespace devserver { - - export class DevInfoFile { - pid: number; - protocol: string; - protocolVersion: number; - addr: string; - vitePort?: number; - pluginId?: string; - version?: string; - startedAt?: string; - - static createFrom(source: any = {}) { - return new DevInfoFile(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.pid = source["pid"]; - this.protocol = source["protocol"]; - this.protocolVersion = source["protocolVersion"]; - this.addr = source["addr"]; - this.vitePort = source["vitePort"]; - this.pluginId = source["pluginId"]; - this.version = source["version"]; - this.startedAt = source["startedAt"]; - } - } - export class DevServerManager { - - - static createFrom(source: any = {}) { - return new DevServerManager(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - - } - } - export class DevServerState { - pluginID: string; - mode: string; - devPath: string; - vitePort: number; - viteURL: string; - viteStatus: string; - goStatus: string; - lastBuildDuration: number; - lastBuildTime: string; - lastError: string; - grpcConnected: boolean; - - static createFrom(source: any = {}) { - return new DevServerState(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.pluginID = source["pluginID"]; - this.mode = source["mode"]; - this.devPath = source["devPath"]; - this.vitePort = source["vitePort"]; - this.viteURL = source["viteURL"]; - this.viteStatus = source["viteStatus"]; - this.goStatus = source["goStatus"]; - this.lastBuildDuration = source["lastBuildDuration"]; - this.lastBuildTime = source["lastBuildTime"]; - this.lastError = source["lastError"]; - this.grpcConnected = source["grpcConnected"]; - } - } - export class LogEntry { - timestamp: string; - source: string; - level: string; - message: string; - pluginID: string; - - static createFrom(source: any = {}) { - return new LogEntry(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.timestamp = source["timestamp"]; - this.source = source["source"]; - this.level = source["level"]; - this.message = source["message"]; - this.pluginID = source["pluginID"]; - } - } - -} - -export namespace exec { - - export class ActionTargetBuilder { - label: string; - label_selector: string; - paths: string[]; - selectors: Record; - - static createFrom(source: any = {}) { - return new ActionTargetBuilder(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.label = source["label"]; - this.label_selector = source["label_selector"]; - this.paths = source["paths"]; - this.selectors = source["selectors"]; - } - } - export class Session { - created_at: time.Time; - labels: Record; - params: Record; - id: string; - command: string[]; - attached: boolean; - - static createFrom(source: any = {}) { - return new Session(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.created_at = this.convertValues(source["created_at"], time.Time); - this.labels = source["labels"]; - this.params = source["params"]; - this.id = source["id"]; - this.command = source["command"]; - this.attached = source["attached"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class AttachSessionResult { - session?: Session; - buffer: string; - - static createFrom(source: any = {}) { - return new AttachSessionResult(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.session = this.convertValues(source["session"], Session); - this.buffer = source["buffer"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class CreateTerminalOptions { - labels: Record; - command: string[]; - - static createFrom(source: any = {}) { - return new CreateTerminalOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.labels = source["labels"]; - this.command = source["command"]; - } - } - export class Handler { - plugin: string; - resource: string; - target_builder: ActionTargetBuilder; - default_command: string[]; - - static createFrom(source: any = {}) { - return new Handler(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin = source["plugin"]; - this.resource = source["resource"]; - this.target_builder = this.convertValues(source["target_builder"], ActionTargetBuilder); - this.default_command = source["default_command"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - export class SessionOptions { - params: Record; - labels: Record; - id: string; - resource_plugin: string; - resource_key: string; - resource_data: Record; - command: string[]; - tty: boolean; - - static createFrom(source: any = {}) { - return new SessionOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.params = source["params"]; - this.labels = source["labels"]; - this.id = source["id"]; - this.resource_plugin = source["resource_plugin"]; - this.resource_key = source["resource_key"]; - this.resource_data = source["resource_data"]; - this.command = source["command"]; - this.tty = source["tty"]; - } - } - -} - -export namespace logs { - - export class ActionTargetBuilder { - label: string; - label_selector: string; - paths: string[]; - selectors: Record; - - static createFrom(source: any = {}) { - return new ActionTargetBuilder(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.label = source["label"]; - this.label_selector = source["label_selector"]; - this.paths = source["paths"]; - this.selectors = source["selectors"]; - } - } - export class LogSessionOptions { - target: string; - follow: boolean; - include_previous: boolean; - include_timestamps: boolean; - tail_lines: number; - since_seconds: number; - since_time?: time.Time; - limit_bytes: number; - include_source_events: boolean; - params: Record; - - static createFrom(source: any = {}) { - return new LogSessionOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.target = source["target"]; - this.follow = source["follow"]; - this.include_previous = source["include_previous"]; - this.include_timestamps = source["include_timestamps"]; - this.tail_lines = source["tail_lines"]; - this.since_seconds = source["since_seconds"]; - this.since_time = this.convertValues(source["since_time"], time.Time); - this.limit_bytes = source["limit_bytes"]; - this.include_source_events = source["include_source_events"]; - this.params = source["params"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class CreateSessionOptions { - resource_key: string; - resource_id: string; - resource_data: Record; - options: LogSessionOptions; - - static createFrom(source: any = {}) { - return new CreateSessionOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource_key = source["resource_key"]; - this.resource_id = source["resource_id"]; - this.resource_data = source["resource_data"]; - this.options = this.convertValues(source["options"], LogSessionOptions); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Handler { - plugin: string; - resource: string; - target_builder: ActionTargetBuilder; - - static createFrom(source: any = {}) { - return new Handler(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin = source["plugin"]; - this.resource = source["resource"]; - this.target_builder = this.convertValues(source["target_builder"], ActionTargetBuilder); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class LogSource { - id: string; - labels: Record; - - static createFrom(source: any = {}) { - return new LogSource(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.labels = source["labels"]; - } - } - export class LogSession { - id: string; - plugin_id: string; - connection_id: string; - resource_key: string; - resource_id: string; - options: LogSessionOptions; - status: number; - active_sources: LogSource[]; - created_at: time.Time; - - static createFrom(source: any = {}) { - return new LogSession(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.plugin_id = source["plugin_id"]; - this.connection_id = source["connection_id"]; - this.resource_key = source["resource_key"]; - this.resource_id = source["resource_id"]; - this.options = this.convertValues(source["options"], LogSessionOptions); - this.status = source["status"]; - this.active_sources = this.convertValues(source["active_sources"], LogSource); - this.created_at = this.convertValues(source["created_at"], time.Time); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - -} - -export namespace main { - - export class FileFilter { - displayName: string; - pattern: string; - - static createFrom(source: any = {}) { - return new FileFilter(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.displayName = source["displayName"]; - this.pattern = source["pattern"]; - } - } - export class FileDialogOptions { - defaultDirectory: string; - defaultFilename: string; - title: string; - filters: FileFilter[]; - showHiddenFiles: boolean; - canCreateDirectories: boolean; - resolvesAliases: boolean; - treatPackagesAsDirectories: boolean; - - static createFrom(source: any = {}) { - return new FileDialogOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.defaultDirectory = source["defaultDirectory"]; - this.defaultFilename = source["defaultFilename"]; - this.title = source["title"]; - this.filters = this.convertValues(source["filters"], FileFilter); - this.showHiddenFiles = source["showHiddenFiles"]; - this.canCreateDirectories = source["canCreateDirectories"]; - this.resolvesAliases = source["resolvesAliases"]; - this.treatPackagesAsDirectories = source["treatPackagesAsDirectories"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} - -export namespace metric { - - export class AggregateValue { - metric_id: string; - min: number; - max: number; - avg: number; - sum: number; - p50: number; - p90: number; - p99: number; - count: number; - window: number; - labels: Record; - - static createFrom(source: any = {}) { - return new AggregateValue(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.metric_id = source["metric_id"]; - this.min = source["min"]; - this.max = source["max"]; - this.avg = source["avg"]; - this.sum = source["sum"]; - this.p50 = source["p50"]; - this.p90 = source["p90"]; - this.p99 = source["p99"]; - this.count = source["count"]; - this.window = source["window"]; - this.labels = source["labels"]; - } - } - export class ColorRange { - min: number; - max: number; - color: string; - - static createFrom(source: any = {}) { - return new ColorRange(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.min = source["min"]; - this.max = source["max"]; - this.color = source["color"]; - } - } - export class CurrentValue { - metric_id: string; - value: number; - timestamp: time.Time; - labels: Record; - - static createFrom(source: any = {}) { - return new CurrentValue(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.metric_id = source["metric_id"]; - this.value = source["value"]; - this.timestamp = this.convertValues(source["timestamp"], time.Time); - this.labels = source["labels"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class DataPoint { - timestamp: time.Time; - value: number; - labels: Record; - - static createFrom(source: any = {}) { - return new DataPoint(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.timestamp = this.convertValues(source["timestamp"], time.Time); - this.value = source["value"]; - this.labels = source["labels"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class MetricDescriptor { - id: string; - name: string; - unit: number; - icon: string; - color_ranges: ColorRange[]; - format_string: string; - supported_shapes: number[]; - chart_group: string; - - static createFrom(source: any = {}) { - return new MetricDescriptor(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.name = source["name"]; - this.unit = source["unit"]; - this.icon = source["icon"]; - this.color_ranges = this.convertValues(source["color_ranges"], ColorRange); - this.format_string = source["format_string"]; - this.supported_shapes = source["supported_shapes"]; - this.chart_group = source["chart_group"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Handler { - resource: string; - metrics: MetricDescriptor[]; - - static createFrom(source: any = {}) { - return new Handler(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource = source["resource"]; - this.metrics = this.convertValues(source["metrics"], MetricDescriptor); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - export class MetricProviderSummary { - plugin_id: string; - provider_id: string; - name: string; - icon: string; - description: string; - handlers: Handler[]; - - static createFrom(source: any = {}) { - return new MetricProviderSummary(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin_id = source["plugin_id"]; - this.provider_id = source["provider_id"]; - this.name = source["name"]; - this.icon = source["icon"]; - this.description = source["description"]; - this.handlers = this.convertValues(source["handlers"], Handler); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class TimeSeries { - metric_id: string; - data_points: DataPoint[]; - labels: Record; - - static createFrom(source: any = {}) { - return new TimeSeries(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.metric_id = source["metric_id"]; - this.data_points = this.convertValues(source["data_points"], DataPoint); - this.labels = source["labels"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class MetricResult { - time_series?: TimeSeries; - current_value?: CurrentValue; - aggregate_value?: AggregateValue; - - static createFrom(source: any = {}) { - return new MetricResult(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.time_series = this.convertValues(source["time_series"], TimeSeries); - this.current_value = this.convertValues(source["current_value"], CurrentValue); - this.aggregate_value = this.convertValues(source["aggregate_value"], AggregateValue); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class QueryRequest { - resource_key: string; - resource_id: string; - resource_namespace: string; - resource_data: Record; - metric_ids: string[]; - shape: number; - start_time: time.Time; - end_time: time.Time; - step: number; - params: Record; - - static createFrom(source: any = {}) { - return new QueryRequest(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource_key = source["resource_key"]; - this.resource_id = source["resource_id"]; - this.resource_namespace = source["resource_namespace"]; - this.resource_data = source["resource_data"]; - this.metric_ids = source["metric_ids"]; - this.shape = source["shape"]; - this.start_time = this.convertValues(source["start_time"], time.Time); - this.end_time = this.convertValues(source["end_time"], time.Time); - this.step = source["step"]; - this.params = source["params"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class QueryResponse { - success: boolean; - results: MetricResult[]; - error: string; - - static createFrom(source: any = {}) { - return new QueryResponse(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.success = source["success"]; - this.results = this.convertValues(source["results"], MetricResult); - this.error = source["error"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class SubscribeRequest { - resource_key: string; - resource_id: string; - resource_namespace: string; - resource_data: Record; - metric_ids: string[]; - interval: number; - - static createFrom(source: any = {}) { - return new SubscribeRequest(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource_key = source["resource_key"]; - this.resource_id = source["resource_id"]; - this.resource_namespace = source["resource_namespace"]; - this.resource_data = source["resource_data"]; - this.metric_ids = source["metric_ids"]; - this.interval = source["interval"]; - } - } - -} - -export namespace networker { - - export class FindPortForwardSessionRequest { - resource_id: string; - connection_id: string; - - static createFrom(source: any = {}) { - return new FindPortForwardSessionRequest(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resource_id = source["resource_id"]; - this.connection_id = source["connection_id"]; - } - } - export class PortForwardSessionEncryption { - algorithm: string; - key: string; - enabled: boolean; - - static createFrom(source: any = {}) { - return new PortForwardSessionEncryption(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.algorithm = source["algorithm"]; - this.key = source["key"]; - this.enabled = source["enabled"]; - } - } - export class PortForwardSession { - created_at: time.Time; - updated_at: time.Time; - connection: any; - labels: Record; - id: string; - protocol: string; - state: string; - connection_type: string; - encryption: PortForwardSessionEncryption; - local_port: number; - remote_port: number; - - static createFrom(source: any = {}) { - return new PortForwardSession(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.created_at = this.convertValues(source["created_at"], time.Time); - this.updated_at = this.convertValues(source["updated_at"], time.Time); - this.connection = source["connection"]; - this.labels = source["labels"]; - this.id = source["id"]; - this.protocol = source["protocol"]; - this.state = source["state"]; - this.connection_type = source["connection_type"]; - this.encryption = this.convertValues(source["encryption"], PortForwardSessionEncryption); - this.local_port = source["local_port"]; - this.remote_port = source["remote_port"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - export class PortForwardSessionOptions { - connection: any; - labels: Record; - params: Record; - protocol: string; - connection_type: string; - encryption: PortForwardSessionEncryption; - local_port: number; - remote_port: number; - - static createFrom(source: any = {}) { - return new PortForwardSessionOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.connection = source["connection"]; - this.labels = source["labels"]; - this.params = source["params"]; - this.protocol = source["protocol"]; - this.connection_type = source["connection_type"]; - this.encryption = this.convertValues(source["encryption"], PortForwardSessionEncryption); - this.local_port = source["local_port"]; - this.remote_port = source["remote_port"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} - -export namespace plugin { - - export class LoadPluginOptions { - DevMode: boolean; - DevModePath: string; - ExistingState?: types.PluginStateRecord; - - static createFrom(source: any = {}) { - return new LoadPluginOptions(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.DevMode = source["DevMode"]; - this.DevModePath = source["DevModePath"]; - this.ExistingState = this.convertValues(source["ExistingState"], types.PluginStateRecord); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} - -export namespace pluginlog { - - export class LogEntry { - timestamp: string; - pluginID: string; - source: string; - level: string; - message: string; - - static createFrom(source: any = {}) { - return new LogEntry(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.timestamp = source["timestamp"]; - this.pluginID = source["pluginID"]; - this.source = source["source"]; - this.level = source["level"]; - this.message = source["message"]; - } - } - export class Manager { - - - static createFrom(source: any = {}) { - return new Manager(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - - } - } - export class PluginLogStream { - - - static createFrom(source: any = {}) { - return new PluginLogStream(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - - } - } - -} - -export namespace registry { - - export class AvailablePlugin { - id: string; - name: string; - description: string; - icon_url: string; - category: string; - tags: string[]; - license: string; - official: boolean; - featured: boolean; - download_count: number; - average_rating: number; - review_count: number; - repository: string; - url: string; - publisher_name: string; - installed: boolean; - installed_version: string; - latest_version: string; - update_available: boolean; - - static createFrom(source: any = {}) { - return new AvailablePlugin(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.name = source["name"]; - this.description = source["description"]; - this.icon_url = source["icon_url"]; - this.category = source["category"]; - this.tags = source["tags"]; - this.license = source["license"]; - this.official = source["official"]; - this.featured = source["featured"]; - this.download_count = source["download_count"]; - this.average_rating = source["average_rating"]; - this.review_count = source["review_count"]; - this.repository = source["repository"]; - this.url = source["url"]; - this.publisher_name = source["publisher_name"]; - this.installed = source["installed"]; - this.installed_version = source["installed_version"]; - this.latest_version = source["latest_version"]; - this.update_available = source["update_available"]; - } - } - export class DailyStat { - date: string; - count: number; - - static createFrom(source: any = {}) { - return new DailyStat(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.date = source["date"]; - this.count = source["count"]; - } - } - export class DownloadStats { - total: number; - last_month: number; - last_week: number; - daily_stats: DailyStat[]; - - static createFrom(source: any = {}) { - return new DownloadStats(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.total = source["total"]; - this.last_month = source["last_month"]; - this.last_week = source["last_week"]; - this.daily_stats = this.convertValues(source["daily_stats"], DailyStat); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Review { - id: string; - user_id: number; - rating: number; - title: string; - body: string; - created_at: string; - - static createFrom(source: any = {}) { - return new Review(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.user_id = source["user_id"]; - this.rating = source["rating"]; - this.title = source["title"]; - this.body = source["body"]; - this.created_at = source["created_at"]; - } - } - export class VersionInfo { - version: string; - description: string; - changelog: string; - min_ide_version: string; - max_ide_version: string; - capabilities: string[]; - created_at: string; - - static createFrom(source: any = {}) { - return new VersionInfo(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.version = source["version"]; - this.description = source["description"]; - this.changelog = source["changelog"]; - this.min_ide_version = source["min_ide_version"]; - this.max_ide_version = source["max_ide_version"]; - this.capabilities = source["capabilities"]; - this.created_at = source["created_at"]; - } - } - -} - -export namespace resource { - - export enum WatchState { - IDLE = 0, - SYNCING = 1, - SYNCED = 2, - ERROR = 3, - STOPPED = 4, - FAILED = 5, - FORBIDDEN = 6, - SKIPPED = 7, - } - export enum SyncPolicy { - ON_CONNECT = 0, - ON_FIRST_QUERY = 1, - NEVER = 2, - } - export class SchemaProperty { - type: string; - description?: string; - enum?: string[]; - default?: any; - minimum?: number; - maximum?: number; - properties?: Record; - required?: string[]; - - static createFrom(source: any = {}) { - return new SchemaProperty(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.type = source["type"]; - this.description = source["description"]; - this.enum = source["enum"]; - this.default = source["default"]; - this.minimum = source["minimum"]; - this.maximum = source["maximum"]; - this.properties = this.convertValues(source["properties"], SchemaProperty, true); - this.required = source["required"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Schema { - properties?: Record; - required?: string[]; - - static createFrom(source: any = {}) { - return new Schema(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.properties = this.convertValues(source["properties"], SchemaProperty, true); - this.required = source["required"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ActionDescriptor { - id: string; - label: string; - description: string; - icon: string; - scope: string; - streaming: boolean; - paramsSchema?: Schema; - outputSchema?: Schema; - dangerous?: boolean; - - static createFrom(source: any = {}) { - return new ActionDescriptor(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.label = source["label"]; - this.description = source["description"]; - this.icon = source["icon"]; - this.scope = source["scope"]; - this.streaming = source["streaming"]; - this.paramsSchema = this.convertValues(source["paramsSchema"], Schema); - this.outputSchema = this.convertValues(source["outputSchema"], Schema); - this.dangerous = source["dangerous"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ActionInput { - id: string; - namespace: string; - params: Record; - - static createFrom(source: any = {}) { - return new ActionInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.namespace = source["namespace"]; - this.params = source["params"]; - } - } - export class ActionResult { - success: boolean; - data: Record; - message: string; - - static createFrom(source: any = {}) { - return new ActionResult(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.success = source["success"]; - this.data = source["data"]; - this.message = source["message"]; - } - } - export class ClientCreateInput { - input: any; - namespace: string; - - static createFrom(source: any = {}) { - return new ClientCreateInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.input = source["input"]; - this.namespace = source["namespace"]; - } - } - export class ClientListResult { - result: any[]; - success: boolean; - totalCount: number; - nextCursor?: string; - - static createFrom(source: any = {}) { - return new ClientListResult(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.result = source["result"]; - this.success = source["success"]; - this.totalCount = source["totalCount"]; - this.nextCursor = source["nextCursor"]; - } - } - export class ClientResult { - result: any; - success: boolean; - - static createFrom(source: any = {}) { - return new ClientResult(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.result = source["result"]; - this.success = source["success"]; - } - } - export class ClientUpdateInput { - input: any; - id: string; - namespace: string; - - static createFrom(source: any = {}) { - return new ClientUpdateInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.input = source["input"]; - this.id = source["id"]; - this.namespace = source["namespace"]; - } - } - export class ResourceLink { - idAccessor: string; - namespaceAccessor: string; - namespaced: boolean; - resourceKey: string; - keyAccessor: string; - keyMap: Record; - detailExtractors: Record; - displayId: boolean; - - static createFrom(source: any = {}) { - return new ResourceLink(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.idAccessor = source["idAccessor"]; - this.namespaceAccessor = source["namespaceAccessor"]; - this.namespaced = source["namespaced"]; - this.resourceKey = source["resourceKey"]; - this.keyAccessor = source["keyAccessor"]; - this.keyMap = source["keyMap"]; - this.detailExtractors = source["detailExtractors"]; - this.displayId = source["displayId"]; - } - } - export class ColumnDefinition { - id: string; - header: string; - accessor: string; - accessorPriority?: string; - colorMap?: Record; - color?: string; - align?: string; - hidden?: boolean; - width?: number; - formatter?: string; - component?: string; - componentParams?: any; - resourceLink?: ResourceLink; - valueMap?: Record; - - static createFrom(source: any = {}) { - return new ColumnDefinition(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.header = source["header"]; - this.accessor = source["accessor"]; - this.accessorPriority = source["accessorPriority"]; - this.colorMap = source["colorMap"]; - this.color = source["color"]; - this.align = source["align"]; - this.hidden = source["hidden"]; - this.width = source["width"]; - this.formatter = source["formatter"]; - this.component = source["component"]; - this.componentParams = source["componentParams"]; - this.resourceLink = this.convertValues(source["resourceLink"], ResourceLink); - this.valueMap = source["valueMap"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class DeleteInput { - id: string; - namespace: string; - gracePeriodSeconds?: number; - - static createFrom(source: any = {}) { - return new DeleteInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.namespace = source["namespace"]; - this.gracePeriodSeconds = source["gracePeriodSeconds"]; - } - } - export class EditorSchema { - resourceKey: string; - fileMatch: string; - uri: string; - url?: string; - content?: number[]; - language: string; - - static createFrom(source: any = {}) { - return new EditorSchema(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.resourceKey = source["resourceKey"]; - this.fileMatch = source["fileMatch"]; - this.uri = source["uri"]; - this.url = source["url"]; - this.content = source["content"]; - this.language = source["language"]; - } - } - export class FilterPredicate { - field: string; - operator: string; - value?: any; - - static createFrom(source: any = {}) { - return new FilterPredicate(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.field = source["field"]; - this.operator = source["operator"]; - this.value = source["value"]; - } - } - export class FilterExpression { - logic?: string; - predicates?: FilterPredicate[]; - groups?: FilterExpression[]; - - static createFrom(source: any = {}) { - return new FilterExpression(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.logic = source["logic"]; - this.predicates = this.convertValues(source["predicates"], FilterPredicate); - this.groups = this.convertValues(source["groups"], FilterExpression); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class FilterField { - path: string; - displayName: string; - description: string; - type: string; - operators: string[]; - allowedValues?: string[]; - required?: boolean; - - static createFrom(source: any = {}) { - return new FilterField(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.path = source["path"]; - this.displayName = source["displayName"]; - this.description = source["description"]; - this.type = source["type"]; - this.operators = source["operators"]; - this.allowedValues = source["allowedValues"]; - this.required = source["required"]; - } - } - - export class PaginationParams { - page: number; - pageSize: number; - cursor?: string; - - static createFrom(source: any = {}) { - return new PaginationParams(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.page = source["page"]; - this.pageSize = source["pageSize"]; - this.cursor = source["cursor"]; - } - } - export class OrderField { - field: string; - descending: boolean; - - static createFrom(source: any = {}) { - return new OrderField(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.field = source["field"]; - this.descending = source["descending"]; - } - } - export class FindInput { - filters?: FilterExpression; - textQuery?: string; - namespaces: string[]; - order: OrderField[]; - pagination: PaginationParams; - - static createFrom(source: any = {}) { - return new FindInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.filters = this.convertValues(source["filters"], FilterExpression); - this.textQuery = source["textQuery"]; - this.namespaces = source["namespaces"]; - this.order = this.convertValues(source["order"], OrderField); - this.pagination = this.convertValues(source["pagination"], PaginationParams); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class GetInput { - id: string; - namespace: string; - - static createFrom(source: any = {}) { - return new GetInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.namespace = source["namespace"]; - } - } - export class HealthCondition { - type: string; - status: string; - reason?: string; - message?: string; - lastProbeTime?: time.Time; - lastTransitionTime?: time.Time; - - static createFrom(source: any = {}) { - return new HealthCondition(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.type = source["type"]; - this.status = source["status"]; - this.reason = source["reason"]; - this.message = source["message"]; - this.lastProbeTime = this.convertValues(source["lastProbeTime"], time.Time); - this.lastTransitionTime = this.convertValues(source["lastTransitionTime"], time.Time); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ListInput { - namespaces: string[]; - order: OrderField[]; - pagination: PaginationParams; - - static createFrom(source: any = {}) { - return new ListInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.namespaces = source["namespaces"]; - this.order = this.convertValues(source["order"], OrderField); - this.pagination = this.convertValues(source["pagination"], PaginationParams); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - - export class RelationshipExtractor { - method: string; - fieldPath?: string; - labelSelector?: Record; - - static createFrom(source: any = {}) { - return new RelationshipExtractor(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.method = source["method"]; - this.fieldPath = source["fieldPath"]; - this.labelSelector = source["labelSelector"]; - } - } - export class RelationshipDescriptor { - type: string; - targetResourceKey: string; - label: string; - inverseLabel?: string; - cardinality?: string; - direction?: string; - extractor?: RelationshipExtractor; - targetNamespaced?: boolean; - - static createFrom(source: any = {}) { - return new RelationshipDescriptor(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.type = source["type"]; - this.targetResourceKey = source["targetResourceKey"]; - this.label = source["label"]; - this.inverseLabel = source["inverseLabel"]; - this.cardinality = source["cardinality"]; - this.direction = source["direction"]; - this.extractor = this.convertValues(source["extractor"], RelationshipExtractor); - this.targetNamespaced = source["targetNamespaced"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - export class ResourceRef { - pluginId?: string; - connectionId: string; - resourceKey: string; - id: string; - namespace?: string; - displayName?: string; - - static createFrom(source: any = {}) { - return new ResourceRef(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.pluginId = source["pluginId"]; - this.connectionId = source["connectionId"]; - this.resourceKey = source["resourceKey"]; - this.id = source["id"]; - this.namespace = source["namespace"]; - this.displayName = source["displayName"]; - } - } - export class ResolvedRelationship { - descriptor: RelationshipDescriptor; - targets: ResourceRef[]; - - static createFrom(source: any = {}) { - return new ResolvedRelationship(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.descriptor = this.convertValues(source["descriptor"], RelationshipDescriptor); - this.targets = this.convertValues(source["targets"], ResourceRef); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ScaleHint { - level: string; - expectedCount?: number; - defaultPageSize?: number; - - static createFrom(source: any = {}) { - return new ScaleHint(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.level = source["level"]; - this.expectedCount = source["expectedCount"]; - this.defaultPageSize = source["defaultPageSize"]; - } - } - export class ResourceCapabilities { - canGet: boolean; - canList: boolean; - canFind: boolean; - canCreate: boolean; - canUpdate: boolean; - canDelete: boolean; - watchable: boolean; - filterable: boolean; - searchable: boolean; - hasActions: boolean; - hasSchema: boolean; - namespaceScoped: boolean; - hasRelationships: boolean; - hasHealth: boolean; - hasEvents: boolean; - scaleHint?: ScaleHint; - - static createFrom(source: any = {}) { - return new ResourceCapabilities(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.canGet = source["canGet"]; - this.canList = source["canList"]; - this.canFind = source["canFind"]; - this.canCreate = source["canCreate"]; - this.canUpdate = source["canUpdate"]; - this.canDelete = source["canDelete"]; - this.watchable = source["watchable"]; - this.filterable = source["filterable"]; - this.searchable = source["searchable"]; - this.hasActions = source["hasActions"]; - this.hasSchema = source["hasSchema"]; - this.namespaceScoped = source["namespaceScoped"]; - this.hasRelationships = source["hasRelationships"]; - this.hasHealth = source["hasHealth"]; - this.hasEvents = source["hasEvents"]; - this.scaleHint = this.convertValues(source["scaleHint"], ScaleHint); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ResourceDefinition { - id_accessor: string; - namespace_accessor: string; - memoizer_accessor: string; - columnDefs: ColumnDefinition[]; - - static createFrom(source: any = {}) { - return new ResourceDefinition(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id_accessor = source["id_accessor"]; - this.namespace_accessor = source["namespace_accessor"]; - this.memoizer_accessor = source["memoizer_accessor"]; - this.columnDefs = this.convertValues(source["columnDefs"], ColumnDefinition); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ResourceEvent { - type: string; - reason: string; - message: string; - source?: string; - count?: number; - firstSeen: time.Time; - lastSeen: time.Time; - - static createFrom(source: any = {}) { - return new ResourceEvent(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.type = source["type"]; - this.reason = source["reason"]; - this.message = source["message"]; - this.source = source["source"]; - this.count = source["count"]; - this.firstSeen = this.convertValues(source["firstSeen"], time.Time); - this.lastSeen = this.convertValues(source["lastSeen"], time.Time); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ResourceGroup { - id: string; - name: string; - description: string; - icon: string; - resources: Record>; - - static createFrom(source: any = {}) { - return new ResourceGroup(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.name = source["name"]; - this.description = source["description"]; - this.icon = source["icon"]; - this.resources = this.convertValues(source["resources"], Array, true); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class ResourceHealth { - status: string; - reason?: string; - message?: string; - since?: time.Time; - conditions?: HealthCondition[]; - - static createFrom(source: any = {}) { - return new ResourceHealth(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.status = source["status"]; - this.reason = source["reason"]; - this.message = source["message"]; - this.since = this.convertValues(source["since"], time.Time); - this.conditions = this.convertValues(source["conditions"], HealthCondition); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - export class ResourceMeta { - group: string; - version: string; - kind: string; - label: string; - icon: string; - description: string; - category: string; - - static createFrom(source: any = {}) { - return new ResourceMeta(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.group = source["group"]; - this.version = source["version"]; - this.kind = source["kind"]; - this.label = source["label"]; - this.icon = source["icon"]; - this.description = source["description"]; - this.category = source["category"]; - } - } - - - - - export class WatchScope { - partitions?: string[]; - - static createFrom(source: any = {}) { - return new WatchScope(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.partitions = source["partitions"]; - } - } - export class WatchConnectionSummary { - connectionId: string; - resources: Record; - resourceCounts: Record; - scope?: WatchScope; - - static createFrom(source: any = {}) { - return new WatchConnectionSummary(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.connectionId = source["connectionId"]; - this.resources = source["resources"]; - this.resourceCounts = source["resourceCounts"]; - this.scope = this.convertValues(source["scope"], WatchScope); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} - -export namespace settings { - - export enum SettingType { - TEXT = "text", - SELECT = "select", - MULTISELECT = "multiselect", - INTEGER = "integer", - FLOAT = "float", - TOGGLE = "toggle", - COLOR = "color", - DATETIME = "datetime", - PASSWORD = "password", - } - export class SettingFileSelection { - enabled: boolean; - allowFolders: boolean; - extensions: string[]; - multiple: boolean; - relative: boolean; - defaultPath: string; - - static createFrom(source: any = {}) { - return new SettingFileSelection(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.enabled = source["enabled"]; - this.allowFolders = source["allowFolders"]; - this.extensions = source["extensions"]; - this.multiple = source["multiple"]; - this.relative = source["relative"]; - this.defaultPath = source["defaultPath"]; - } - } - export class SettingOption { - label: string; - description: string; - value: any; - - static createFrom(source: any = {}) { - return new SettingOption(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.label = source["label"]; - this.description = source["description"]; - this.value = source["value"]; - } - } - export class Setting { - id: string; - label: string; - description: string; - type: SettingType; - value: any; - default: any; - options: SettingOption[]; - fileSelection?: SettingFileSelection; - sensitive: boolean; - devOnly: boolean; - - static createFrom(source: any = {}) { - return new Setting(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.label = source["label"]; - this.description = source["description"]; - this.type = source["type"]; - this.value = source["value"]; - this.default = source["default"]; - this.options = this.convertValues(source["options"], SettingOption); - this.fileSelection = this.convertValues(source["fileSelection"], SettingFileSelection); - this.sensitive = source["sensitive"]; - this.devOnly = source["devOnly"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Category { - settings: Record; - id: string; - label: string; - description: string; - icon: string; - - static createFrom(source: any = {}) { - return new Category(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.settings = this.convertValues(source["settings"], Setting, true); - this.id = source["id"]; - this.label = source["label"]; - this.description = source["description"]; - this.icon = source["icon"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - - -} - -export namespace time { - - export class Time { - - - static createFrom(source: any = {}) { - return new Time(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - - } - } - -} - -export namespace types { - - export enum ConnectionStatusCode { - UNKNOWN = "UNKNOWN", - CONNECTED = "CONNECTED", - DISCONNECTED = "DISCONNECTED", - PENDING = "PENDING", - FAILED = "FAILED", - ERROR = "ERROR", - UNAUTHORIZED = "UNAUTHORIZED", - FORBIDDEN = "FORBIDDEN", - BAD_REQUEST = "BAD_REQUEST", - NOT_FOUND = "NOT_FOUND", - TIMEOUT = "TIMEOUT", - UNAVAILABLE = "UNAVAILABLE", - REQUEST_ENTITY_TOO_LARGE = "REQUEST_ENTITY_TOO_LARGE", - } - export class ConnectionAutoConnect { - enabled: boolean; - triggers: string[]; - retry: string; - - static createFrom(source: any = {}) { - return new ConnectionAutoConnect(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.enabled = source["enabled"]; - this.triggers = source["triggers"]; - this.retry = source["retry"]; - } - } - export class ConnectionLifecycle { - auto_connect?: ConnectionAutoConnect; - - static createFrom(source: any = {}) { - return new ConnectionLifecycle(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.auto_connect = this.convertValues(source["auto_connect"], ConnectionAutoConnect); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class Connection { - last_refresh: time.Time; - data: Record; - labels: Record; - lifecycle: ConnectionLifecycle; - id: string; - uid: string; - name: string; - description: string; - avatar: string; - expiry_time: number; - Client: any; - - static createFrom(source: any = {}) { - return new Connection(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.last_refresh = this.convertValues(source["last_refresh"], time.Time); - this.data = source["data"]; - this.labels = source["labels"]; - this.lifecycle = this.convertValues(source["lifecycle"], ConnectionLifecycle); - this.id = source["id"]; - this.uid = source["uid"]; - this.name = source["name"]; - this.description = source["description"]; - this.avatar = source["avatar"]; - this.expiry_time = source["expiry_time"]; - this.Client = source["Client"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - - - export class ConnectionStatus { - connection?: Connection; - status: ConnectionStatusCode; - error: string; - details: string; - - static createFrom(source: any = {}) { - return new ConnectionStatus(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.connection = this.convertValues(source["connection"], Connection); - this.status = source["status"]; - this.error = source["error"]; - this.details = source["details"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class PluginInfo { - id: string; - metadata: config.PluginMeta; - phase: string; - enabled: boolean; - devMode: boolean; - devPath?: string; - capabilities: string[]; - lastError?: string; - - static createFrom(source: any = {}) { - return new PluginInfo(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.metadata = this.convertValues(source["metadata"], config.PluginMeta); - this.phase = source["phase"]; - this.enabled = source["enabled"]; - this.devMode = source["devMode"]; - this.devPath = source["devPath"]; - this.capabilities = source["capabilities"]; - this.lastError = source["lastError"]; - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - export class PluginStateRecord { - id: string; - phase: string; - metadata: config.PluginMeta; - enabled: boolean; - devMode: boolean; - devPath?: string; - lastError?: string; - errorCount: number; - installedAt: time.Time; - - static createFrom(source: any = {}) { - return new PluginStateRecord(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.id = source["id"]; - this.phase = source["phase"]; - this.metadata = this.convertValues(source["metadata"], config.PluginMeta); - this.enabled = source["enabled"]; - this.devMode = source["devMode"]; - this.devPath = source["devPath"]; - this.lastError = source["lastError"]; - this.errorCount = source["errorCount"]; - this.installedAt = this.convertValues(source["installedAt"], time.Time); - } - - convertValues(a: any, classs: any, asMap: boolean = false): any { - if (!a) { - return a; - } - if (a.slice && a.map) { - return (a as any[]).map(elem => this.convertValues(elem, classs)); - } else if ("object" === typeof a) { - if (asMap) { - for (const key of Object.keys(a)) { - a[key] = new classs(a[key]); - } - return a; - } - return new classs(a); - } - return a; - } - } - -} - -export namespace ui { - - export class GetPluginComponentsInput { - plugin: string; - - static createFrom(source: any = {}) { - return new GetPluginComponentsInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin = source["plugin"]; - } - } - export class GetResourceAreaComponentInput { - plugin: string; - resource: string; - area: string; - - static createFrom(source: any = {}) { - return new GetResourceAreaComponentInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin = source["plugin"]; - this.resource = source["resource"]; - this.area = source["area"]; - } - } - export class GetResourceComponentsInput { - plugin: string; - resource: string; - - static createFrom(source: any = {}) { - return new GetResourceComponentsInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.plugin = source["plugin"]; - this.resource = source["resource"]; - } - } - export class ResourceComponent { - owner: string; - name: string; - plugin: string; - resource: string; - area: string; - extension: string; - - static createFrom(source: any = {}) { - return new ResourceComponent(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.owner = source["owner"]; - this.name = source["name"]; - this.plugin = source["plugin"]; - this.resource = source["resource"]; - this.area = source["area"]; - this.extension = source["extension"]; - } - } - -} - -export namespace utils { - - export class GetLanguageInput { - filename: string; - contents: string; - - static createFrom(source: any = {}) { - return new GetLanguageInput(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) source = JSON.parse(source); - this.filename = source["filename"]; - this.contents = source["contents"]; - } - } - -} - diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.d.ts deleted file mode 100755 index fe961346..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {networker} from '../models'; - -export function ClosePortForwardSession(arg1:string):Promise; - -export function FindPortForwardSessions(arg1:string,arg2:string,arg3:networker.FindPortForwardSessionRequest):Promise>; - -export function GetPortForwardSession(arg1:string):Promise; - -export function GetSupportedPortForwardTargets(arg1:string):Promise>; - -export function ListAllPortForwardSessions():Promise>; - -export function ListPortForwardSessions(arg1:string,arg2:string):Promise>; - -export function StartResourcePortForwardingSession(arg1:string,arg2:string,arg3:networker.PortForwardSessionOptions):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.js deleted file mode 100755 index 8c3b94cd..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/networker/Client.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function ClosePortForwardSession(arg1) { - return window['go']['networker']['Client']['ClosePortForwardSession'](arg1); -} - -export function FindPortForwardSessions(arg1, arg2, arg3) { - return window['go']['networker']['Client']['FindPortForwardSessions'](arg1, arg2, arg3); -} - -export function GetPortForwardSession(arg1) { - return window['go']['networker']['Client']['GetPortForwardSession'](arg1); -} - -export function GetSupportedPortForwardTargets(arg1) { - return window['go']['networker']['Client']['GetSupportedPortForwardTargets'](arg1); -} - -export function ListAllPortForwardSessions() { - return window['go']['networker']['Client']['ListAllPortForwardSessions'](); -} - -export function ListPortForwardSessions(arg1, arg2) { - return window['go']['networker']['Client']['ListPortForwardSessions'](arg1, arg2); -} - -export function StartResourcePortForwardingSession(arg1, arg2, arg3) { - return window['go']['networker']['Client']['StartResourcePortForwardingSession'](arg1, arg2, arg3); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.d.ts deleted file mode 100755 index 2815654f..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {types} from '../models'; -import {registry} from '../models'; -import {config} from '../models'; -import {context} from '../models'; -import {plugin} from '../models'; -import {devserver} from '../models'; -import {pluginlog} from '../models'; - -export function GetPlugin(arg1:string):Promise; - -export function GetPluginDownloadStats(arg1:string):Promise; - -export function GetPluginMeta(arg1:string):Promise; - -export function GetPluginReadme(arg1:string):Promise; - -export function GetPluginReleaseHistory(arg1:string):Promise>; - -export function GetPluginReviews(arg1:string,arg2:number):Promise>; - -export function GetPluginVersions(arg1:string):Promise>; - -export function HandlePluginCrash(arg1:string):Promise; - -export function Initialize(arg1:context.Context):Promise; - -export function InstallFromPathPrompt():Promise; - -export function InstallInDevMode():Promise; - -export function InstallPluginFromPath(arg1:string):Promise; - -export function InstallPluginVersion(arg1:string,arg2:string):Promise; - -export function ListAvailablePlugins():Promise>; - -export function ListPluginMetas():Promise>; - -export function ListPlugins():Promise>; - -export function LoadPlugin(arg1:string,arg2:plugin.LoadPluginOptions):Promise; - -export function ReloadPlugin(arg1:string):Promise; - -export function RetryFailedPlugin(arg1:string):Promise; - -export function Run(arg1:context.Context):Promise; - -export function SearchPlugins(arg1:string,arg2:string,arg3:string):Promise>; - -export function SetDevServerChecker(arg1:plugin.DevServerChecker):Promise; - -export function SetDevServerManager(arg1:devserver.DevServerManager):Promise; - -export function SetPluginLogManager(arg1:pluginlog.Manager):Promise; - -export function Shutdown():Promise; - -export function UninstallPlugin(arg1:string):Promise; - -export function UnloadPlugin(arg1:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.js b/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.js deleted file mode 100755 index 27d05082..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/plugin/pluginManager.js +++ /dev/null @@ -1,111 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetPlugin(arg1) { - return window['go']['plugin']['pluginManager']['GetPlugin'](arg1); -} - -export function GetPluginDownloadStats(arg1) { - return window['go']['plugin']['pluginManager']['GetPluginDownloadStats'](arg1); -} - -export function GetPluginMeta(arg1) { - return window['go']['plugin']['pluginManager']['GetPluginMeta'](arg1); -} - -export function GetPluginReadme(arg1) { - return window['go']['plugin']['pluginManager']['GetPluginReadme'](arg1); -} - -export function GetPluginReleaseHistory(arg1) { - return window['go']['plugin']['pluginManager']['GetPluginReleaseHistory'](arg1); -} - -export function GetPluginReviews(arg1, arg2) { - return window['go']['plugin']['pluginManager']['GetPluginReviews'](arg1, arg2); -} - -export function GetPluginVersions(arg1) { - return window['go']['plugin']['pluginManager']['GetPluginVersions'](arg1); -} - -export function HandlePluginCrash(arg1) { - return window['go']['plugin']['pluginManager']['HandlePluginCrash'](arg1); -} - -export function Initialize(arg1) { - return window['go']['plugin']['pluginManager']['Initialize'](arg1); -} - -export function InstallFromPathPrompt() { - return window['go']['plugin']['pluginManager']['InstallFromPathPrompt'](); -} - -export function InstallInDevMode() { - return window['go']['plugin']['pluginManager']['InstallInDevMode'](); -} - -export function InstallPluginFromPath(arg1) { - return window['go']['plugin']['pluginManager']['InstallPluginFromPath'](arg1); -} - -export function InstallPluginVersion(arg1, arg2) { - return window['go']['plugin']['pluginManager']['InstallPluginVersion'](arg1, arg2); -} - -export function ListAvailablePlugins() { - return window['go']['plugin']['pluginManager']['ListAvailablePlugins'](); -} - -export function ListPluginMetas() { - return window['go']['plugin']['pluginManager']['ListPluginMetas'](); -} - -export function ListPlugins() { - return window['go']['plugin']['pluginManager']['ListPlugins'](); -} - -export function LoadPlugin(arg1, arg2) { - return window['go']['plugin']['pluginManager']['LoadPlugin'](arg1, arg2); -} - -export function ReloadPlugin(arg1) { - return window['go']['plugin']['pluginManager']['ReloadPlugin'](arg1); -} - -export function RetryFailedPlugin(arg1) { - return window['go']['plugin']['pluginManager']['RetryFailedPlugin'](arg1); -} - -export function Run(arg1) { - return window['go']['plugin']['pluginManager']['Run'](arg1); -} - -export function SearchPlugins(arg1, arg2, arg3) { - return window['go']['plugin']['pluginManager']['SearchPlugins'](arg1, arg2, arg3); -} - -export function SetDevServerChecker(arg1) { - return window['go']['plugin']['pluginManager']['SetDevServerChecker'](arg1); -} - -export function SetDevServerManager(arg1) { - return window['go']['plugin']['pluginManager']['SetDevServerManager'](arg1); -} - -export function SetPluginLogManager(arg1) { - return window['go']['plugin']['pluginManager']['SetPluginLogManager'](arg1); -} - -export function Shutdown() { - return window['go']['plugin']['pluginManager']['Shutdown'](); -} - -export function UninstallPlugin(arg1) { - return window['go']['plugin']['pluginManager']['UninstallPlugin'](arg1); -} - -export function UnloadPlugin(arg1) { - return window['go']['plugin']['pluginManager']['UnloadPlugin'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.d.ts deleted file mode 100755 index b3f90a35..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {pluginlog} from '../models'; - -export function Close():Promise; - -export function GetLogs(arg1:string,arg2:number):Promise>; - -export function ListStreams():Promise>; - -export function LogDir():Promise; - -export function OnEmit(arg1:pluginlog.EmitFunc):Promise; - -export function SearchLogs(arg1:string,arg2:string):Promise>; - -export function Stream(arg1:string):Promise; - -export function Subscribe(arg1:string):Promise; - -export function Unsubscribe(arg1:string):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.js b/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.js deleted file mode 100755 index 8e138c11..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/pluginlog/Manager.js +++ /dev/null @@ -1,39 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function Close() { - return window['go']['pluginlog']['Manager']['Close'](); -} - -export function GetLogs(arg1, arg2) { - return window['go']['pluginlog']['Manager']['GetLogs'](arg1, arg2); -} - -export function ListStreams() { - return window['go']['pluginlog']['Manager']['ListStreams'](); -} - -export function LogDir() { - return window['go']['pluginlog']['Manager']['LogDir'](); -} - -export function OnEmit(arg1) { - return window['go']['pluginlog']['Manager']['OnEmit'](arg1); -} - -export function SearchLogs(arg1, arg2) { - return window['go']['pluginlog']['Manager']['SearchLogs'](arg1, arg2); -} - -export function Stream(arg1) { - return window['go']['pluginlog']['Manager']['Stream'](arg1); -} - -export function Subscribe(arg1) { - return window['go']['pluginlog']['Manager']['Subscribe'](arg1); -} - -export function Unsubscribe(arg1) { - return window['go']['pluginlog']['Manager']['Unsubscribe'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.d.ts deleted file mode 100755 index af29498f..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.d.ts +++ /dev/null @@ -1,94 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {types} from '../models'; -import {resource} from '../models'; - -export function AddConnection(arg1:string,arg2:types.Connection):Promise; - -export function CheckConnection(arg1:string,arg2:string):Promise; - -export function Create(arg1:string,arg2:string,arg3:string,arg4:resource.ClientCreateInput):Promise; - -export function Delete(arg1:string,arg2:string,arg3:string,arg4:resource.DeleteInput):Promise; - -export function EnsureResourceWatch(arg1:string,arg2:string,arg3:string):Promise; - -export function ExecuteAction(arg1:string,arg2:string,arg3:string,arg4:string,arg5:resource.ActionInput):Promise; - -export function Find(arg1:string,arg2:string,arg3:string,arg4:resource.FindInput):Promise; - -export function Get(arg1:string,arg2:string,arg3:string,arg4:resource.GetInput):Promise; - -export function GetActions(arg1:string,arg2:string,arg3:string):Promise>; - -export function GetAllConnectionStates():Promise>>; - -export function GetConnection(arg1:string,arg2:string):Promise; - -export function GetConnectionNamespaces(arg1:string,arg2:string):Promise>; - -export function GetEditorSchemas(arg1:string,arg2:string):Promise>; - -export function GetFilterFields(arg1:string,arg2:string,arg3:string):Promise>; - -export function GetHealth(arg1:string,arg2:string,arg3:string,arg4:any):Promise; - -export function GetRelationships(arg1:string,arg2:string):Promise>; - -export function GetResourceCapabilities(arg1:string,arg2:string):Promise; - -export function GetResourceDefinition(arg1:string,arg2:string):Promise; - -export function GetResourceEvents(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string,arg6:number):Promise>; - -export function GetResourceGroup(arg1:string,arg2:string):Promise; - -export function GetResourceGroups(arg1:string,arg2:string):Promise>; - -export function GetResourceSchema(arg1:string,arg2:string,arg3:string):Promise; - -export function GetResourceType(arg1:string,arg2:string):Promise; - -export function GetResourceTypes(arg1:string,arg2:string):Promise>; - -export function GetWatchState(arg1:string,arg2:string):Promise; - -export function HasResourceType(arg1:string,arg2:string):Promise; - -export function IsResourceWatchRunning(arg1:string,arg2:string,arg3:string):Promise; - -export function List(arg1:string,arg2:string,arg3:string,arg4:resource.ListInput):Promise; - -export function ListAllConnections():Promise>>; - -export function ListConnections(arg1:string):Promise>; - -export function ListPlugins():Promise>; - -export function LoadConnections(arg1:string):Promise>; - -export function RemoveConnection(arg1:string,arg2:string):Promise; - -export function ResolveRelationships(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string):Promise>; - -export function RestartResourceWatch(arg1:string,arg2:string,arg3:string):Promise; - -export function StartConnection(arg1:string,arg2:string):Promise; - -export function StartConnectionWatch(arg1:string,arg2:string):Promise; - -export function StopConnection(arg1:string,arg2:string):Promise; - -export function StopConnectionWatch(arg1:string,arg2:string):Promise; - -export function StopResourceWatch(arg1:string,arg2:string,arg3:string):Promise; - -export function StreamAction(arg1:string,arg2:string,arg3:string,arg4:string,arg5:resource.ActionInput):Promise; - -export function SubscribeResource(arg1:string,arg2:string,arg3:string):Promise; - -export function UnsubscribeResource(arg1:string,arg2:string,arg3:string):Promise; - -export function Update(arg1:string,arg2:string,arg3:string,arg4:resource.ClientUpdateInput):Promise; - -export function UpdateConnection(arg1:string,arg2:types.Connection):Promise; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.js deleted file mode 100755 index 3b504e4f..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/resource/Client.js +++ /dev/null @@ -1,183 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function AddConnection(arg1, arg2) { - return window['go']['resource']['Client']['AddConnection'](arg1, arg2); -} - -export function CheckConnection(arg1, arg2) { - return window['go']['resource']['Client']['CheckConnection'](arg1, arg2); -} - -export function Create(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['Create'](arg1, arg2, arg3, arg4); -} - -export function Delete(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['Delete'](arg1, arg2, arg3, arg4); -} - -export function EnsureResourceWatch(arg1, arg2, arg3) { - return window['go']['resource']['Client']['EnsureResourceWatch'](arg1, arg2, arg3); -} - -export function ExecuteAction(arg1, arg2, arg3, arg4, arg5) { - return window['go']['resource']['Client']['ExecuteAction'](arg1, arg2, arg3, arg4, arg5); -} - -export function Find(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['Find'](arg1, arg2, arg3, arg4); -} - -export function Get(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['Get'](arg1, arg2, arg3, arg4); -} - -export function GetActions(arg1, arg2, arg3) { - return window['go']['resource']['Client']['GetActions'](arg1, arg2, arg3); -} - -export function GetAllConnectionStates() { - return window['go']['resource']['Client']['GetAllConnectionStates'](); -} - -export function GetConnection(arg1, arg2) { - return window['go']['resource']['Client']['GetConnection'](arg1, arg2); -} - -export function GetConnectionNamespaces(arg1, arg2) { - return window['go']['resource']['Client']['GetConnectionNamespaces'](arg1, arg2); -} - -export function GetEditorSchemas(arg1, arg2) { - return window['go']['resource']['Client']['GetEditorSchemas'](arg1, arg2); -} - -export function GetFilterFields(arg1, arg2, arg3) { - return window['go']['resource']['Client']['GetFilterFields'](arg1, arg2, arg3); -} - -export function GetHealth(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['GetHealth'](arg1, arg2, arg3, arg4); -} - -export function GetRelationships(arg1, arg2) { - return window['go']['resource']['Client']['GetRelationships'](arg1, arg2); -} - -export function GetResourceCapabilities(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceCapabilities'](arg1, arg2); -} - -export function GetResourceDefinition(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceDefinition'](arg1, arg2); -} - -export function GetResourceEvents(arg1, arg2, arg3, arg4, arg5, arg6) { - return window['go']['resource']['Client']['GetResourceEvents'](arg1, arg2, arg3, arg4, arg5, arg6); -} - -export function GetResourceGroup(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceGroup'](arg1, arg2); -} - -export function GetResourceGroups(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceGroups'](arg1, arg2); -} - -export function GetResourceSchema(arg1, arg2, arg3) { - return window['go']['resource']['Client']['GetResourceSchema'](arg1, arg2, arg3); -} - -export function GetResourceType(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceType'](arg1, arg2); -} - -export function GetResourceTypes(arg1, arg2) { - return window['go']['resource']['Client']['GetResourceTypes'](arg1, arg2); -} - -export function GetWatchState(arg1, arg2) { - return window['go']['resource']['Client']['GetWatchState'](arg1, arg2); -} - -export function HasResourceType(arg1, arg2) { - return window['go']['resource']['Client']['HasResourceType'](arg1, arg2); -} - -export function IsResourceWatchRunning(arg1, arg2, arg3) { - return window['go']['resource']['Client']['IsResourceWatchRunning'](arg1, arg2, arg3); -} - -export function List(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['List'](arg1, arg2, arg3, arg4); -} - -export function ListAllConnections() { - return window['go']['resource']['Client']['ListAllConnections'](); -} - -export function ListConnections(arg1) { - return window['go']['resource']['Client']['ListConnections'](arg1); -} - -export function ListPlugins() { - return window['go']['resource']['Client']['ListPlugins'](); -} - -export function LoadConnections(arg1) { - return window['go']['resource']['Client']['LoadConnections'](arg1); -} - -export function RemoveConnection(arg1, arg2) { - return window['go']['resource']['Client']['RemoveConnection'](arg1, arg2); -} - -export function ResolveRelationships(arg1, arg2, arg3, arg4, arg5) { - return window['go']['resource']['Client']['ResolveRelationships'](arg1, arg2, arg3, arg4, arg5); -} - -export function RestartResourceWatch(arg1, arg2, arg3) { - return window['go']['resource']['Client']['RestartResourceWatch'](arg1, arg2, arg3); -} - -export function StartConnection(arg1, arg2) { - return window['go']['resource']['Client']['StartConnection'](arg1, arg2); -} - -export function StartConnectionWatch(arg1, arg2) { - return window['go']['resource']['Client']['StartConnectionWatch'](arg1, arg2); -} - -export function StopConnection(arg1, arg2) { - return window['go']['resource']['Client']['StopConnection'](arg1, arg2); -} - -export function StopConnectionWatch(arg1, arg2) { - return window['go']['resource']['Client']['StopConnectionWatch'](arg1, arg2); -} - -export function StopResourceWatch(arg1, arg2, arg3) { - return window['go']['resource']['Client']['StopResourceWatch'](arg1, arg2, arg3); -} - -export function StreamAction(arg1, arg2, arg3, arg4, arg5) { - return window['go']['resource']['Client']['StreamAction'](arg1, arg2, arg3, arg4, arg5); -} - -export function SubscribeResource(arg1, arg2, arg3) { - return window['go']['resource']['Client']['SubscribeResource'](arg1, arg2, arg3); -} - -export function UnsubscribeResource(arg1, arg2, arg3) { - return window['go']['resource']['Client']['UnsubscribeResource'](arg1, arg2, arg3); -} - -export function Update(arg1, arg2, arg3, arg4) { - return window['go']['resource']['Client']['Update'](arg1, arg2, arg3, arg4); -} - -export function UpdateConnection(arg1, arg2) { - return window['go']['resource']['Client']['UpdateConnection'](arg1, arg2); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.d.ts deleted file mode 100755 index 8d802f7b..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {settings} from '../models'; - -export function GetSetting(arg1:string,arg2:string):Promise; - -export function ListPlugins():Promise>; - -export function ListSettings(arg1:string):Promise>; - -export function PluginValues(arg1:string):Promise>; - -export function SetSetting(arg1:string,arg2:string,arg3:any):Promise; - -export function SetSettings(arg1:string,arg2:Record):Promise; - -export function Values():Promise>; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.js deleted file mode 100755 index 4d3161f4..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/settings/Client.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetSetting(arg1, arg2) { - return window['go']['settings']['Client']['GetSetting'](arg1, arg2); -} - -export function ListPlugins() { - return window['go']['settings']['Client']['ListPlugins'](); -} - -export function ListSettings(arg1) { - return window['go']['settings']['Client']['ListSettings'](arg1); -} - -export function PluginValues(arg1) { - return window['go']['settings']['Client']['PluginValues'](arg1); -} - -export function SetSetting(arg1, arg2, arg3) { - return window['go']['settings']['Client']['SetSetting'](arg1, arg2, arg3); -} - -export function SetSettings(arg1, arg2) { - return window['go']['settings']['Client']['SetSettings'](arg1, arg2); -} - -export function Values() { - return window['go']['settings']['Client']['Values'](); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.d.ts deleted file mode 100755 index d7735e1b..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {settings} from '../models'; -import {context} from '../models'; - -export function GetBool(arg1:string):Promise; - -export function GetCategories():Promise>; - -export function GetCategory(arg1:string):Promise; - -export function GetCategoryValues(arg1:string):Promise>; - -export function GetFloat(arg1:string):Promise; - -export function GetFloatSlice(arg1:string):Promise>; - -export function GetInt(arg1:string):Promise; - -export function GetIntSlice(arg1:string):Promise>; - -export function GetSetting(arg1:string):Promise; - -export function GetSettingValue(arg1:string):Promise; - -export function GetString(arg1:string):Promise; - -export function GetStringSlice(arg1:string):Promise>; - -export function HasSetting(arg1:string):Promise; - -export function Initialize(arg1:context.Context,arg2:Array):Promise; - -export function ListSettings():Promise; - -export function LoadSettings():Promise; - -export function RegisterChangeHandler(arg1:string,arg2:settings.CategoryChangeFunc):Promise; - -export function RegisterSetting(arg1:string,arg2:settings.Setting):Promise; - -export function RegisterSettings(arg1:string,arg2:Array):Promise; - -export function ResetSetting(arg1:string):Promise; - -export function SaveSettings():Promise; - -export function SetSetting(arg1:string,arg2:any):Promise; - -export function SetSettings(arg1:Record):Promise; - -export function Values():Promise>; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.js b/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.js deleted file mode 100755 index f7dbd0fb..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/settings/provider.js +++ /dev/null @@ -1,99 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetBool(arg1) { - return window['go']['settings']['provider']['GetBool'](arg1); -} - -export function GetCategories() { - return window['go']['settings']['provider']['GetCategories'](); -} - -export function GetCategory(arg1) { - return window['go']['settings']['provider']['GetCategory'](arg1); -} - -export function GetCategoryValues(arg1) { - return window['go']['settings']['provider']['GetCategoryValues'](arg1); -} - -export function GetFloat(arg1) { - return window['go']['settings']['provider']['GetFloat'](arg1); -} - -export function GetFloatSlice(arg1) { - return window['go']['settings']['provider']['GetFloatSlice'](arg1); -} - -export function GetInt(arg1) { - return window['go']['settings']['provider']['GetInt'](arg1); -} - -export function GetIntSlice(arg1) { - return window['go']['settings']['provider']['GetIntSlice'](arg1); -} - -export function GetSetting(arg1) { - return window['go']['settings']['provider']['GetSetting'](arg1); -} - -export function GetSettingValue(arg1) { - return window['go']['settings']['provider']['GetSettingValue'](arg1); -} - -export function GetString(arg1) { - return window['go']['settings']['provider']['GetString'](arg1); -} - -export function GetStringSlice(arg1) { - return window['go']['settings']['provider']['GetStringSlice'](arg1); -} - -export function HasSetting(arg1) { - return window['go']['settings']['provider']['HasSetting'](arg1); -} - -export function Initialize(arg1, arg2) { - return window['go']['settings']['provider']['Initialize'](arg1, arg2); -} - -export function ListSettings() { - return window['go']['settings']['provider']['ListSettings'](); -} - -export function LoadSettings() { - return window['go']['settings']['provider']['LoadSettings'](); -} - -export function RegisterChangeHandler(arg1, arg2) { - return window['go']['settings']['provider']['RegisterChangeHandler'](arg1, arg2); -} - -export function RegisterSetting(arg1, arg2) { - return window['go']['settings']['provider']['RegisterSetting'](arg1, arg2); -} - -export function RegisterSettings(arg1, arg2) { - return window['go']['settings']['provider']['RegisterSettings'](arg1, arg2); -} - -export function ResetSetting(arg1) { - return window['go']['settings']['provider']['ResetSetting'](arg1); -} - -export function SaveSettings() { - return window['go']['settings']['provider']['SaveSettings'](); -} - -export function SetSetting(arg1, arg2) { - return window['go']['settings']['provider']['SetSetting'](arg1, arg2); -} - -export function SetSettings(arg1) { - return window['go']['settings']['provider']['SetSettings'](arg1); -} - -export function Values() { - return window['go']['settings']['provider']['Values'](); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.js b/packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.js deleted file mode 100755 index 229c83de..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/telemetry/TelemetryBinding.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function IngestFrontendSignals(arg1) { - return window['go']['telemetry']['TelemetryBinding']['IngestFrontendSignals'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.d.ts b/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.d.ts deleted file mode 100755 index 385cc05a..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT -import {ui} from '../models'; - -export function GetPluginComponents(arg1:ui.GetPluginComponentsInput):Promise>>; - -export function GetResourceAreaComponent(arg1:ui.GetResourceAreaComponentInput):Promise; - -export function GetResourceComponents(arg1:ui.GetResourceComponentsInput):Promise>; diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.js deleted file mode 100755 index 1e9d4a92..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/ui/Client.js +++ /dev/null @@ -1,15 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function GetPluginComponents(arg1) { - return window['go']['ui']['Client']['GetPluginComponents'](arg1); -} - -export function GetResourceAreaComponent(arg1) { - return window['go']['ui']['Client']['GetResourceAreaComponent'](arg1); -} - -export function GetResourceComponents(arg1) { - return window['go']['ui']['Client']['GetResourceComponents'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.js b/packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.js deleted file mode 100755 index fb8a7394..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/go/utils/Client.js +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-check -// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL -// This file is automatically generated. DO NOT EDIT - -export function DetectLanguage(arg1) { - return window['go']['utils']['Client']['DetectLanguage'](arg1); -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/runtime/package.json b/packages/omniviewdev-runtime/src/wailsjs/runtime/package.json deleted file mode 100755 index 1e7c8a5d..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/runtime/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@wailsapp/runtime", - "version": "2.0.0", - "description": "Wails Javascript runtime library", - "main": "runtime.js", - "types": "runtime.d.ts", - "scripts": { - }, - "repository": { - "type": "git", - "url": "git+https://github.com/wailsapp/wails.git" - }, - "keywords": [ - "Wails", - "Javascript", - "Go" - ], - "author": "Lea Anthony ", - "license": "MIT", - "bugs": { - "url": "https://github.com/wailsapp/wails/issues" - }, - "homepage": "https://github.com/wailsapp/wails#readme" -} diff --git a/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.d.ts b/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.d.ts deleted file mode 100755 index 4445dac2..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.d.ts +++ /dev/null @@ -1,249 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export interface Position { - x: number; - y: number; -} - -export interface Size { - w: number; - h: number; -} - -export interface Screen { - isCurrent: boolean; - isPrimary: boolean; - width : number - height : number -} - -// Environment information such as platform, buildtype, ... -export interface EnvironmentInfo { - buildType: string; - platform: string; - arch: string; -} - -// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) -// emits the given event. Optional data may be passed with the event. -// This will trigger any event listeners. -export function EventsEmit(eventName: string, ...data: any): void; - -// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. -export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) -// sets up a listener for the given event name, but will only trigger a given number times. -export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; - -// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) -// sets up a listener for the given event name, but will only trigger once. -export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; - -// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) -// unregisters the listener for the given event name. -export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; - -// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) -// unregisters all listeners. -export function EventsOffAll(): void; - -// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) -// logs the given message as a raw message -export function LogPrint(message: string): void; - -// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) -// logs the given message at the `trace` log level. -export function LogTrace(message: string): void; - -// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) -// logs the given message at the `debug` log level. -export function LogDebug(message: string): void; - -// [LogError](https://wails.io/docs/reference/runtime/log#logerror) -// logs the given message at the `error` log level. -export function LogError(message: string): void; - -// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) -// logs the given message at the `fatal` log level. -// The application will quit after calling this method. -export function LogFatal(message: string): void; - -// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) -// logs the given message at the `info` log level. -export function LogInfo(message: string): void; - -// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) -// logs the given message at the `warning` log level. -export function LogWarning(message: string): void; - -// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) -// Forces a reload by the main application as well as connected browsers. -export function WindowReload(): void; - -// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) -// Reloads the application frontend. -export function WindowReloadApp(): void; - -// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) -// Sets the window AlwaysOnTop or not on top. -export function WindowSetAlwaysOnTop(b: boolean): void; - -// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) -// *Windows only* -// Sets window theme to system default (dark/light). -export function WindowSetSystemDefaultTheme(): void; - -// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) -// *Windows only* -// Sets window to light theme. -export function WindowSetLightTheme(): void; - -// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) -// *Windows only* -// Sets window to dark theme. -export function WindowSetDarkTheme(): void; - -// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) -// Centers the window on the monitor the window is currently on. -export function WindowCenter(): void; - -// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) -// Sets the text in the window title bar. -export function WindowSetTitle(title: string): void; - -// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) -// Makes the window full screen. -export function WindowFullscreen(): void; - -// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) -// Restores the previous window dimensions and position prior to full screen. -export function WindowUnfullscreen(): void; - -// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) -// Returns the state of the window, i.e. whether the window is in full screen mode or not. -export function WindowIsFullscreen(): Promise; - -// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) -// Sets the width and height of the window. -export function WindowSetSize(width: number, height: number): void; - -// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) -// Gets the width and height of the window. -export function WindowGetSize(): Promise; - -// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) -// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMaxSize(width: number, height: number): void; - -// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) -// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. -// Setting a size of 0,0 will disable this constraint. -export function WindowSetMinSize(width: number, height: number): void; - -// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) -// Sets the window position relative to the monitor the window is currently on. -export function WindowSetPosition(x: number, y: number): void; - -// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) -// Gets the window position relative to the monitor the window is currently on. -export function WindowGetPosition(): Promise; - -// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) -// Hides the window. -export function WindowHide(): void; - -// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) -// Shows the window, if it is currently hidden. -export function WindowShow(): void; - -// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) -// Maximises the window to fill the screen. -export function WindowMaximise(): void; - -// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) -// Toggles between Maximised and UnMaximised. -export function WindowToggleMaximise(): void; - -// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) -// Restores the window to the dimensions and position prior to maximising. -export function WindowUnmaximise(): void; - -// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) -// Returns the state of the window, i.e. whether the window is maximised or not. -export function WindowIsMaximised(): Promise; - -// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) -// Minimises the window. -export function WindowMinimise(): void; - -// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) -// Restores the window to the dimensions and position prior to minimising. -export function WindowUnminimise(): void; - -// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) -// Returns the state of the window, i.e. whether the window is minimised or not. -export function WindowIsMinimised(): Promise; - -// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) -// Returns the state of the window, i.e. whether the window is normal or not. -export function WindowIsNormal(): Promise; - -// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) -// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. -export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; - -// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) -// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. -export function ScreenGetAll(): Promise; - -// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) -// Opens the given URL in the system browser. -export function BrowserOpenURL(url: string): void; - -// [Environment](https://wails.io/docs/reference/runtime/intro#environment) -// Returns information about the environment -export function Environment(): Promise; - -// [Quit](https://wails.io/docs/reference/runtime/intro#quit) -// Quits the application. -export function Quit(): void; - -// [Hide](https://wails.io/docs/reference/runtime/intro#hide) -// Hides the application. -export function Hide(): void; - -// [Show](https://wails.io/docs/reference/runtime/intro#show) -// Shows the application. -export function Show(): void; - -// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext) -// Returns the current text stored on clipboard -export function ClipboardGetText(): Promise; - -// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext) -// Sets a text on the clipboard -export function ClipboardSetText(text: string): Promise; - -// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop) -// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. -export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void - -// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff) -// OnFileDropOff removes the drag and drop listeners and handlers. -export function OnFileDropOff() :void - -// Check if the file path resolver is available -export function CanResolveFilePaths(): boolean; - -// Resolves file paths for an array of files -export function ResolveFilePaths(files: File[]): void \ No newline at end of file diff --git a/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.js b/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.js deleted file mode 100755 index 7cb89d75..00000000 --- a/packages/omniviewdev-runtime/src/wailsjs/runtime/runtime.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - _ __ _ __ -| | / /___ _(_) /____ -| | /| / / __ `/ / / ___/ -| |/ |/ / /_/ / / (__ ) -|__/|__/\__,_/_/_/____/ -The electron alternative for Go -(c) Lea Anthony 2019-present -*/ - -export function LogPrint(message) { - window.runtime.LogPrint(message); -} - -export function LogTrace(message) { - window.runtime.LogTrace(message); -} - -export function LogDebug(message) { - window.runtime.LogDebug(message); -} - -export function LogInfo(message) { - window.runtime.LogInfo(message); -} - -export function LogWarning(message) { - window.runtime.LogWarning(message); -} - -export function LogError(message) { - window.runtime.LogError(message); -} - -export function LogFatal(message) { - window.runtime.LogFatal(message); -} - -export function EventsOnMultiple(eventName, callback, maxCallbacks) { - return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); -} - -export function EventsOn(eventName, callback) { - return EventsOnMultiple(eventName, callback, -1); -} - -export function EventsOff(eventName, ...additionalEventNames) { - return window.runtime.EventsOff(eventName, ...additionalEventNames); -} - -export function EventsOffAll() { - return window.runtime.EventsOffAll(); -} - -export function EventsOnce(eventName, callback) { - return EventsOnMultiple(eventName, callback, 1); -} - -export function EventsEmit(eventName) { - let args = [eventName].slice.call(arguments); - return window.runtime.EventsEmit.apply(null, args); -} - -export function WindowReload() { - window.runtime.WindowReload(); -} - -export function WindowReloadApp() { - window.runtime.WindowReloadApp(); -} - -export function WindowSetAlwaysOnTop(b) { - window.runtime.WindowSetAlwaysOnTop(b); -} - -export function WindowSetSystemDefaultTheme() { - window.runtime.WindowSetSystemDefaultTheme(); -} - -export function WindowSetLightTheme() { - window.runtime.WindowSetLightTheme(); -} - -export function WindowSetDarkTheme() { - window.runtime.WindowSetDarkTheme(); -} - -export function WindowCenter() { - window.runtime.WindowCenter(); -} - -export function WindowSetTitle(title) { - window.runtime.WindowSetTitle(title); -} - -export function WindowFullscreen() { - window.runtime.WindowFullscreen(); -} - -export function WindowUnfullscreen() { - window.runtime.WindowUnfullscreen(); -} - -export function WindowIsFullscreen() { - return window.runtime.WindowIsFullscreen(); -} - -export function WindowGetSize() { - return window.runtime.WindowGetSize(); -} - -export function WindowSetSize(width, height) { - window.runtime.WindowSetSize(width, height); -} - -export function WindowSetMaxSize(width, height) { - window.runtime.WindowSetMaxSize(width, height); -} - -export function WindowSetMinSize(width, height) { - window.runtime.WindowSetMinSize(width, height); -} - -export function WindowSetPosition(x, y) { - window.runtime.WindowSetPosition(x, y); -} - -export function WindowGetPosition() { - return window.runtime.WindowGetPosition(); -} - -export function WindowHide() { - window.runtime.WindowHide(); -} - -export function WindowShow() { - window.runtime.WindowShow(); -} - -export function WindowMaximise() { - window.runtime.WindowMaximise(); -} - -export function WindowToggleMaximise() { - window.runtime.WindowToggleMaximise(); -} - -export function WindowUnmaximise() { - window.runtime.WindowUnmaximise(); -} - -export function WindowIsMaximised() { - return window.runtime.WindowIsMaximised(); -} - -export function WindowMinimise() { - window.runtime.WindowMinimise(); -} - -export function WindowUnminimise() { - window.runtime.WindowUnminimise(); -} - -export function WindowSetBackgroundColour(R, G, B, A) { - window.runtime.WindowSetBackgroundColour(R, G, B, A); -} - -export function ScreenGetAll() { - return window.runtime.ScreenGetAll(); -} - -export function WindowIsMinimised() { - return window.runtime.WindowIsMinimised(); -} - -export function WindowIsNormal() { - return window.runtime.WindowIsNormal(); -} - -export function BrowserOpenURL(url) { - window.runtime.BrowserOpenURL(url); -} - -export function Environment() { - return window.runtime.Environment(); -} - -export function Quit() { - window.runtime.Quit(); -} - -export function Hide() { - window.runtime.Hide(); -} - -export function Show() { - window.runtime.Show(); -} - -export function ClipboardGetText() { - return window.runtime.ClipboardGetText(); -} - -export function ClipboardSetText(text) { - return window.runtime.ClipboardSetText(text); -} - -/** - * Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * - * @export - * @callback OnFileDropCallback - * @param {number} x - x coordinate of the drop - * @param {number} y - y coordinate of the drop - * @param {string[]} paths - A list of file paths. - */ - -/** - * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings. - * - * @export - * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished. - * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target) - */ -export function OnFileDrop(callback, useDropTarget) { - return window.runtime.OnFileDrop(callback, useDropTarget); -} - -/** - * OnFileDropOff removes the drag and drop listeners and handlers. - */ -export function OnFileDropOff() { - return window.runtime.OnFileDropOff(); -} - -export function CanResolveFilePaths() { - return window.runtime.CanResolveFilePaths(); -} - -export function ResolveFilePaths(files) { - return window.runtime.ResolveFilePaths(files); -} \ No newline at end of file diff --git a/packages/omniviewdev-showcase/package.json b/packages/omniviewdev-showcase/package.json index 17386b93..cbf26cdc 100644 --- a/packages/omniviewdev-showcase/package.json +++ b/packages/omniviewdev-showcase/package.json @@ -20,10 +20,11 @@ "@mui/x-date-pickers": "^8.27.0", "@tanstack/react-router": "^1.160.0", "@tanstack/react-table": "^8.21.0", - "@types/node": "^22.0.0", + "@types/node": "^25.5.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^5.1.0", + "@vitejs/plugin-react-swc": "^4.0.0", "@xterm/addon-fit": "^0.9.0", "@xterm/addon-webgl": "^0.17.0", "@xterm/xterm": "^5.5.0", @@ -33,7 +34,6 @@ "react-dom": "^19.0.0", "react-icons": "^5.5.0", "typescript": "^5.8.3", - "vite": "^7.3.0", - "@vitejs/plugin-react-swc": "^4.0.0" + "vite": "^7.3.0" } } diff --git a/packages/omniviewdev-ui/package.json b/packages/omniviewdev-ui/package.json index 7ff5890b..08ee8861 100644 --- a/packages/omniviewdev-ui/package.json +++ b/packages/omniviewdev-ui/package.json @@ -208,7 +208,7 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", - "@types/node": "^22.0.0", + "@types/node": "^25.5.0", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^5.1.0", diff --git a/fileloader.go b/plugin_asset_handler.go similarity index 67% rename from fileloader.go rename to plugin_asset_handler.go index ecbd1ed7..59ba8a33 100644 --- a/fileloader.go +++ b/plugin_asset_handler.go @@ -12,26 +12,28 @@ import ( "github.com/wailsapp/mimetype" ) -type FileLoader struct { - http.Handler +// PluginAssetHandler serves plugin assets from the local filesystem. +// It is used as middleware in the Wails v3 AssetOptions to handle +// requests for plugin-specific static files (JS, CSS, images, fonts). +type PluginAssetHandler struct { logger logging.Logger } -func NewFileLoader(logger logging.Logger) *FileLoader { - return &FileLoader{ +// NewPluginAssetHandler creates a new PluginAssetHandler. +func NewPluginAssetHandler(logger logging.Logger) *PluginAssetHandler { + return &PluginAssetHandler{ logger: logger, } } +// allowedPathRegex is compiled once at init — regexp.MustCompile is expensive +// and should not be called on every HTTP request. +var allowedPathRegex = regexp.MustCompile( + `^/plugins/[^/]+/(assets|dist)/.*\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|html|js\.map)$`, +) + func isAllowed(path string) bool { - // only allow the following patterns: - // - /plugins//(assets|dist)/*.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|html) - // - /assets/*.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|html) - - tester := regexp.MustCompile( - `^/plugins/[^/]+/(assets|dist)/.*\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|html|js\.map)$`, - ) - return tester.MatchString(path) + return allowedPathRegex.MatchString(path) } func forceMimeType(path string) string { @@ -65,7 +67,8 @@ func forceMimeType(path string) string { } } -func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { +// ServeHTTP handles HTTP requests for plugin assets. +func (h *PluginAssetHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) { var err error ctx := req.Context() respondUnauthorized := func() { @@ -95,7 +98,9 @@ func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { homeDir, err := os.UserHomeDir() if err != nil { - panic(err) + h.logger.Errorw(ctx, "failed to get home directory", "error", err) + res.WriteHeader(http.StatusInternalServerError) + return } toFetch := filepath.Join(homeDir, ".omniview", requestedFilename) @@ -135,3 +140,16 @@ func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { h.logger.Errorw(ctx, "error serving file", "error", err) } } + +// Middleware returns an application.Middleware that intercepts plugin asset +// requests (those prefixed with /_/) and delegates them to the +// PluginAssetHandler. All other requests pass through to the next handler. +func (h *PluginAssetHandler) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.HasPrefix(r.URL.Path, "/_/") { + h.ServeHTTP(w, r) + return + } + next.ServeHTTP(w, r) + }) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fe770d7..1434bfba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,6 +169,9 @@ importers: specifier: ^2.7.1 version: 2.7.1 devDependencies: + '@rolldown/plugin-babel': + specifier: ^0.2.2 + version: 0.2.2(@babel/core@7.29.0)(@babel/runtime@7.28.6)(rolldown@1.0.0-rc.10)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) '@stylistic/eslint-plugin': specifier: ^5.10.0 version: 5.10.0(eslint@9.25.1(jiti@1.21.0)) @@ -188,8 +191,8 @@ importers: specifier: ^4.4.9 version: 4.4.9 '@types/node': - specifier: ^20.11.30 - version: 20.17.30 + specifier: ^25.5.0 + version: 25.5.0 '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -209,17 +212,20 @@ importers: specifier: ^8.31.0 version: 8.31.0(eslint@9.25.1(jiti@1.21.0))(typescript@5.8.3) '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.4.1(vite@6.2.6(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + specifier: ^6.0.1 + version: 6.0.1(@rolldown/plugin-babel@0.2.2(@babel/core@7.29.0)(@babel/runtime@7.28.6)(rolldown@1.0.0-rc.10)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) '@vitest/ui': specifier: ^4.0.18 version: 4.0.18(vitest@4.0.18) + '@wailsio/runtime': + specifier: 3.0.0-alpha.79 + version: 3.0.0-alpha.79 '@welldone-software/why-did-you-render': specifier: ^8.0.1 version: 8.0.3(react@19.2.4) autoprefixer: specifier: ^10.4.18 - version: 10.4.21(postcss@8.5.6) + version: 10.4.21(postcss@8.5.8) babel-plugin-react-compiler: specifier: ^1.0.0 version: 1.0.0 @@ -249,16 +255,16 @@ importers: version: 3.0.0 ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.15.13)(@types/node@20.17.30)(typescript@5.8.3) + version: 10.9.2(@swc/core@1.15.13)(@types/node@25.5.0)(typescript@5.8.3) typescript: specifier: ^5.8.3 version: 5.8.3 vite: - specifier: ~6.2.6 - version: 6.2.6(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + specifier: ~8.0.1 + version: 8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.17.30)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(tsx@4.21.0)(yaml@2.7.1) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) e2e: devDependencies: @@ -266,35 +272,42 @@ importers: specifier: 1.50.1 version: 1.50.1 '@types/node': - specifier: ^20.11.30 - version: 20.17.30 + specifier: ^25.5.0 + version: 25.5.0 packages/omniviewdev-providers: + dependencies: + '@wailsio/runtime': + specifier: 3.0.0-alpha.79 + version: 3.0.0-alpha.79 devDependencies: '@types/node': - specifier: ^20.12.7 - version: 20.17.30 + specifier: ^25.5.0 + version: 25.5.0 '@types/react': specifier: ^19.0.0 version: 19.2.14 '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.4.1(vite@5.4.18(@types/node@20.17.30)) + version: 4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) react: specifier: ^19.0.0 version: 19.2.4 tsup: specifier: ^8.0.2 - version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@20.17.30))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) + version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@25.5.0))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) typescript: specifier: ^5.4.5 version: 5.8.3 vite: specifier: ^5.2.10 - version: 5.4.18(@types/node@20.17.30) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) packages/omniviewdev-runtime: dependencies: + '@wailsio/runtime': + specifier: 3.0.0-alpha.79 + version: 3.0.0-alpha.79 lodash.get: specifier: ^4.4.2 version: 4.4.2 @@ -306,14 +319,14 @@ importers: specifier: ^5.76.1 version: 5.76.1(react@19.2.4) '@types/node': - specifier: ^20.12.7 - version: 20.17.30 + specifier: ^25.5.0 + version: 25.5.0 '@types/react': specifier: ^19.0.0 version: 19.2.14 '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.4.1(vite@5.4.18(@types/node@20.17.30)) + version: 4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) notistack: specifier: ^3.0.1 version: 3.0.2(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -325,19 +338,19 @@ importers: version: 19.2.4(react@19.2.4) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.15.13)(@types/node@20.17.30)(typescript@5.8.3) + version: 10.9.2(@swc/core@1.15.13)(@types/node@25.5.0)(typescript@5.8.3) tsup: specifier: ^8.0.2 - version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@20.17.30))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) + version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@25.5.0))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) typescript: specifier: ^5.8.3 version: 5.8.3 vite: specifier: ^5.2.10 - version: 5.4.18(@types/node@20.17.30) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) vite-plugin-dts: specifier: ^4.5.3 - version: 4.5.3(@types/node@20.17.30)(rollup@4.57.1)(typescript@5.8.3)(vite@5.4.18(@types/node@20.17.30)) + version: 4.5.3(@types/node@25.5.0)(rollup@4.57.1)(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) packages/omniviewdev-showcase: dependencies: @@ -373,8 +386,8 @@ importers: specifier: ^8.21.0 version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/node': - specifier: ^22.0.0 - version: 22.14.1 + specifier: ^25.5.0 + version: 25.5.0 '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -383,10 +396,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^5.1.0 - version: 5.1.4(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + version: 5.1.4(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) '@vitejs/plugin-react-swc': specifier: ^4.0.0 - version: 4.2.3(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + version: 4.2.3(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) '@xterm/addon-fit': specifier: ^0.9.0 version: 0.9.0(@xterm/xterm@5.5.0) @@ -416,7 +429,7 @@ importers: version: 5.8.3 vite: specifier: ^7.3.0 - version: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + version: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) packages/omniviewdev-ui: dependencies: @@ -458,8 +471,8 @@ importers: specifier: ^14.6.1 version: 14.6.1(@testing-library/dom@10.4.0) '@types/node': - specifier: ^22.0.0 - version: 22.14.1 + specifier: ^25.5.0 + version: 25.5.0 '@types/react': specifier: ^19.0.0 version: 19.2.14 @@ -468,7 +481,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^5.1.0 - version: 5.1.4(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + version: 5.1.4(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) '@vitest/ui': specifier: ^4.0.18 version: 4.0.18(vitest@4.0.18) @@ -504,22 +517,22 @@ importers: version: 5.8.3 vite: specifier: ^7.3.0 - version: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + version: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) vite-plugin-dts: specifier: ^4.5.3 - version: 4.5.3(@types/node@22.14.1)(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + version: 4.5.3(@types/node@25.5.0)(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) vite-plugin-static-copy: specifier: ^3.0.0 - version: 3.2.0(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + version: 3.2.0(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) vitest: specifier: ^4.0.18 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.14.1)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(tsx@4.21.0)(yaml@2.7.1) + version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) packages/omniviewdev-vite-plugin: devDependencies: tsup: specifier: ^8.0.2 - version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@22.14.1))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) + version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@25.5.0))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1) tsx: specifier: ^4.7.0 version: 4.21.0 @@ -528,7 +541,7 @@ importers: version: 5.8.3 vite: specifier: ^5.2.0 - version: 5.4.18(@types/node@22.14.1) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) plugins/aws/ui: dependencies: @@ -604,7 +617,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.4.1(vite@5.4.18(@types/node@22.14.1)) + version: 4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -619,7 +632,7 @@ importers: version: 5.8.3 vite: specifier: ^5.2.0 - version: 5.4.18(@types/node@22.14.1) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) plugins/containers/ui: dependencies: @@ -707,7 +720,7 @@ importers: version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3) '@storybook/react-vite': specifier: ^8.0.4 - version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@22.14.1)) + version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) '@storybook/test': specifier: ^8.0.4 version: 8.6.12(storybook@8.6.12(prettier@3.5.3)) @@ -728,7 +741,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.4.1(vite@5.4.18(@types/node@22.14.1)) + version: 4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -749,7 +762,7 @@ importers: version: 5.8.3 vite: specifier: ^5.2.0 - version: 5.4.18(@types/node@22.14.1) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) plugins/testui/ui: dependencies: @@ -837,7 +850,7 @@ importers: version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3) '@storybook/react-vite': specifier: ^8.0.4 - version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@22.14.1)) + version: 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) '@storybook/test': specifier: ^8.0.4 version: 8.6.12(storybook@8.6.12(prettier@3.5.3)) @@ -858,7 +871,7 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.8.3) '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.4.1(vite@5.4.18(@types/node@22.14.1)) + version: 4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -879,7 +892,7 @@ importers: version: 5.8.3 vite: specifier: ^5.2.0 - version: 5.4.18(@types/node@22.14.1) + version: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) packages: @@ -1144,6 +1157,15 @@ packages: peerDependencies: react: '>=16.8.0' + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -1981,6 +2003,9 @@ packages: peerDependencies: react: ^17.0.0 || ^18.0.0 || ^19.0.0 + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2105,6 +2130,9 @@ packages: resolution: {integrity: sha512-Uo08jW5pj1t58OUKuZNkmzcfTN2pqeVuAWCCiKf/75/oll4Efq4cHOqSE1FXMlvwZNGDziNdDyBbQ5IANem3CQ==} engines: {node: '>=14.0.0', pnpm: '>=7.0.1'} + '@oxc-project/types@0.120.0': + resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2194,12 +2222,124 @@ packages: resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} engines: {node: '>=14.0.0'} + '@rolldown/binding-android-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + resolution: {integrity: sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + resolution: {integrity: sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + resolution: {integrity: sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + resolution: {integrity: sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/plugin-babel@0.2.2': + resolution: {integrity: sha512-q9pE8+47bQNHb5eWVcE6oXppA+JTSwvnrhH53m0ZuHuK5MLvwsLoWrWzBTFQqQ06BVxz1gp0HblLsch8o6pvZw==} + engines: {node: '>=22.12.0 || ^24.0.0'} + peerDependencies: + '@babel/core': ^7.29.0 || ^8.0.0-rc.1 + '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1 + '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1 + rolldown: ^1.0.0-rc.5 + vite: ^8.0.0 + peerDependenciesMeta: + '@babel/plugin-transform-runtime': + optional: true + '@babel/runtime': + optional: true + vite: + optional: true + + '@rolldown/pluginutils@1.0.0-rc.10': + resolution: {integrity: sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==} + '@rolldown/pluginutils@1.0.0-rc.2': resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rolldown/pluginutils@1.0.0-rc.7': + resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} + '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -2861,6 +3001,9 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} @@ -2966,11 +3109,8 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@20.17.30': - resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==} - - '@types/node@22.14.1': - resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3184,6 +3324,19 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@vitejs/plugin-react@6.0.1': + resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + '@vitest/expect@2.0.5': resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} @@ -3265,6 +3418,9 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@wailsio/runtime@3.0.0-alpha.79': + resolution: {integrity: sha512-NITzxKmJsMEruc39L166lbPJVECxzcbdqpHVqOOF7Cu/7Zqk/e3B/gNpkUjhNyo5rVb3V1wpS8oEgLUmpu1cwA==} + '@welldone-software/why-did-you-render@8.0.3': resolution: {integrity: sha512-bb5bKPMStYnocyTBVBu4UTegZdBqzV1mPhxc0UIV/S43KFUSRflux9gvzJfu2aM4EWLJ3egTvdjOi+viK+LKGA==} peerDependencies: @@ -3842,6 +3998,10 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -4946,6 +5106,76 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -5433,10 +5663,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -5502,6 +5728,10 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -5785,6 +6015,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rolldown@1.0.0-rc.10: + resolution: {integrity: sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.40.0: resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -6335,11 +6570,8 @@ packages: underscore@1.12.1: resolution: {integrity: sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} undici@7.22.0: resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} @@ -6461,19 +6693,19 @@ packages: terser: optional: true - vite@6.2.6: - resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -6501,15 +6733,16 @@ packages: yaml: optional: true - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@8.0.1: + resolution: {integrity: sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -6520,12 +6753,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -7046,6 +7281,22 @@ snapshots: react: 19.2.4 tslib: 2.8.1 + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emotion/babel-plugin@11.13.5': dependencies: '@babel/helper-module-imports': 7.25.9 @@ -7486,12 +7737,12 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.3)(vite@5.4.18(@types/node@22.14.1))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0))': dependencies: glob: 10.3.12 magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.8.3) - vite: 5.4.18(@types/node@22.14.1) + vite: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) optionalDependencies: typescript: 5.8.3 @@ -7542,49 +7793,23 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - '@microsoft/api-extractor-model@7.30.5(@types/node@20.17.30)': + '@microsoft/api-extractor-model@7.30.5(@types/node@25.5.0)': dependencies: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.13.0(@types/node@20.17.30) - transitivePeerDependencies: - - '@types/node' - - '@microsoft/api-extractor-model@7.30.5(@types/node@22.14.1)': - dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.13.0(@types/node@22.14.1) - transitivePeerDependencies: - - '@types/node' - - '@microsoft/api-extractor@7.52.4(@types/node@20.17.30)': - dependencies: - '@microsoft/api-extractor-model': 7.30.5(@types/node@20.17.30) - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.13.0(@types/node@20.17.30) - '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.15.2(@types/node@20.17.30) - '@rushstack/ts-command-line': 4.23.7(@types/node@20.17.30) - lodash: 4.17.21 - minimatch: 3.0.8 - resolve: 1.22.10 - semver: 7.5.4 - source-map: 0.6.1 - typescript: 5.8.2 + '@rushstack/node-core-library': 5.13.0(@types/node@25.5.0) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.52.4(@types/node@22.14.1)': + '@microsoft/api-extractor@7.52.4(@types/node@25.5.0)': dependencies: - '@microsoft/api-extractor-model': 7.30.5(@types/node@22.14.1) + '@microsoft/api-extractor-model': 7.30.5(@types/node@25.5.0) '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.13.0(@types/node@22.14.1) + '@rushstack/node-core-library': 5.13.0(@types/node@25.5.0) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.15.2(@types/node@22.14.1) - '@rushstack/ts-command-line': 4.23.7(@types/node@22.14.1) + '@rushstack/terminal': 0.15.2(@types/node@25.5.0) + '@rushstack/ts-command-line': 4.23.7(@types/node@25.5.0) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.10 @@ -7783,6 +8008,13 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7924,6 +8156,8 @@ snapshots: estree-walker: 3.0.3 magic-string: 0.27.0 + '@oxc-project/types@0.120.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -7998,15 +8232,75 @@ snapshots: '@remix-run/router@1.23.0': {} + '@rolldown/binding-android-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/plugin-babel@0.2.2(@babel/core@7.29.0)(@babel/runtime@7.28.6)(rolldown@1.0.0-rc.10)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': + dependencies: + '@babel/core': 7.29.0 + picomatch: 4.0.3 + rolldown: 1.0.0-rc.10 + optionalDependencies: + '@babel/runtime': 7.28.6 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + + '@rolldown/pluginutils@1.0.0-rc.10': {} + '@rolldown/pluginutils@1.0.0-rc.2': {} '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rolldown/pluginutils@1.0.0-rc.7': {} + '@rollup/pluginutils@5.1.4(rollup@4.57.1)': dependencies: '@types/estree': 1.0.7 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: rollup: 4.57.1 @@ -8147,7 +8441,7 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/node-core-library@5.13.0(@types/node@20.17.30)': + '@rushstack/node-core-library@5.13.0(@types/node@25.5.0)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -8158,52 +8452,23 @@ snapshots: resolve: 1.22.10 semver: 7.5.4 optionalDependencies: - '@types/node': 20.17.30 - - '@rushstack/node-core-library@5.13.0(@types/node@22.14.1)': - dependencies: - ajv: 8.13.0 - ajv-draft-04: 1.0.0(ajv@8.13.0) - ajv-formats: 3.0.1(ajv@8.13.0) - fs-extra: 11.3.0 - import-lazy: 4.0.0 - jju: 1.4.0 - resolve: 1.22.10 - semver: 7.5.4 - optionalDependencies: - '@types/node': 22.14.1 + '@types/node': 25.5.0 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.10 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.15.2(@types/node@20.17.30)': + '@rushstack/terminal@0.15.2(@types/node@25.5.0)': dependencies: - '@rushstack/node-core-library': 5.13.0(@types/node@20.17.30) + '@rushstack/node-core-library': 5.13.0(@types/node@25.5.0) supports-color: 8.1.1 optionalDependencies: - '@types/node': 20.17.30 + '@types/node': 25.5.0 - '@rushstack/terminal@0.15.2(@types/node@22.14.1)': + '@rushstack/ts-command-line@4.23.7(@types/node@25.5.0)': dependencies: - '@rushstack/node-core-library': 5.13.0(@types/node@22.14.1) - supports-color: 8.1.1 - optionalDependencies: - '@types/node': 22.14.1 - - '@rushstack/ts-command-line@4.23.7(@types/node@20.17.30)': - dependencies: - '@rushstack/terminal': 0.15.2(@types/node@20.17.30) - '@types/argparse': 1.0.38 - argparse: 1.0.10 - string-argv: 0.3.2 - transitivePeerDependencies: - - '@types/node' - - '@rushstack/ts-command-line@4.23.7(@types/node@22.14.1)': - dependencies: - '@rushstack/terminal': 0.15.2(@types/node@22.14.1) + '@rushstack/terminal': 0.15.2(@types/node@25.5.0) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -8327,13 +8592,13 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/builder-vite@8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@5.4.18(@types/node@22.14.1))': + '@storybook/builder-vite@8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0))': dependencies: '@storybook/csf-plugin': 8.6.12(storybook@8.6.12(prettier@3.5.3)) browser-assert: 1.2.1 storybook: 8.6.12(prettier@3.5.3) ts-dedent: 2.2.0 - vite: 5.4.18(@types/node@22.14.1) + vite: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) '@storybook/components@8.6.12(storybook@8.6.12(prettier@3.5.3))': dependencies: @@ -8396,11 +8661,11 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 8.6.12(prettier@3.5.3) - '@storybook/react-vite@8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@22.14.1))': + '@storybook/react-vite@8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.57.1)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.8.3)(vite@5.4.18(@types/node@22.14.1)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) '@rollup/pluginutils': 5.1.4(rollup@4.57.1) - '@storybook/builder-vite': 8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@5.4.18(@types/node@22.14.1)) + '@storybook/builder-vite': 8.6.12(storybook@8.6.12(prettier@3.5.3))(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)) '@storybook/react': 8.6.12(@storybook/test@8.6.12(storybook@8.6.12(prettier@3.5.3)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@8.6.12(prettier@3.5.3))(typescript@5.8.3) find-up: 5.0.0 magic-string: 0.30.17 @@ -8410,7 +8675,7 @@ snapshots: resolve: 1.22.10 storybook: 8.6.12(prettier@3.5.3) tsconfig-paths: 4.2.0 - vite: 5.4.18(@types/node@22.14.1) + vite: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) optionalDependencies: '@storybook/test': 8.6.12(storybook@8.6.12(prettier@3.5.3)) transitivePeerDependencies: @@ -8658,6 +8923,11 @@ snapshots: '@tsconfig/node16@1.0.4': {} + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/argparse@1.0.38': {} '@types/aria-query@5.0.4': {} @@ -8762,13 +9032,9 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@20.17.30': + '@types/node@25.5.0': dependencies: - undici-types: 6.19.8 - - '@types/node@22.14.1': - dependencies: - undici-types: 6.21.0 + undici-types: 7.18.2 '@types/parse-json@4.0.2': {} @@ -9030,48 +9296,26 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@4.2.3(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': + '@vitejs/plugin-react-swc@4.2.3(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 '@swc/core': 1.15.13 - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.4.1(vite@5.4.18(@types/node@20.17.30))': + '@vitejs/plugin-react@4.4.1(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.26.10 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 5.4.18(@types/node@20.17.30) + vite: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.4.1(vite@5.4.18(@types/node@22.14.1))': - dependencies: - '@babel/core': 7.26.10 - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 5.4.18(@types/node@22.14.1) - transitivePeerDependencies: - - supports-color - - '@vitejs/plugin-react@4.4.1(vite@6.2.6(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': - dependencies: - '@babel/core': 7.26.10 - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 6.2.6(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) - transitivePeerDependencies: - - supports-color - - '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': + '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -9079,10 +9323,18 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) transitivePeerDependencies: - supports-color + '@vitejs/plugin-react@6.0.1(@rolldown/plugin-babel@0.2.2(@babel/core@7.29.0)(@babel/runtime@7.28.6)(rolldown@1.0.0-rc.10)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.7 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + optionalDependencies: + '@rolldown/plugin-babel': 0.2.2(@babel/core@7.29.0)(@babel/runtime@7.28.6)(rolldown@1.0.0-rc.10)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + babel-plugin-react-compiler: 1.0.0 + '@vitest/expect@2.0.5': dependencies: '@vitest/spy': 2.0.5 @@ -9099,21 +9351,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) - - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) '@vitest/pretty-format@2.0.5': dependencies: @@ -9153,7 +9397,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.17.30)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(tsx@4.21.0)(yaml@2.7.1) + vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) '@vitest/utils@2.0.5': dependencies: @@ -9218,6 +9462,8 @@ snapshots: '@vue/shared@3.5.13': {} + '@wailsio/runtime@3.0.0-alpha.79': {} + '@welldone-software/why-did-you-render@8.0.3(react@19.2.4)': dependencies: lodash: 4.17.21 @@ -9429,14 +9675,14 @@ snapshots: async-function@1.0.0: {} - autoprefixer@10.4.21(postcss@8.5.6): + autoprefixer@10.4.21(postcss@8.5.8): dependencies: browserslist: 4.24.4 caniuse-lite: 1.0.30001715 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 - postcss: 8.5.6 + postcss: 8.5.8 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -9815,6 +10061,8 @@ snapshots: dequal@2.0.3: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -11345,6 +11593,55 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -12060,8 +12357,6 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} - picomatch@4.0.3: {} pirates@4.0.6: {} @@ -12094,12 +12389,12 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.7.1): + postcss-load-config@6.0.1(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.7.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.0 - postcss: 8.5.6 + postcss: 8.5.8 tsx: 4.21.0 yaml: 2.7.1 @@ -12117,6 +12412,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.1.2: {} prelude-ls@1.2.1: {} @@ -12151,7 +12452,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 20.17.30 + '@types/node': 25.5.0 long: 5.3.2 punycode@2.3.1: {} @@ -12491,6 +12792,27 @@ snapshots: dependencies: glob: 7.2.3 + rolldown@1.0.0-rc.10: + dependencies: + '@oxc-project/types': 0.120.0 + '@rolldown/pluginutils': 1.0.0-rc.10 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-x64': 1.0.0-rc.10 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.10 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.10 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.10 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.10 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.10 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.10 + rollup@4.40.0: dependencies: '@types/estree': 1.0.7 @@ -12958,14 +13280,14 @@ snapshots: dependencies: tslib: 2.6.2 - ts-node@10.9.2(@swc/core@1.15.13)(@types/node@20.17.30)(typescript@5.8.3): + ts-node@10.9.2(@swc/core@1.15.13)(@types/node@25.5.0)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.30 + '@types/node': 25.5.0 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -12997,36 +13319,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.4.0(@microsoft/api-extractor@7.52.4(@types/node@20.17.30))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1): - dependencies: - bundle-require: 5.1.0(esbuild@0.25.3) - cac: 6.7.14 - chokidar: 4.0.3 - consola: 3.4.2 - debug: 4.4.0 - esbuild: 0.25.3 - joycon: 3.1.1 - picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.7.1) - resolve-from: 5.0.0 - rollup: 4.40.0 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.13 - tree-kill: 1.2.2 - optionalDependencies: - '@microsoft/api-extractor': 7.52.4(@types/node@20.17.30) - '@swc/core': 1.15.13 - postcss: 8.5.6 - typescript: 5.8.3 - transitivePeerDependencies: - - jiti - - supports-color - - tsx - - yaml - - tsup@8.4.0(@microsoft/api-extractor@7.52.4(@types/node@22.14.1))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1): + tsup@8.4.0(@microsoft/api-extractor@7.52.4(@types/node@25.5.0))(@swc/core@1.15.13)(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.7.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.3) cac: 6.7.14 @@ -13036,7 +13329,7 @@ snapshots: esbuild: 0.25.3 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@1.21.0)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.7.1) + postcss-load-config: 6.0.1(jiti@1.21.0)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.7.1) resolve-from: 5.0.0 rollup: 4.40.0 source-map: 0.8.0-beta.0 @@ -13045,9 +13338,9 @@ snapshots: tinyglobby: 0.2.13 tree-kill: 1.2.2 optionalDependencies: - '@microsoft/api-extractor': 7.52.4(@types/node@22.14.1) + '@microsoft/api-extractor': 7.52.4(@types/node@25.5.0) '@swc/core': 1.15.13 - postcss: 8.5.6 + postcss: 8.5.8 typescript: 5.8.3 transitivePeerDependencies: - jiti @@ -13178,9 +13471,7 @@ snapshots: underscore@1.12.1: {} - undici-types@6.19.8: {} - - undici-types@6.21.0: {} + undici-types@7.18.2: {} undici@7.22.0: {} @@ -13281,9 +13572,9 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-plugin-dts@4.5.3(@types/node@20.17.30)(rollup@4.57.1)(typescript@5.8.3)(vite@5.4.18(@types/node@20.17.30)): + vite-plugin-dts@4.5.3(@types/node@25.5.0)(rollup@4.57.1)(typescript@5.8.3)(vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0)): dependencies: - '@microsoft/api-extractor': 7.52.4(@types/node@20.17.30) + '@microsoft/api-extractor': 7.52.4(@types/node@25.5.0) '@rollup/pluginutils': 5.1.4(rollup@4.57.1) '@volar/typescript': 2.4.12 '@vue/language-core': 2.2.0(typescript@5.8.3) @@ -13294,15 +13585,15 @@ snapshots: magic-string: 0.30.17 typescript: 5.8.3 optionalDependencies: - vite: 5.4.18(@types/node@20.17.30) + vite: 5.4.18(@types/node@25.5.0)(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-dts@4.5.3(@types/node@22.14.1)(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)): + vite-plugin-dts@4.5.3(@types/node@25.5.0)(rollup@4.57.1)(typescript@5.8.3)(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)): dependencies: - '@microsoft/api-extractor': 7.52.4(@types/node@22.14.1) + '@microsoft/api-extractor': 7.52.4(@types/node@25.5.0) '@rollup/pluginutils': 5.1.4(rollup@4.57.1) '@volar/typescript': 2.4.12 '@vue/language-core': 2.2.0(typescript@5.8.3) @@ -13313,51 +13604,31 @@ snapshots: magic-string: 0.30.17 typescript: 5.8.3 optionalDependencies: - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)): + vite-plugin-static-copy@3.2.0(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)): dependencies: chokidar: 3.6.0 p-map: 7.0.4 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) - - vite@5.4.18(@types/node@20.17.30): - dependencies: - esbuild: 0.21.5 - postcss: 8.5.3 - rollup: 4.40.0 - optionalDependencies: - '@types/node': 20.17.30 - fsevents: 2.3.3 + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) - vite@5.4.18(@types/node@22.14.1): + vite@5.4.18(@types/node@25.5.0)(lightningcss@1.32.0): dependencies: esbuild: 0.21.5 postcss: 8.5.3 rollup: 4.40.0 optionalDependencies: - '@types/node': 22.14.1 - fsevents: 2.3.3 - - vite@6.2.6(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1): - dependencies: - esbuild: 0.25.3 - postcss: 8.5.3 - rollup: 4.40.0 - optionalDependencies: - '@types/node': 20.17.30 + '@types/node': 25.5.0 fsevents: 2.3.3 - jiti: 1.21.0 - tsx: 4.21.0 - yaml: 2.7.1 + lightningcss: 1.32.0 - vite@7.3.1(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1): + vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -13366,71 +13637,32 @@ snapshots: rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 20.17.30 + '@types/node': 25.5.0 fsevents: 2.3.3 jiti: 1.21.0 + lightningcss: 1.32.0 tsx: 4.21.0 yaml: 2.7.1 - vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1): + vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.3)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.32.0 picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 + postcss: 8.5.8 + rolldown: 1.0.0-rc.10 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.14.1 + '@types/node': 25.5.0 + esbuild: 0.27.3 fsevents: 2.3.3 jiti: 1.21.0 tsx: 4.21.0 yaml: 2.7.1 - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.17.30)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(tsx@4.21.0)(yaml@2.7.1): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@20.17.30)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.0 - '@types/node': 20.17.30 - '@vitest/ui': 4.0.18(vitest@4.0.18) - jsdom: 28.1.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.14.1)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(tsx@4.21.0)(yaml@2.7.1): + vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(@vitest/ui@4.0.18)(jiti@1.21.0)(jsdom@28.1.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1)) + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -13447,11 +13679,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@22.14.1)(jiti@1.21.0)(tsx@4.21.0)(yaml@2.7.1) + vite: 7.3.1(@types/node@25.5.0)(jiti@1.21.0)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.7.1) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - '@types/node': 22.14.1 + '@types/node': 25.5.0 '@vitest/ui': 4.0.18(vitest@4.0.18) jsdom: 28.1.0 transitivePeerDependencies: diff --git a/ui/components/displays/Footer/AppStatusFooter.tsx b/ui/components/displays/Footer/AppStatusFooter.tsx index 871acdbb..6002c3ff 100644 --- a/ui/components/displays/Footer/AppStatusFooter.tsx +++ b/ui/components/displays/Footer/AppStatusFooter.tsx @@ -18,8 +18,8 @@ import { LuExternalLink, LuX, } from 'react-icons/lu'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; -import type { config } from '@omniviewdev/runtime/models'; +import { Events } from '@omniviewdev/runtime/runtime'; +import type { PluginMeta } from '@omniviewdev/runtime/models'; import { useDevServers } from '@/features/devtools/useDevServers'; import { devToolsChannel } from '@/features/devtools/events'; @@ -477,9 +477,10 @@ function PluginLoadingSpinner() { const [loading, setLoading] = React.useState>({}); React.useEffect(() => { - const cancelDevInstallStart = EventsOn( + const cancelDevInstallStart = Events.On( 'plugin/dev_install_start', - (meta: config.PluginMeta) => { + (ev) => { + const meta = ev.data as PluginMeta; setLoading((prev) => ({ ...prev, [meta.id]: `Installing plugin '${meta.name}' in development mode`, @@ -487,19 +488,21 @@ function PluginLoadingSpinner() { }, ); - const cancelUpdateStart = EventsOn( + const cancelUpdateStart = Events.On( 'plugin/update_started', - (id: string, version: string) => { + (ev) => { + const payload = ev.data as { pluginID: string; version: string }; setLoading((prev) => ({ ...prev, - [id]: `Updating plugin '${id}' to '${version}'`, + [payload.pluginID]: `Updating plugin '${payload.pluginID}' to '${payload.version}'`, })); }, ); - const cancelInstallStart = EventsOn( + const cancelInstallStart = Events.On( 'plugin/install_started', - (meta: config.PluginMeta) => { + (ev) => { + const meta = ev.data as PluginMeta; setLoading((prev) => ({ ...prev, [meta.id]: `Installing plugin '${meta.name}'`, @@ -507,9 +510,10 @@ function PluginLoadingSpinner() { }, ); - const cancelReloadStart = EventsOn( + const cancelReloadStart = Events.On( 'plugin/dev_reload_start', - (meta: config.PluginMeta) => { + (ev) => { + const meta = ev.data as PluginMeta; setLoading((prev) => ({ ...prev, [meta.id]: `Reloading plugin '${meta.name}'`, @@ -517,32 +521,38 @@ function PluginLoadingSpinner() { }, ); - const clearLoading = (meta: config.PluginMeta) => { + const clearLoading = (meta: PluginMeta) => { setLoading((prev) => ({ ...prev, [meta.id]: '' })); }; + const clearLoadingByEv = (ev: Events.WailsEvent) => { + clearLoading(ev.data as PluginMeta); + }; + const clearLoadingById = (id: string) => { setLoading((prev) => ({ ...prev, [id]: '' })); }; - const cancelReloadError = EventsOn('plugin/dev_reload_error', clearLoading); - const cancelReloadComplete = EventsOn('plugin/dev_reload_complete', clearLoading); - const cancelDevInstallError = EventsOn('plugin/dev_install_error', clearLoading); - const cancelDevInstallComplete = EventsOn('plugin/dev_install_complete', clearLoading); - const cancelInstallComplete = EventsOn('plugin/install_complete', clearLoading); - const cancelInstallFinished = EventsOn('plugin/install_finished', (meta: config.PluginMeta) => { + const cancelReloadError = Events.On('plugin/dev_reload_error', clearLoadingByEv); + const cancelReloadComplete = Events.On('plugin/dev_reload_complete', clearLoadingByEv); + const cancelDevInstallError = Events.On('plugin/dev_install_error', clearLoadingByEv); + const cancelDevInstallComplete = Events.On('plugin/dev_install_complete', clearLoadingByEv); + const cancelInstallComplete = Events.On('plugin/install_complete', clearLoadingByEv); + const cancelInstallFinished = Events.On('plugin/install_finished', (ev) => { + const meta = ev.data as PluginMeta; clearLoading(meta); clearLoadingById(meta.id); }); - const cancelInstallError = EventsOn('plugin/install_error', (meta: config.PluginMeta) => { + const cancelInstallError = Events.On('plugin/install_error', (ev) => { + const meta = ev.data as PluginMeta; clearLoading(meta); clearLoadingById(meta.id); }); - const cancelUpdateError = EventsOn('plugin/update_error', (id: string) => { - clearLoadingById(id); + const cancelUpdateError = Events.On('plugin/update_error', (ev) => { + clearLoadingById(ev.data as string); }); - const cancelUpdateComplete = EventsOn('plugin/update_complete', (id: string) => { - clearLoadingById(id); + const cancelUpdateComplete = Events.On('plugin/update_complete', (ev) => { + clearLoadingById(ev.data as string); }); return () => { diff --git a/ui/components/tables/Resources/actions/ExecAction.tsx b/ui/components/tables/Resources/actions/ExecAction.tsx index ecd850f5..bb3dbb1c 100644 --- a/ui/components/tables/Resources/actions/ExecAction.tsx +++ b/ui/components/tables/Resources/actions/ExecAction.tsx @@ -12,7 +12,7 @@ import jsonpath from 'jsonpath'; import { LuSquareTerminal } from 'react-icons/lu'; // types -import { exec } from '@omniviewdev/runtime/models'; +import { Handler, SessionOptions } from '@omniviewdev/runtime/models'; // project imports import ActionMenuListItem from './ActionMenuListItem'; @@ -25,7 +25,7 @@ type Props = { handleLeaveMenu: (getIsOnButton: () => boolean) => void; handleDismiss: () => void; itemProps: Record; - action: exec.Handler; + action: Handler; plugin: string; connection: string; resource: string; @@ -37,7 +37,7 @@ type ExecTarget = { params: Record; }; -const calcTargets = (action: exec.Handler, data: Record): ExecTarget[] => { +const calcTargets = (action: Handler, data: Record): ExecTarget[] => { const targets = [] as ExecTarget[]; const datas = action.target_builder.paths.reduce>>((acc, path) => { @@ -86,7 +86,7 @@ const ExecAction: React.FC = ({ */ const handlePerformExec = (label: string, params: Record) => { /* eslint-disable @typescript-eslint/naming-convention */ - const opts = exec.SessionOptions.createFrom({ + const opts = SessionOptions.createFrom({ params, resource_plugin: plugin, resource_key: resource, diff --git a/ui/components/tables/Resources/actions/types.ts b/ui/components/tables/Resources/actions/types.ts index 8ef3f217..2a2647c5 100644 --- a/ui/components/tables/Resources/actions/types.ts +++ b/ui/components/tables/Resources/actions/types.ts @@ -1,6 +1,6 @@ // types -import { type exec } from '@omniviewdev/runtime/models'; +import type { Handler } from '@omniviewdev/runtime/models'; export type Actions = { - exec?: exec.Handler; + exec?: Handler; }; diff --git a/ui/components/tables/Resources/cells/ResourceLinkCell.tsx b/ui/components/tables/Resources/cells/ResourceLinkCell.tsx index 3e7dc65f..40cb1959 100644 --- a/ui/components/tables/Resources/cells/ResourceLinkCell.tsx +++ b/ui/components/tables/Resources/cells/ResourceLinkCell.tsx @@ -9,11 +9,11 @@ import { Tooltip } from '@omniviewdev/ui/overlays'; import get from 'lodash.get'; // types -import { type types } from '@omniviewdev/runtime/models'; +import type { ResourceLink } from '@omniviewdev/runtime/models'; import useRightDrawer from '@/hooks/useRightDrawer'; import { type ResourceMetadata } from '@/hooks/resource/useResourceDefinition'; -type Props = types.ResourceLink & { +type Props = ResourceLink & { value: any; metadata?: ResourceMetadata; }; diff --git a/ui/components/tables/Resources/cells/TextCell.tsx b/ui/components/tables/Resources/cells/TextCell.tsx index 1cf0f35b..3a853de4 100644 --- a/ui/components/tables/Resources/cells/TextCell.tsx +++ b/ui/components/tables/Resources/cells/TextCell.tsx @@ -5,7 +5,7 @@ import Box from '@mui/material/Box'; import { Text } from '@omniviewdev/ui/typography'; import { formatTimeDifference } from '@/utils/time'; import { convertByteUnits } from '@/utils/units'; -import { type types } from '@omniviewdev/runtime/models'; +import type { ResourceLink } from '@omniviewdev/runtime/models'; import { type ResourceMetadata } from '@/hooks/resource/useResourceDefinition'; import ResourceLinkCell from './ResourceLinkCell'; @@ -25,7 +25,7 @@ type Props = { /** Formatter for the text */ formatter?: string; /** Resource links to parse */ - resourceLink?: types.ResourceLink; + resourceLink?: ResourceLink; /** Metadata for the resource */ metadata?: ResourceMetadata; /** children */ diff --git a/ui/contexts/PluginContext.tsx b/ui/contexts/PluginContext.tsx index 1589c137..110d3279 100644 --- a/ui/contexts/PluginContext.tsx +++ b/ui/contexts/PluginContext.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { type types } from '@omniviewdev/runtime/models'; +import type { PluginInfo } from '@omniviewdev/runtime/models'; /** * PluginContext provides data about the current plugin that is within scope. */ -export const PluginContext = React.createContext(undefined); +export const PluginContext = React.createContext(undefined); /** * UsePluginContext provides the current plugin that is within scope. diff --git a/ui/features/devtools/types.ts b/ui/features/devtools/types.ts index 257b716e..9c19ac06 100644 --- a/ui/features/devtools/types.ts +++ b/ui/features/devtools/types.ts @@ -3,13 +3,13 @@ * Core types (DevServerState, DevBuildLine) are re-exported from the * Wails-generated bindings so there is a single source of truth. */ -import { devserver } from '@omniviewdev/runtime/models'; +import type { DevServerState as DevServerStateModel, DevServerLogEntry } from '@omniviewdev/runtime/models'; /** Dev server state, re-exported from the Wails binding models. */ -export type DevServerState = devserver.DevServerState; +export type DevServerState = DevServerStateModel; /** A single line of build output, re-exported from the Wails binding models. */ -export type DevBuildLine = devserver.LogEntry; +export type DevBuildLine = DevServerLogEntry; /** A structured build error from the Go compiler output. */ export interface DevBuildError { diff --git a/ui/features/devtools/wailsBridge.ts b/ui/features/devtools/wailsBridge.ts index b2593065..4a7b3407 100644 --- a/ui/features/devtools/wailsBridge.ts +++ b/ui/features/devtools/wailsBridge.ts @@ -1,4 +1,4 @@ -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { DevServerManager } from '@omniviewdev/runtime/api'; import { devToolsChannel } from './events'; import type { DevServerState, DevBuildLine, DevBuildError } from './types'; @@ -12,13 +12,14 @@ export function initDevToolsBridge(): () => void { const cleanups: Array<() => void> = []; cleanups.push( - EventsOn('plugin/devserver/status', (state: DevServerState) => { - devToolsChannel.emit('onStatusChange', state); + Events.On('plugin/devserver/status', (ev) => { + devToolsChannel.emit('onStatusChange', ev.data as DevServerState); }), ); cleanups.push( - EventsOn('plugin/devserver/log', (entries: DevBuildLine[]) => { + Events.On('plugin/devserver/log', (ev) => { + const entries = ev.data as DevBuildLine[]; for (const entry of entries) { devToolsChannel.emit('onBuildLog', entry); } @@ -26,8 +27,9 @@ export function initDevToolsBridge(): () => void { ); cleanups.push( - EventsOn('plugin/devserver/error', (pluginId: string, errors: DevBuildError[]) => { - devToolsChannel.emit('onBuildError', { pluginId, errors }); + Events.On('plugin/devserver/error', (ev) => { + const payload = ev.data as { pluginID: string; errors: DevBuildError[] }; + devToolsChannel.emit('onBuildError', { pluginId: payload.pluginID, errors: payload.errors }); }), ); diff --git a/ui/features/logger/useLogger.tsx b/ui/features/logger/useLogger.tsx index e9840075..a2fb2164 100644 --- a/ui/features/logger/useLogger.tsx +++ b/ui/features/logger/useLogger.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { DiagnosticsClient } from "@omniviewdev/runtime/api"; -import { EventsOn } from "@omniviewdev/runtime/runtime"; +import { Events } from '@omniviewdev/runtime/runtime'; export function useComponentLogs( component: string, @@ -41,7 +41,7 @@ export function useComponentLogs( }; // subscribe & start tail - const closer = EventsOn(`internal/log/update:${logType}`, handler); + const closer = Events.On(`internal/log/update:${logType}`, (ev) => handler(ev.data as string)); DiagnosticsClient.StartTail(logType); return () => { diff --git a/ui/features/pluginlogs/types.ts b/ui/features/pluginlogs/types.ts index 5eca007c..3901885a 100644 --- a/ui/features/pluginlogs/types.ts +++ b/ui/features/pluginlogs/types.ts @@ -3,7 +3,7 @@ * LogEntry is re-exported from the Wails-generated binding so there * is a single source of truth. */ -import { pluginlog } from '@omniviewdev/runtime/models'; +import type { PluginLogEntry as PluginLogEntryModel } from '@omniviewdev/runtime/models'; /** A single line of plugin process output. */ -export type PluginLogEntry = pluginlog.LogEntry; +export type PluginLogEntry = PluginLogEntryModel; diff --git a/ui/features/pluginlogs/wailsBridge.ts b/ui/features/pluginlogs/wailsBridge.ts index 55a58a37..5faee029 100644 --- a/ui/features/pluginlogs/wailsBridge.ts +++ b/ui/features/pluginlogs/wailsBridge.ts @@ -1,4 +1,4 @@ -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { pluginLogChannel } from './events'; import type { PluginLogEntry } from './types'; @@ -11,8 +11,8 @@ export function initPluginLogBridge(): () => void { const cleanups: Array<() => void> = []; cleanups.push( - EventsOn('plugin/process/log', (entry: PluginLogEntry) => { - pluginLogChannel.emit('onPluginLog', entry); + Events.On('plugin/process/log', (ev) => { + pluginLogChannel.emit('onPluginLog', ev.data as PluginLogEntry); }), ); diff --git a/ui/features/plugins/adapters/createProductionDeps.ts b/ui/features/plugins/adapters/createProductionDeps.ts index f8c02f82..c4b73b7e 100644 --- a/ui/features/plugins/adapters/createProductionDeps.ts +++ b/ui/features/plugins/adapters/createProductionDeps.ts @@ -1,6 +1,6 @@ import { EXTENSION_REGISTRY } from '@/features/extensions/store'; import { ensureBuiltinExtensionPointsRegistered } from '@/features/extensions/registerBuiltinExtensionPoints'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { validatePluginExports } from '../core/validation'; import { MissingExtensionPointError, DuplicateContributionError } from '../core/errors'; import { InMemoryCrashDataStrategy } from '../core/CrashDataService'; @@ -38,8 +38,8 @@ export function createProductionDeps(config?: Partial): Plu clearPlugin, onEvent: (eventName, handler) => { - // EventsOn returns () => void — use it for proper cleanup. - return EventsOn(eventName, handler); + // Events.On returns () => void — use it for proper cleanup. + return Events.On(eventName, (ev) => handler(ev.data)); }, ensureBuiltinExtensionPoints: () => { diff --git a/ui/features/plugins/react/PluginServiceProvider.tsx b/ui/features/plugins/react/PluginServiceProvider.tsx index 91738d85..fdb99be9 100644 --- a/ui/features/plugins/react/PluginServiceProvider.tsx +++ b/ui/features/plugins/react/PluginServiceProvider.tsx @@ -1,5 +1,5 @@ import React, { useRef, useMemo, useEffect } from 'react'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { PluginServiceContext } from './context'; import { PluginService } from '../core/PluginService'; import { createProductionDeps } from '../adapters/createProductionDeps'; @@ -81,11 +81,12 @@ export function PluginServiceProvider({ children }: PluginServiceProviderProps) // Listen for dev server readiness — load dev plugins once their server is up useEffect(() => { - const cleanup = EventsOn('plugin/devserver/status', (state: { - pluginID: string; - vitePort: number; - viteStatus: string; - }) => { + const cleanup = Events.On('plugin/devserver/status', (ev) => { + const state = ev.data as { + pluginID: string; + vitePort: number; + viteStatus: string; + }; if (state.viteStatus !== 'ready' || !state.vitePort || state.vitePort <= 0) return; const ps = service.getPluginState(state.pluginID); diff --git a/ui/federation/LinkedResourceDrawer.tsx b/ui/federation/LinkedResourceDrawer.tsx index c5d57c4c..35d4c8f3 100644 --- a/ui/federation/LinkedResourceDrawer.tsx +++ b/ui/federation/LinkedResourceDrawer.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; // material-ui import { Stack } from '@omniviewdev/ui/layout'; import { Button } from '@omniviewdev/ui/buttons'; +import { InlineErrorFallback } from '@/components/errors/ErrorFallback'; // types import type { DrawerComponent, DrawerContext } from '@omniviewdev/runtime'; @@ -151,9 +153,16 @@ export const createLinkedResourceDrawer = ( { title: 'Overview', icon: , - component: (ctx) => SidebarComponent - ? - : , + component: (ctx) => ( + } + resetKeys={[resourceKey]} + > + {SidebarComponent + ? + : } + + ), }, { title: 'Editor', diff --git a/ui/federation/ResourceSidebarComponent.tsx b/ui/federation/ResourceSidebarComponent.tsx index 39fa085b..69605005 100644 --- a/ui/federation/ResourceSidebarComponent.tsx +++ b/ui/federation/ResourceSidebarComponent.tsx @@ -21,7 +21,7 @@ import { } from '@omniviewdev/runtime' // types -import { resource, ui } from '@omniviewdev/runtime/models'; +import { UpdateInput, GetResourceAreaComponentInput } from '@omniviewdev/runtime/models'; // icons import Icon from '@/components/icons/Icon'; @@ -76,7 +76,7 @@ const ResourceDrawerContainer: React.FC = ({ * Update the resource */ const onResourceUpdate = async (data: Record) => { - const input = resource.UpdateInput.createFrom({ + const input = UpdateInput.createFrom({ input: data, params: {}, id: resourceID, @@ -421,7 +421,7 @@ type ResourceSidebarComponentProps = { * Get the dynamic resource sidebar component with the fallback */ const ResourceSidebarComponent: React.FC = ({ plugin, resource, data, onSubmit, onCancel, useSearch }) => { - const { component } = useResourceAreaComponent(ui.GetResourceAreaComponentInput.createFrom({ plugin, resource, area: 'SIDEBAR' })); + const { component } = useResourceAreaComponent(GetResourceAreaComponentInput.createFrom({ plugin, resource, area: 'SIDEBAR' })); if (component.isLoading) { return ( diff --git a/ui/hooks/plugin/useDevServer.ts b/ui/hooks/plugin/useDevServer.ts index a9bc7334..c2cee86d 100644 --- a/ui/hooks/plugin/useDevServer.ts +++ b/ui/hooks/plugin/useDevServer.ts @@ -4,16 +4,16 @@ import { useMutation, useQueryClient, } from '@tanstack/react-query'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { DevServerManager } from '@omniviewdev/runtime/api'; -import { devserver } from '@omniviewdev/runtime/models'; +import type { DevServerState as DevServerStateModel, DevServerLogEntry } from '@omniviewdev/runtime/models'; // ── Types ────────────────────────────────────────────────────────────────── // Re-export from the Wails binding models so consumers don't need to import // from two places. -export type DevServerState = devserver.DevServerState; -export type DevLogEntry = devserver.LogEntry; +export type DevServerState = DevServerStateModel; +export type DevLogEntry = DevServerLogEntry; export interface DevBuildError { file: string; @@ -66,9 +66,10 @@ export function useDevServer(pluginID?: string) { // ── Real-time event subscription ─────────────────────────────────────── React.useEffect(() => { - const offStatus = EventsOn( + const offStatus = Events.On( 'plugin/devserver/status', - (state: DevServerState) => { + (ev) => { + const state = ev.data as DevServerState; // Update single-plugin cache queryClient.setQueryData(KEYS.one(state.pluginID), state); @@ -158,7 +159,8 @@ export function useDevBuildStream( const [errors, setErrors] = React.useState([]); React.useEffect(() => { - const offLog = EventsOn('plugin/devserver/log', (entries: DevLogEntry[]) => { + const offLog = Events.On('plugin/devserver/log', (ev) => { + const entries = ev.data as DevLogEntry[]; const filtered = entries.filter((entry) => { if (entry.pluginID !== pluginID) return false; if (sourceFilter !== 'all' && entry.source !== sourceFilter) return false; @@ -173,11 +175,12 @@ export function useDevBuildStream( }); }); - const offError = EventsOn( + const offError = Events.On( 'plugin/devserver/error', - (errorPluginID: string, buildErrors: DevBuildError[]) => { - if (errorPluginID !== pluginID) return; - setErrors((prev) => [...prev, ...buildErrors]); + (ev) => { + const payload = ev.data as { pluginID: string; errors: DevBuildError[] }; + if (payload.pluginID !== pluginID) return; + setErrors((prev) => [...prev, ...payload.errors]); } ); diff --git a/ui/hooks/plugin/usePluginManager.ts b/ui/hooks/plugin/usePluginManager.ts index f18e7e09..8ea339fd 100644 --- a/ui/hooks/plugin/usePluginManager.ts +++ b/ui/hooks/plugin/usePluginManager.ts @@ -2,8 +2,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useSnackbar, createErrorHandler, parseAppError, actionToSnackbar } from '@omniviewdev/runtime'; import { PluginManager } from '@omniviewdev/runtime/api'; import React from 'react'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; -import { type config, type types } from '@omniviewdev/runtime/models'; +import { Events } from '@omniviewdev/runtime/runtime'; +import type { PluginMeta, PluginInfo } from '@omniviewdev/runtime/models'; import { usePluginService } from '@/features/plugins'; @@ -22,7 +22,7 @@ export const usePluginManager = () => { // Listen for backend init_complete to immediately refresh the plugin list // instead of waiting for the 2s poll interval. React.useEffect(() => { - const cleanup = EventsOn('plugin/init_complete', () => { + const cleanup = Events.On('plugin/init_complete', () => { console.debug('[usePluginManager] plugin/init_complete received'); void queryClient.invalidateQueries({ queryKey: [Entity.PLUGINS] }); }); @@ -32,25 +32,27 @@ export const usePluginManager = () => { // === Watchers === // React.useEffect(() => { // Set up watchers for plugin reload and install events - const closer1 = EventsOn('plugin/dev_reload_start', (meta: config.PluginMeta) => { - queryClient.setQueryData([Entity.PLUGINS], (oldData: types.PluginInfo[] | undefined) => + const closer1 = Events.On('plugin/dev_reload_start', (ev) => { + const meta = ev.data as PluginMeta; + queryClient.setQueryData([Entity.PLUGINS], (oldData: PluginInfo[] | undefined) => oldData?.map(plugin => plugin.id === meta.id ? { ...plugin, phase: 'Starting', lastError: '' } : plugin, ), ); - queryClient.setQueryData([Entity.PLUGINS, meta.id], (oldData: types.PluginInfo | undefined) => + queryClient.setQueryData([Entity.PLUGINS, meta.id], (oldData: PluginInfo | undefined) => oldData ? { ...oldData, phase: 'Starting', lastError: '' } : oldData, ); }); - const closer2 = EventsOn('plugin/dev_reload_error', (meta: config.PluginMeta, error: string) => { - queryClient.setQueryData([Entity.PLUGINS], (oldData: types.PluginInfo[] | undefined) => + const closer2 = Events.On('plugin/dev_reload_error', (ev) => { + const [meta, error] = ev.data as [PluginMeta, string]; + queryClient.setQueryData([Entity.PLUGINS], (oldData: PluginInfo[] | undefined) => oldData?.map(plugin => plugin.id === meta.id ? { ...plugin, phase: 'Failed', lastError: error } : plugin, ), ); - queryClient.setQueryData([Entity.PLUGINS, meta.id], (oldData: types.PluginInfo | undefined) => + queryClient.setQueryData([Entity.PLUGINS, meta.id], (oldData: PluginInfo | undefined) => oldData ? { ...oldData, phase: 'Failed', lastError: error } : oldData, ); diff --git a/ui/hooks/resource/useResourceDefinition.tsx b/ui/hooks/resource/useResourceDefinition.tsx index 707eec8b..77a81b19 100644 --- a/ui/hooks/resource/useResourceDefinition.tsx +++ b/ui/hooks/resource/useResourceDefinition.tsx @@ -7,7 +7,7 @@ import get from 'lodash.get'; // project imports import { ResourceClient, ExecClient } from '@omniviewdev/runtime/api'; -import { type types } from '@omniviewdev/runtime/models'; +import type { ColumnDefinition } from '@omniviewdev/runtime/models'; import SelectBoxHeader from '@/components/tables/Resources/cells/SelectBoxHeader'; import SelectBoxRow from '@/components/tables/Resources/cells/SelectBoxRow'; import { type Actions } from '@/components/tables/Resources/actions/types'; @@ -44,7 +44,7 @@ const getAlignment = (align?: string) => { }; type ParseColumnDefOpts = { - columnDefs?: types.ColumnDef[]; + columnDefs?: ColumnDefinition[]; actions?: Actions; pluginID: string; connectionID: string; diff --git a/ui/hooks/settings/useCoreSettings.ts b/ui/hooks/settings/useCoreSettings.ts index 7db317bc..0bcba440 100644 --- a/ui/hooks/settings/useCoreSettings.ts +++ b/ui/hooks/settings/useCoreSettings.ts @@ -3,7 +3,7 @@ import { useSnackbar, createErrorHandler } from '@omniviewdev/runtime'; // Underlying client import { SettingsProvider } from '@omniviewdev/runtime/api'; -import { type settings } from '@omniviewdev/runtime/models'; +import type { Category } from '@omniviewdev/runtime/models'; /** * Interact with the global settings provider. Intended for use in the settings UI. If you need to read or write settings @@ -38,7 +38,7 @@ export const useSettingsProvider = () => { const settings = useQuery({ queryKey, - queryFn: async () => SettingsProvider.ListSettings() as Promise>, + queryFn: async () => SettingsProvider.ListSettings() as Promise>, }); return { diff --git a/ui/hooks/settings/usePluginSettings.ts b/ui/hooks/settings/usePluginSettings.ts index c28a0200..df1b4a86 100644 --- a/ui/hooks/settings/usePluginSettings.ts +++ b/ui/hooks/settings/usePluginSettings.ts @@ -3,7 +3,7 @@ import { useSnackbar, createErrorHandler } from '@omniviewdev/runtime'; // Underlying client import { SettingsClient } from '@omniviewdev/runtime/api'; -import { type settings } from '@omniviewdev/runtime/models'; +import type { Setting } from '@omniviewdev/runtime/models'; type PluginSettingsOptions = { /** @@ -34,7 +34,7 @@ export const usePluginSettings = ({ plugin }: PluginSettingsOptions) => { const settings = useQuery({ queryKey, - queryFn: async () => SettingsClient.ListSettings(plugin) as Promise>, + queryFn: async () => SettingsClient.ListSettings(plugin) as Promise>, }); return { diff --git a/ui/layouts/core/main/BottomDrawer/__tests__/BottomDrawer.test.tsx b/ui/layouts/core/main/BottomDrawer/__tests__/BottomDrawer.test.tsx index 5667fd3c..87e2c582 100644 --- a/ui/layouts/core/main/BottomDrawer/__tests__/BottomDrawer.test.tsx +++ b/ui/layouts/core/main/BottomDrawer/__tests__/BottomDrawer.test.tsx @@ -22,7 +22,9 @@ vi.mock('@omniviewdev/runtime', () => ({ })); vi.mock('@omniviewdev/runtime/runtime', () => ({ - EventsOn: mocks.mockEventsOn, + Events: { + On: mocks.mockEventsOn, + }, })); vi.mock('@/providers/BottomDrawer/events', () => ({ diff --git a/ui/layouts/core/main/BottomDrawer/index.tsx b/ui/layouts/core/main/BottomDrawer/index.tsx index de4dabb0..f2879a0a 100644 --- a/ui/layouts/core/main/BottomDrawer/index.tsx +++ b/ui/layouts/core/main/BottomDrawer/index.tsx @@ -15,7 +15,7 @@ import PluginLogViewer from '@/providers/BottomDrawer/containers/PluginLogViewer import EditorDebugPanel from '@/providers/BottomDrawer/containers/EditorDebugPanel'; import { useBottomDrawer } from '@omniviewdev/runtime'; import { bottomDrawerChannel } from '@/providers/BottomDrawer/events'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; const TerminalContainerMemo = React.memo(TerminalContainer, (prev, next) => { return prev.sessionId === next.sessionId @@ -160,14 +160,14 @@ const BottomDrawerContainer: React.FC = () => { expandDrawerToHeight(height); }); - const closerFullScreen = EventsOn("menu/view/bottomdrawer/fullscreen", () => { + const closerFullScreen = Events.On("menu/view/bottomdrawer/fullscreen", () => { fullscreen(); }) const unsubscribeOnFullScreen = bottomDrawerChannel.on('onFullscreen', () => { fullscreen(); }); - const closerMinimize = EventsOn("menu/view/bottomdrawer/minimize", () => { + const closerMinimize = Events.On("menu/view/bottomdrawer/minimize", () => { minimize(); }); const unsubscribeOnMinimize = bottomDrawerChannel.on('onMinimize', () => { diff --git a/ui/layouts/core/main/Header/areas/HeaderItemsArea.tsx b/ui/layouts/core/main/Header/areas/HeaderItemsArea.tsx index 94af831e..3fe40c82 100644 --- a/ui/layouts/core/main/Header/areas/HeaderItemsArea.tsx +++ b/ui/layouts/core/main/Header/areas/HeaderItemsArea.tsx @@ -13,7 +13,7 @@ import HeaderIconLink from './components/HeaderIconLink'; import { type HeaderAreaItemList, type HeaderAreaItemListType, HeaderAreaItemType } from '@/store/header/types'; // import usePanes from '@/hooks/usePanes'; // import { Tooltip } from '@omniviewdev/ui/overlays'; -import { WindowIsMaximised, WindowMaximise, WindowUnmaximise } from '@omniviewdev/runtime/runtime'; +import { Window } from '@omniviewdev/runtime/runtime'; type Props = { /** The items to display in the header. */ @@ -38,11 +38,11 @@ const HeaderItemsArea: React.FC = ({ items }) => { // don't do anything break; default: - WindowIsMaximised().then((isMaximized) => { + Window.IsMaximised().then((isMaximized) => { if (isMaximized) { - WindowUnmaximise(); + Window.UnMaximise(); } else { - WindowMaximise(); + Window.Maximise(); } }).catch((err) => { log.error(err instanceof Error ? err : new Error(String(err)), { event: 'window_maximize_toggle' }); diff --git a/ui/layouts/core/main/Header/areas/HeaderTabsArea.tsx b/ui/layouts/core/main/Header/areas/HeaderTabsArea.tsx index 7f94bf70..86cba066 100644 --- a/ui/layouts/core/main/Header/areas/HeaderTabsArea.tsx +++ b/ui/layouts/core/main/Header/areas/HeaderTabsArea.tsx @@ -2,7 +2,7 @@ import React from 'react'; // material-ui import Box from '@mui/material/Box'; -import { WindowIsMaximised, WindowMaximise, WindowUnmaximise } from '@omniviewdev/runtime/runtime'; +import { Window } from '@omniviewdev/runtime/runtime'; // import TabBarProvider from '@/providers/header/TabBarProvider'; @@ -21,11 +21,11 @@ const HeaderTabsArea: React.FC = () => { // don't do anything break; default: - WindowIsMaximised().then((isMaximized) => { + Window.IsMaximised().then((isMaximized) => { if (isMaximized) { - WindowUnmaximise(); + Window.UnMaximise(); } else { - WindowMaximise(); + Window.Maximise(); } }).catch((err) => { console.error(err); diff --git a/ui/layouts/core/main/Header/index.tsx b/ui/layouts/core/main/Header/index.tsx index e85863a2..cdcf418b 100644 --- a/ui/layouts/core/main/Header/index.tsx +++ b/ui/layouts/core/main/Header/index.tsx @@ -11,7 +11,7 @@ import { useSelector } from 'react-redux'; import { type RootState } from '@/store/store'; import HeaderTabsArea from './areas/HeaderTabsArea'; import { WindowContext } from '@/contexts/WindowContext'; -import { WindowIsMaximised, WindowMaximise, WindowUnmaximise } from '@omniviewdev/runtime/runtime'; +import { Window } from '@omniviewdev/runtime/runtime'; /** * Primary header component for the core main layout @@ -32,11 +32,11 @@ const CoreLayoutHeader: React.FC = props => { // don't do anything break; default: - WindowIsMaximised().then((isMaximized) => { + Window.IsMaximised().then((isMaximized) => { if (isMaximized) { - WindowUnmaximise(); + Window.UnMaximise(); } else { - WindowMaximise(); + Window.Maximise(); } }).catch((err) => { console.error(err); diff --git a/ui/pages/[plugin]/ConnectionListItem.tsx b/ui/pages/[plugin]/ConnectionListItem.tsx index 9b9be50a..27f81646 100644 --- a/ui/pages/[plugin]/ConnectionListItem.tsx +++ b/ui/pages/[plugin]/ConnectionListItem.tsx @@ -15,7 +15,7 @@ import { useConnection } from '@omniviewdev/runtime'; // Types import { stringToColor } from '@/utils/color'; -import { types } from '@omniviewdev/runtime/models'; +import { Connection, ConnectionStatus, ConnectionStatusCode } from '@omniviewdev/runtime/models'; // Icons import { MoreVert } from '@mui/icons-material'; @@ -25,7 +25,7 @@ import { LuPencil, LuTrash } from 'react-icons/lu'; import { Link, usePluginRouter } from '@infraview/router'; import { useSnackbar } from '@omniviewdev/runtime'; -type Props = Omit; +type Props = Omit; function stringAvatar(name: string) { if (!name) { @@ -86,9 +86,9 @@ const ConnectionListItem: React.FC = ({ id, name, description, avatar, la const { startConnection } = useConnection({ pluginID: plugin.id, connectionID: id }); const [connecting, setConnecting] = React.useState(false); - const handleConnectionStatus = (status: types.ConnectionStatus) => { + const handleConnectionStatus = (status: ConnectionStatus) => { switch (status.status) { - case types.ConnectionStatusCode.UNAUTHORIZED: + case ConnectionStatusCode.ConnectionStatusUnauthorized: showSnackbar({ status: 'warning', message: `Failed to authorize to '${name}'`, @@ -96,7 +96,7 @@ const ConnectionListItem: React.FC = ({ id, name, description, avatar, la icon: 'LuShieldClose', }); break; - case types.ConnectionStatusCode.CONNECTED: + case ConnectionStatusCode.ConnectionStatusConnected: // showSnackbar({ // status: 'success', // message: `Connected to '${name}'`, diff --git a/ui/pages/[plugin]/ConnectionTable.tsx b/ui/pages/[plugin]/ConnectionTable.tsx index 701b563d..553d8b91 100644 --- a/ui/pages/[plugin]/ConnectionTable.tsx +++ b/ui/pages/[plugin]/ConnectionTable.tsx @@ -5,17 +5,17 @@ import Box from '@mui/material/Box'; import { Text } from '@omniviewdev/ui/typography'; // types -import { type types } from '@omniviewdev/runtime/models'; +import type { Connection } from '@omniviewdev/runtime/models'; // icons import ConnectionTableItem from './ConnectionTableItem'; type Props = { - connections: types.Connection[]; + connections: Connection[]; }; -const getConnectionOrderedLabelCols = (connections: types.Connection[]) => { +const getConnectionOrderedLabelCols = (connections: Connection[]) => { const px = 7; const maxLabelWidth = 400; diff --git a/ui/pages/[plugin]/ConnectionTableItem.tsx b/ui/pages/[plugin]/ConnectionTableItem.tsx index 08118c36..f2c26134 100644 --- a/ui/pages/[plugin]/ConnectionTableItem.tsx +++ b/ui/pages/[plugin]/ConnectionTableItem.tsx @@ -17,7 +17,7 @@ import { // Types import { stringToColor } from '@/utils/color'; -import { types } from '@omniviewdev/runtime/models'; +import { Connection, ConnectionStatus, ConnectionStatusCode } from '@omniviewdev/runtime/models'; // Icons import { MoreVert } from '@mui/icons-material'; @@ -26,7 +26,7 @@ import { LuPencil, LuTrash } from 'react-icons/lu'; // Third-party import { Link, usePluginRouter } from '@infraview/router'; -type Props = Omit; +type Props = Omit; const truncate = (input: string) => input.length > 60 ? `${input.substring(0, 60)}...` : input; @@ -89,9 +89,9 @@ const ConnectionTableItem: React.FC = ({ id, name, description, avatar, l const { startConnection } = useConnection({ pluginID: plugin.id, connectionID: id }); const [connecting, setConnecting] = React.useState(false); - const handleConnectionStatus = (status: types.ConnectionStatus) => { + const handleConnectionStatus = (status: ConnectionStatus) => { switch (status.status) { - case types.ConnectionStatusCode.UNAUTHORIZED: + case ConnectionStatusCode.ConnectionStatusUnauthorized: showSnackbar({ status: 'warning', message: `Failed to authorize to '${name}'`, @@ -99,7 +99,7 @@ const ConnectionTableItem: React.FC = ({ id, name, description, avatar, l icon: 'LuShieldClose', }); break; - case types.ConnectionStatusCode.CONNECTED: + case ConnectionStatusCode.ConnectionStatusConnected: showSnackbar({ status: 'success', message: `Connected to '${name}'`, diff --git a/ui/pages/[plugin]/[connectionID]/resources/ResourceTableView.tsx b/ui/pages/[plugin]/[connectionID]/resources/ResourceTableView.tsx index a1ce6ee7..8bd1478a 100644 --- a/ui/pages/[plugin]/[connectionID]/resources/ResourceTableView.tsx +++ b/ui/pages/[plugin]/[connectionID]/resources/ResourceTableView.tsx @@ -22,7 +22,7 @@ import { } from '@omniviewdev/runtime'; // Types -import { type types } from '@omniviewdev/runtime/models'; +import type { ResourceMeta } from '@omniviewdev/runtime/models'; // Layout import Layout from '@/layouts/core/sidenav'; @@ -42,7 +42,7 @@ import { LuCog } from 'react-icons/lu'; /** * Get the ID from the meta object */ -const toID = (meta: types.ResourceMeta) => `${meta.group}::${meta.version}::${meta.kind}`; +const toID = (meta: ResourceMeta) => `${meta.group}::${meta.version}::${meta.kind}`; export default function ResourceTableView(): React.ReactElement { const theme = useTheme(); diff --git a/ui/pages/connecting/index.tsx b/ui/pages/connecting/index.tsx index 71d07a06..edd30e28 100644 --- a/ui/pages/connecting/index.tsx +++ b/ui/pages/connecting/index.tsx @@ -13,7 +13,7 @@ import { List, ListItem, ListSubheader } from '@omniviewdev/ui'; import { produce } from 'immer'; import { usePluginRouter } from '@infraview/router'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { handleRemoveTab } from '@/store/tabs/slice'; import { useDispatch } from 'react-redux'; @@ -196,13 +196,13 @@ const Connecting: FC = () => { // Go is much faster here, so we may actually receive the event before we're done setting up the listeners // so we need to make sure we're listening before we start the switch context - const readyCloser = EventsOn(ReadyEvent, (resource: string) => { - dispatch({ type: 'MARK_RESOURCE_READY', payload: resource }); + const readyCloser = Events.On(ReadyEvent, (ev) => { + dispatch({ type: 'MARK_RESOURCE_READY', payload: ev.data as string }); }); - const errorCloser = EventsOn(ErrorEvent, (resource: string) => { - dispatch({ type: 'MARK_RESOURCE_ERROR', payload: resource }); + const errorCloser = Events.On(ErrorEvent, (ev) => { + dispatch({ type: 'MARK_RESOURCE_ERROR', payload: ev.data as string }); }); - const allReadyCloser = EventsOn(AllReadyEvent, () => { + const allReadyCloser = Events.On(AllReadyEvent, () => { handleInitialized(); }); // diff --git a/ui/pages/home/HomepageCard.tsx b/ui/pages/home/HomepageCard.tsx index 67b4b2cb..3626cd34 100644 --- a/ui/pages/home/HomepageCard.tsx +++ b/ui/pages/home/HomepageCard.tsx @@ -6,14 +6,70 @@ import Tooltip from '@mui/material/Tooltip'; import SettingsIcon from '@mui/icons-material/Settings'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import VisibilityIcon from '@mui/icons-material/Visibility'; +import { ErrorBoundary, type FallbackProps } from 'react-error-boundary'; +import { LuRotateCw, LuTriangleAlert } from 'react-icons/lu'; import { Text } from '@omniviewdev/ui/typography'; import { Stack } from '@omniviewdev/ui/layout'; +import MuiButton from '@mui/material/Button'; import { PluginContext } from '@omniviewdev/runtime'; -import { config as runtimeConfig } from '@omniviewdev/runtime/models'; +import { PluginMeta } from '@omniviewdev/runtime/models'; import type { ExtensionContributionRegistration } from '@omniviewdev/runtime'; import type { HomepageCardProps, HomepageCardMeta, HomepageCardConfig } from '@/features/extensions/homepage/types'; import HomepageCardConfigPopover from './HomepageCardConfigPopover'; +/** + * Card-specific error fallback that fills the card content area with a + * centered, visually integrated error state. + */ +function CardErrorFallback({ error, resetErrorBoundary, label }: FallbackProps & { label: string }) { + return ( + + + + + + + {label} failed to load + + + {error.message.length > 120 ? error.message.slice(0, 120) + '…' : error.message} + + + } + sx={{ textTransform: 'none', fontSize: 12 }} + > + Retry + + + ); +} + type Props = { registration: ExtensionContributionRegistration>; config: HomepageCardConfig; @@ -35,7 +91,7 @@ const HomepageCard: React.FC = ({ const providerValue = useMemo(() => ({ pluginId: registration.plugin, - meta: new runtimeConfig.PluginMeta(), + meta: new PluginMeta(), settings: {}, }), [registration.plugin]); @@ -105,12 +161,19 @@ const HomepageCard: React.FC = ({ )} - {/* Card content — use a lightweight context provider instead of - PluginContextProvider which blocks rendering on async metadata fetch */} + {/* Card content — wrapped in per-card error boundary so a single + plugin crash doesn't take down the entire homepage */} - - - + ( + + )} + resetKeys={[registration.id]} + > + + + + {/* Config popover */} diff --git a/ui/pages/plugins/InstalledPluginCard.tsx b/ui/pages/plugins/InstalledPluginCard.tsx index fee12ccd..6cb5b671 100644 --- a/ui/pages/plugins/InstalledPluginCard.tsx +++ b/ui/pages/plugins/InstalledPluginCard.tsx @@ -16,7 +16,7 @@ import { LuAtom, LuRefreshCcwDot, LuView } from 'react-icons/lu'; // Hooks import { usePlugin } from '@/hooks/plugin/usePluginManager'; -import { BrowserOpenURL } from '@omniviewdev/runtime/runtime'; +import { Browser } from '@omniviewdev/runtime/runtime'; import UninstallPluginModal from './UninstallPluginModal'; import PluginUpdateButton from './PluginUpdateButton'; import DevModeSection from './DevModeSection'; @@ -38,7 +38,7 @@ const InstalledPluginCard: React.FC = ({ id }) => { url = `https://${url}`; } if (url !== undefined) { - BrowserOpenURL(url); + Browser.OpenURL(url); } }; diff --git a/ui/pages/plugins/PluginDetails.tsx b/ui/pages/plugins/PluginDetails.tsx index 88398820..7ae0e26f 100644 --- a/ui/pages/plugins/PluginDetails.tsx +++ b/ui/pages/plugins/PluginDetails.tsx @@ -15,7 +15,7 @@ import MarkdownPreview from '@uiw/react-markdown-preview'; import { useParams, useNavigate } from 'react-router-dom'; import { LuDownload, LuExternalLink } from 'react-icons/lu'; import { usePluginManager, usePlugin } from '@/hooks/plugin/usePluginManager'; -import { BrowserOpenURL } from '@omniviewdev/runtime/runtime'; +import { Browser } from '@omniviewdev/runtime/runtime'; import PluginUpdateButton from './PluginUpdateButton'; import UninstallPluginModal from './UninstallPluginModal'; import PluginChangelog from './sections/PluginChangelog'; @@ -123,7 +123,7 @@ const PluginDetails: FC = () => { {displayRepository && ( BrowserOpenURL(displayRepository)} + onClick={() => Browser.OpenURL(displayRepository)} sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.5, cursor: 'pointer', '&:hover': { opacity: 0.8 } }} > diff --git a/ui/pages/settings/SettingsEntries.tsx b/ui/pages/settings/SettingsEntries.tsx index 058fecb2..01c8cabd 100644 --- a/ui/pages/settings/SettingsEntries.tsx +++ b/ui/pages/settings/SettingsEntries.tsx @@ -8,11 +8,11 @@ import { Text } from '@omniviewdev/ui/typography'; // Types import { type SectionSelection } from '.'; import SettingsEntry from './SettingsEntry'; -import { type settings } from '@omniviewdev/runtime/models'; +import type { Setting } from '@omniviewdev/runtime/models'; import { useDevMode } from '@/hooks/useDevMode'; type Props = SectionSelection & { - settings: Record; + settings: Record; draftValues: Record; setDraftValues: (draftValues: Record) => void; }; diff --git a/ui/pages/settings/SettingsEntry.tsx b/ui/pages/settings/SettingsEntry.tsx index 26969724..c10f3956 100644 --- a/ui/pages/settings/SettingsEntry.tsx +++ b/ui/pages/settings/SettingsEntry.tsx @@ -10,13 +10,14 @@ import { Select } from '@omniviewdev/ui/inputs'; import { Stack } from '@omniviewdev/ui/layout'; // Hooks -import { main, settings } from '@omniviewdev/runtime/models'; +import { FileDialogOptions, SettingType } from '@omniviewdev/runtime/models'; +import type { Setting } from '@omniviewdev/runtime/models'; import { parseAppError } from '@omniviewdev/runtime'; import { LuFile } from 'react-icons/lu'; import { OpenFileSelectionDialog } from '@omniviewdev/runtime/api'; type Props = { - setting: settings.Setting; + setting: Setting; id: string; draftValue: any; handleChange: (name: string, value: any) => void; @@ -42,7 +43,7 @@ const SettingsEntry: React.FC = ({ setting, id, draftValue, handleChange const settingType = setting.type as unknown as string; switch (settingType) { - case settings.SettingType.TEXT: + case SettingType.Text: /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */ return ; case 'select': @@ -51,11 +52,11 @@ const SettingsEntry: React.FC = ({ setting, id, draftValue, handleChange case 'multiselect': /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */ return ; - case settings.SettingType.TOGGLE: + case SettingType.Toggle: /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */ return ; - case settings.SettingType.INTEGER: - case settings.SettingType.FLOAT: + case SettingType.Integer: + case SettingType.Float: /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */ return ; default: @@ -76,7 +77,7 @@ const TextSetting: React.FC = ({ setting, id, draftValue, handleChange }) newValue = []; } - OpenFileSelectionDialog(main.FileDialogOptions.createFrom({ + OpenFileSelectionDialog(FileDialogOptions.createFrom({ showHiddenFiles: true, })).then((result) => { console.log('File selection dialog result:', result); @@ -217,7 +218,7 @@ const MultiSelectSetting: React.FC = ({ setting, id, draftValue, handleCh const newValue = toStringArray(isChanged ? draftValue : setting.value); - OpenFileSelectionDialog(main.FileDialogOptions.createFrom({ + OpenFileSelectionDialog(FileDialogOptions.createFrom({ showHiddenFiles: true, })).then((result) => { if (result) { diff --git a/ui/providers/BottomDrawer/__tests__/tabs.test.tsx b/ui/providers/BottomDrawer/__tests__/tabs.test.tsx index d637f32d..08baef18 100644 --- a/ui/providers/BottomDrawer/__tests__/tabs.test.tsx +++ b/ui/providers/BottomDrawer/__tests__/tabs.test.tsx @@ -48,23 +48,21 @@ vi.mock('@omniviewdev/runtime/api', () => ({ })); vi.mock('@omniviewdev/runtime/models', () => ({ - exec: { - CreateTerminalOptions: { - createFrom: (opts: any) => opts, - }, + SessionOptions: { + createFrom: (opts: any) => opts, }, - logs: { - CreateSessionOptions: { - createFrom: (opts: any) => opts, - }, - LogSessionOptions: { - createFrom: (opts: any) => opts, - }, + CreateSessionOptions: { + createFrom: (opts: any) => opts, + }, + LogSessionOptions: { + createFrom: (opts: any) => opts, }, })); vi.mock('@omniviewdev/runtime/runtime', () => ({ - EventsOn: mocks.mockEventsOn, + Events: { + On: mocks.mockEventsOn, + }, })); vi.mock('../events', () => ({ diff --git a/ui/providers/BottomDrawer/containers/LogViewer/hooks/useLogStream.ts b/ui/providers/BottomDrawer/containers/LogViewer/hooks/useLogStream.ts index 65cc0165..50d7da1f 100644 --- a/ui/providers/BottomDrawer/containers/LogViewer/hooks/useLogStream.ts +++ b/ui/providers/BottomDrawer/containers/LogViewer/hooks/useLogStream.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useRef } from 'react'; -import { EventsOn, EventsOff } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import type { LogEntry, LogStreamEvent, RawLogLine } from '../types'; import { parseRawLogLine } from '../utils/parseLogLine'; @@ -32,7 +32,8 @@ export function useLogStream({ sessionId, onLines, onEvent, paused }: UseLogStre const linesKey = `core/logs/lines/${sessionId}`; const eventKey = `core/logs/event/${sessionId}`; - const linesCleanup = EventsOn(linesKey, (data: string) => { + const linesCleanup = Events.On(linesKey, (ev) => { + const data = ev.data as string; try { const rawLines: RawLogLine[] = JSON.parse(data); const entries = rawLines.map(raw => parseRawLogLine(raw, ++lineCounterRef.current)); @@ -47,7 +48,8 @@ export function useLogStream({ sessionId, onLines, onEvent, paused }: UseLogStre } }); - const eventCleanup = EventsOn(eventKey, (data: string) => { + const eventCleanup = Events.On(eventKey, (ev) => { + const data = ev.data as string; try { const event: LogStreamEvent = JSON.parse(data); onEvent(event); @@ -59,8 +61,8 @@ export function useLogStream({ sessionId, onLines, onEvent, paused }: UseLogStre return () => { linesCleanup(); eventCleanup(); - EventsOff(linesKey); - EventsOff(eventKey); + Events.Off(linesKey); + Events.Off(eventKey); }; }, [sessionId, onLines, onEvent]); diff --git a/ui/providers/BottomDrawer/containers/LogViewer/sources/sessionSource.ts b/ui/providers/BottomDrawer/containers/LogViewer/sources/sessionSource.ts index 00087290..aded33cd 100644 --- a/ui/providers/BottomDrawer/containers/LogViewer/sources/sessionSource.ts +++ b/ui/providers/BottomDrawer/containers/LogViewer/sources/sessionSource.ts @@ -1,4 +1,4 @@ -import { EventsOn, EventsOff } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import type { LogDataSource, LogStreamEvent, RawLogLine } from '../types'; import { parseRawLogLine } from '../utils/parseLogLine'; @@ -15,7 +15,8 @@ export function createSessionSource(sessionId: string): LogDataSource { const linesKey = `core/logs/lines/${sessionId}`; const eventKey = `core/logs/event/${sessionId}`; - const linesCleanup = EventsOn(linesKey, (data: string) => { + const linesCleanup = Events.On(linesKey, (ev) => { + const data = ev.data as string; try { const rawLines: RawLogLine[] = JSON.parse(data); const entries = rawLines.map(raw => parseRawLogLine(raw, ++lineCounter)); @@ -25,7 +26,8 @@ export function createSessionSource(sessionId: string): LogDataSource { } }); - const eventCleanup = EventsOn(eventKey, (data: string) => { + const eventCleanup = Events.On(eventKey, (ev) => { + const data = ev.data as string; try { const event: LogStreamEvent = JSON.parse(data); handlers.onEvent(event); @@ -37,8 +39,8 @@ export function createSessionSource(sessionId: string): LogDataSource { return () => { linesCleanup(); eventCleanup(); - EventsOff(linesKey); - EventsOff(eventKey); + Events.Off(linesKey); + Events.Off(eventKey); }; }, // No loadHistory — SDK sessions stream from the beginning. diff --git a/ui/providers/BottomDrawer/containers/Terminal.tsx b/ui/providers/BottomDrawer/containers/Terminal.tsx index 230a915c..b7d3f750 100644 --- a/ui/providers/BottomDrawer/containers/Terminal.tsx +++ b/ui/providers/BottomDrawer/containers/Terminal.tsx @@ -14,10 +14,10 @@ import { debounce } from '@/utils/debounce'; // project import import { ExecClient } from '@omniviewdev/runtime/api'; -import { exec } from '@omniviewdev/runtime/models'; +import { SessionOptions } from '@omniviewdev/runtime/models'; import log from '@/features/logger'; import { bottomDrawerChannel } from '../events'; -import * as runtime from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; import { Base64 } from 'js-base64'; import { useSettings, parseAppError } from '@omniviewdev/runtime'; import type { BottomDrawerTab } from '@omniviewdev/runtime'; @@ -121,7 +121,7 @@ export default function TerminalContainer({ sessionId, tab }: Props) { } // Build session opts from stored tab properties, overriding command - const opts = exec.SessionOptions.createFrom({ + const opts = SessionOptions.createFrom({ tty: true, ...((props.opts ?? {}) as Record), command, @@ -251,7 +251,8 @@ export default function TerminalContainer({ sessionId, tab }: Props) { // that fail immediately (e.g., ERROR followed by CLOSE). const setupSignalHandlers = () => { // ERROR signal: structured error from plugin layer - runtime.EventsOn(constructSignalHandler('ERROR', sessionId), (errorInfo: any) => { + Events.On(constructSignalHandler('ERROR', sessionId), (ev) => { + const errorInfo = ev.data as any; if (errorInfo && typeof errorInfo === 'object') { const info: TerminalErrorInfo = { title: errorInfo.title || errorInfo.Title || 'Session error', @@ -266,7 +267,7 @@ export default function TerminalContainer({ sessionId, tab }: Props) { }); // CLOSE signal: session is done - runtime.EventsOn(constructSignalHandler('CLOSE', sessionId), () => { + Events.On(constructSignalHandler('CLOSE', sessionId), () => { // If an error overlay is already showing, don't auto-close the tab if (errorRef.current) { return; @@ -277,28 +278,30 @@ export default function TerminalContainer({ sessionId, tab }: Props) { } }); - runtime.EventsOn(constructSignalHandler('SIGINT', sessionId), () => { console.log('SIGINT'); }); - runtime.EventsOn(constructSignalHandler('SIGQUIT', sessionId), () => { console.log('SIGQUIT'); }); - runtime.EventsOn(constructSignalHandler('SIGTERM', sessionId), () => { console.log('SIGTERM'); }); - runtime.EventsOn(constructSignalHandler('SIGKILL', sessionId), () => { console.log('SIGKILL'); }); - runtime.EventsOn(constructSignalHandler('SIGHUP', sessionId), () => { console.log('SIGHUP'); }); - runtime.EventsOn(constructSignalHandler('SIGUSR1', sessionId), () => { console.log('SIGUSR1'); }); - runtime.EventsOn(constructSignalHandler('SIGUSR2', sessionId), () => { console.log('SIGUSR2'); }); - runtime.EventsOn(constructSignalHandler('SIGWINCH', sessionId), () => { console.log('SIGWINCH'); }); + Events.On(constructSignalHandler('SIGINT', sessionId), () => { console.log('SIGINT'); }); + Events.On(constructSignalHandler('SIGQUIT', sessionId), () => { console.log('SIGQUIT'); }); + Events.On(constructSignalHandler('SIGTERM', sessionId), () => { console.log('SIGTERM'); }); + Events.On(constructSignalHandler('SIGKILL', sessionId), () => { console.log('SIGKILL'); }); + Events.On(constructSignalHandler('SIGHUP', sessionId), () => { console.log('SIGHUP'); }); + Events.On(constructSignalHandler('SIGUSR1', sessionId), () => { console.log('SIGUSR1'); }); + Events.On(constructSignalHandler('SIGUSR2', sessionId), () => { console.log('SIGUSR2'); }); + Events.On(constructSignalHandler('SIGWINCH', sessionId), () => { console.log('SIGWINCH'); }); }; setupSignalHandlers(); // Function to handle attachment logic const attachToSession = async () => { - runtime.EventsOn(stdout, (data: any) => { + Events.On(stdout, (ev) => { + const data = ev.data; if (data !== null && data !== undefined) { const decoded = textDecoder.decode(Base64.toUint8Array(data)); terminal.write(decoded); } }); - runtime.EventsOn(stderr, (data: any) => { + Events.On(stderr, (ev) => { + const data = ev.data; if (data !== null && data !== undefined) { const decoded = textDecoder.decode(Base64.toUint8Array(data)); terminal.write(decoded); @@ -353,7 +356,7 @@ export default function TerminalContainer({ sessionId, tab }: Props) { // cleanup signal handlers ['ERROR', 'CLOSE', 'SIGINT', 'SIGQUIT', 'SIGTERM', 'SIGKILL', 'SIGHUP', 'SIGUSR1', 'SIGUSR2', 'SIGWINCH'].forEach((signal) => { - runtime.EventsOff(constructSignalHandler(signal, sessionId)); + Events.Off(constructSignalHandler(signal, sessionId)); }); ExecClient.DetachSession(sessionId).then(() => { }).catch((err: unknown) => { diff --git a/ui/providers/BottomDrawer/containers/__tests__/Terminal.test.tsx b/ui/providers/BottomDrawer/containers/__tests__/Terminal.test.tsx index d743e6ac..7e99bc06 100644 --- a/ui/providers/BottomDrawer/containers/__tests__/Terminal.test.tsx +++ b/ui/providers/BottomDrawer/containers/__tests__/Terminal.test.tsx @@ -65,8 +65,10 @@ vi.mock('@xterm/addon-web-links', () => ({ // ─── runtime mocks ───────────────────────────────────────────────────────────── vi.mock('@omniviewdev/runtime/runtime', () => ({ - EventsOn: mocks.mockEventsOn, - EventsOff: mocks.mockEventsOff, + Events: { + On: mocks.mockEventsOn, + Off: mocks.mockEventsOff, + }, })); vi.mock('@omniviewdev/runtime/api', () => ({ diff --git a/ui/providers/BottomDrawer/events.ts b/ui/providers/BottomDrawer/events.ts index 49fe6f8c..d6cde4aa 100644 --- a/ui/providers/BottomDrawer/events.ts +++ b/ui/providers/BottomDrawer/events.ts @@ -1,10 +1,10 @@ import { eventbus } from '@/events/eventbus'; -import { type exec } from '@omniviewdev/runtime/models'; +import type { SessionOptions } from '@omniviewdev/runtime/models'; type OnCreateSessionOpts = { plugin: string; connection: string; - opts: exec.SessionOptions; + opts: SessionOptions; icon?: string; label?: string; }; diff --git a/ui/providers/BottomDrawer/tabs.tsx b/ui/providers/BottomDrawer/tabs.tsx index 962ad817..2a584a0d 100644 --- a/ui/providers/BottomDrawer/tabs.tsx +++ b/ui/providers/BottomDrawer/tabs.tsx @@ -31,13 +31,13 @@ import { import Icon from '@/components/icons/Icon'; import { LuChevronDown, LuChevronUp, LuMaximize, LuMinimize, LuPlus, LuX } from 'react-icons/lu'; import { useSettings } from '@omniviewdev/runtime'; -import { exec, logs } from '@omniviewdev/runtime/models'; +import { SessionOptions, CreateSessionOptions, LogSessionOptions } from '@omniviewdev/runtime/models'; import { ExecClient, LogsClient } from '@omniviewdev/runtime/api'; import { bottomDrawerChannel } from './events'; import { devToolsChannel } from '@/features/devtools/events'; import { pluginLogChannel } from '@/features/pluginlogs/events'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; type Props = { hasTabs: boolean; @@ -96,7 +96,7 @@ const BottomDrawerTabs: React.FC = ({ hasTabs, isMinimized, isFullscreen, icon: 'LuSquareTerminal', properties: { status: 'connecting' }, }); - ExecClient.CreateTerminal(exec.CreateTerminalOptions.createFrom({ command: [settings['terminal.defaultShell'] || '/bin/bash'] })) + ExecClient.CreateTerminal(SessionOptions.createFrom({ command: [settings['terminal.defaultShell'] || '/bin/bash'] })) .then((session: any) => { updateTab( { id: tempId }, @@ -173,11 +173,11 @@ const BottomDrawerTabs: React.FC = ({ hasTabs, isMinimized, isFullscreen, const unsubscribeCreateLogSession = bottomDrawerChannel.on('onCreateLogSession', ({ plugin, connection, resourceKey, resourceID, resourceData, target, follow, tailLines, icon, label, params, }) => { - const opts = logs.CreateSessionOptions.createFrom({ + const opts = CreateSessionOptions.createFrom({ resource_key: resourceKey, resource_id: resourceID, resource_data: resourceData, - options: logs.LogSessionOptions.createFrom({ + options: LogSessionOptions.createFrom({ target: target ?? '', follow: follow ?? true, include_previous: false, @@ -337,7 +337,7 @@ const BottomDrawerTabs: React.FC = ({ hasTabs, isMinimized, isFullscreen, console.error(err); }); - const closerTerminal = EventsOn("menu/view/terminal/create", () => handleCreate('terminal')) + const closerTerminal = Events.On("menu/view/terminal/create", () => handleCreate('terminal')) return () => { closerTerminal() diff --git a/ui/providers/RightDrawer/index.tsx b/ui/providers/RightDrawer/index.tsx index a8d3e264..3031129a 100644 --- a/ui/providers/RightDrawer/index.tsx +++ b/ui/providers/RightDrawer/index.tsx @@ -12,7 +12,7 @@ import RightDrawerContext, { type RightDrawerContextType } from '@/contexts/Righ // local imports import ResourceDrawerContainer from '@/federation/ResourceSidebarComponent'; -import { EventsOn } from '@omniviewdev/runtime/runtime'; +import { Events } from '@omniviewdev/runtime/runtime'; type RightDrawerProviderProps = { children: ReactNode; @@ -149,7 +149,7 @@ const RightDrawerProvider: React.FC = ({ children }) = }, []); React.useEffect(() => { - const closerMinimize = EventsOn("menu/view/sidebar/minimize", () => closeDrawer()) + const closerMinimize = Events.On("menu/view/sidebar/minimize", () => closeDrawer()) return () => { closerMinimize() diff --git a/ui/providers/RightDrawerProvider.tsx b/ui/providers/RightDrawerProvider.tsx index 65b1b558..75c59c47 100644 --- a/ui/providers/RightDrawerProvider.tsx +++ b/ui/providers/RightDrawerProvider.tsx @@ -18,7 +18,7 @@ import { showAppError, } from '@omniviewdev/runtime'; import { ResourceClient } from '@omniviewdev/runtime/api'; -import { resource } from '@omniviewdev/runtime/models'; +import { UpdateInput, GetInput } from '@omniviewdev/runtime/models'; import RightDrawer from '@/components/displays/RightDrawer'; import { bottomDrawerChannel } from './BottomDrawer/events'; import { createLinkedResourceDrawer } from '@/federation/LinkedResourceDrawer'; @@ -228,7 +228,7 @@ const RightDrawerProvider: React.FC = ({ children }) => { params.pluginID, params.connectionID, params.resourceKey, - resource.UpdateInput.createFrom({ + UpdateInput.createFrom({ input: value, params: {}, id: params.resourceID, @@ -258,7 +258,7 @@ const RightDrawerProvider: React.FC = ({ children }) => { params.pluginID, params.connectionID, params.resourceKey, - resource.GetInput.createFrom({ + GetInput.createFrom({ id: params.resourceID, namespace: params.namespace ?? '', params: {}, diff --git a/vite.config.ts b/vite.config.ts index b3447d5a..d9aa8a67 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'vitest/config'; -import react from '@vitejs/plugin-react'; -// import federation from '@originjs/vite-plugin-federation'; -// import topLevelAwait from 'vite-plugin-top-level-await'; +import react, { reactCompilerPreset } from '@vitejs/plugin-react'; +import babel from '@rolldown/plugin-babel'; +import wails from '@wailsio/runtime/plugins/vite'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -11,10 +11,6 @@ import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const reactCompilerConfig = { - target: '19', -}; - // https://vitejs.dev/config/ export default defineConfig({ test: { @@ -29,24 +25,22 @@ export default defineConfig({ sourcemap: false, }, server: { - host: true, - port: 5173, + // Port is set via WAILS_VITE_PORT env var (wails3 dev sets it automatically). + // Fallback to 9245 to match the default in Taskfile.yml. + port: parseInt(process.env.WAILS_VITE_PORT || '9245'), strictPort: true, - proxy: { - '/_/': { - bypass: function () { - // Return false to produce a 404 error for the request. - return false; - }, - }, + // Wails webview loads from wails://localhost — force HMR to connect + // via ws:// to localhost so it resolves correctly. + // See: https://github.com/wailsapp/wails/issues/3064 + hmr: { + host: 'localhost', + protocol: 'ws', }, }, plugins: [ - react({ - babel: { - plugins: [['babel-plugin-react-compiler', reactCompilerConfig]], - }, - }), + react(), + babel({ presets: [reactCompilerPreset({ target: '19' })] }), + wails('./packages/omniviewdev-runtime/src/bindings'), { name: 'strip-dev-scripts', transformIndexHtml(html, ctx) { diff --git a/wails.json b/wails.json deleted file mode 100644 index 08206341..00000000 --- a/wails.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://wails.io/schemas/config.v2.json", - "name": "Omniview", - "outputfilename": "Omniview", - "frontend:dir": "./ui", - "frontend:install": "pnpm install", - "frontend:build": "pnpm run build", - "frontend:dev:watcher": "pnpm run dev", - "frontend:dev:serverUrl": "http://localhost:5173", - "wailsjsdir": "./packages/omniviewdev-runtime/src/", - "author": { - "name": "Joshua Pare", - "email": "jpare@omniview.dev" - }, - "bindings": { - "ts_generation": { - "prefix": "", - "suffix": "", - "outputType": "classes" - } - }, - "fileAssociations": [ - { - "ext": "icns", - "name": "favicon", - "description": "AppIcon", - "iconName": "fileIcon", - "role": "Editor" - } - ] -}