@agenthippo-ai/agenthippo 1.110.9 → 1.110.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/agentpack/types.js +2 -5
- package/out/analytics/dashboard/artifactManager.js +2 -439
- package/out/analytics/dashboard/fleetDisplayUtils.js +2 -162
- package/out/analytics/dashboard/fleetOrchestrator.js +3 -142
- package/out/analytics/dashboard/fleetRegistry.js +2 -79
- package/out/analytics/dashboard/fleetRowDefaults.js +2 -87
- package/out/analytics/dashboard/fleetScriptAdapter.js +2 -146
- package/out/analytics/dashboard/fleetTypes.js +2 -29
- package/out/analytics/dashboard/index.js +2 -17
- package/out/analytics/dashboard/indexingService.js +2 -422
- package/out/analytics/dashboard/localFleetAdapter.js +2 -222
- package/out/analytics/dashboard/performanceMonitor.js +5 -76
- package/out/analytics/dashboard/processManager.js +2 -209
- package/out/analytics/dashboard/provider.js +38 -3817
- package/out/analytics/dashboard/queryRunner.js +62 -750
- package/out/analytics/dashboard/scheduledFleetStorage.js +2 -241
- package/out/analytics/dashboard/sessionJsonlFleet.js +3 -204
- package/out/analytics/dashboard/teamViewDiscovery.js +2 -106
- package/out/analytics/dashboard/webview/panel.js +34 -2318
- package/out/analytics/dashboard/webview/runtime-bridge.js +2 -82
- package/out/analytics/lifecycle.js +2 -43
- package/out/analytics/service.js +8 -1277
- package/out/auth/authBaseUrl.js +2 -59
- package/out/auth/bootstrapApply.js +2 -71
- package/out/auth/brokerClient.js +2 -160
- package/out/auth/callbackUri.js +2 -59
- package/out/auth/githubStoreGate.js +2 -70
- package/out/auth/loopbackAuthServer.js +4 -159
- package/out/auth/onboardingPrompt.js +2 -112
- package/out/auth/pkce.js +2 -9
- package/out/auth/provider.js +2 -226
- package/out/auth/sessionStore.js +2 -156
- package/out/auth/signInFlow.js +2 -183
- package/out/cli/index.js +619 -551
- package/out/cli/run-custom-engine-runner.js +3 -318
- package/out/cli/vscode-shim.js +2 -86
- package/out/engines/factory.js +2 -45
- package/out/engines/types.js +2 -17
- package/out/examples/run-headless-repl.js +6 -286
- package/out/examples/run-headless.js +2 -187
- package/out/extension.js +32 -4473
- package/out/gateway/gatewayRouteIndex.js +6 -371
- package/out/gateway/gatewaySessionStore.js +3 -243
- package/out/gateway/index.js +2 -31
- package/out/gateway/resetMappings.js +2 -52
- package/out/gateway/service.js +5 -1249
- package/out/mcp/publish.js +2 -143
- package/out/remote/handleRemoteChat.js +2 -169
- package/out/remote/remotePackStatusBar.js +3 -103
- package/out/remote/remoteTrust.js +6 -277
- package/out/remote/serveClient.js +4 -277
- package/out/remoteSkills.js +3 -191
- package/out/runtime/index.js +2 -32
- package/out/runtime/vscode/index.js +2 -20
- package/out/runtime/vscode/vscode-config-provider.js +2 -77
- package/out/runtime/vscode/vscode-edit-tracker.js +2 -122
- package/out/runtime/vscode/vscode-logger.js +2 -30
- package/out/runtime/vscode/vscode-permission-handler.js +2 -72
- package/out/scripts/agentide-litellm.sh +0 -1
- package/out/scripts/agentide_litellm_hooks_v1.py +170 -418
- package/out/scripts/analytics/agent-fleet-widget.js +18 -257
- package/out/scripts/analytics/agentide-litellm-otel.config.yaml +4 -4
- package/out/scripts/analytics/duckdbLocator.js +2 -28
- package/out/scripts/analytics/generate-default-charts.py +43 -323
- package/out/scripts/analytics/hotspot-analysis-widget.js +4 -430
- package/out/scripts/analytics/index-traces.py +78 -1036
- package/out/scripts/analytics/session-comparison-widget.js +26 -472
- package/out/scripts/analytics/session-timeline-widget.js +25 -846
- package/out/scripts/analytics/setup-analytics.ps1 +8 -1
- package/out/scripts/analytics/setup-analytics.sh +13 -2
- package/out/scripts/analytics/token-cost-flamegraph-widget.js +4 -461
- package/out/scripts/analytics/token-cost-trend-widget.js +4 -534
- package/out/scripts/analytics/workflows-collector.cjs +4 -314
- package/out/scripts/analytics/workflows-daemon.mjs +9 -185
- package/out/scripts/analytics/workflows-widget.cjs +15 -159
- package/out/scripts/analytics/wow-model-widget.js +10 -120
- package/out/scripts/vendor-tools.mjs +2 -233
- package/out/skills/publish.js +3 -178
- package/out/store/github/setup.js +7 -212
- package/out/store/oramaIndex.js +2 -884
- package/out/sync.js +26 -1829
- package/out/terminalLogger.js +5 -358
- package/out/utils/pathSafety.js +2 -60
- package/out/utils/pythonRunner.js +4 -258
- package/out/utils/toolPath.js +2 -83
- package/out/workspaceFolders.js +2 -59
- package/package.json +1 -1
- package/out/agentpack/github.js +0 -547
- package/out/agentpack/index.js +0 -67
- package/out/agentpack/install.js +0 -297
- package/out/agentpack/manager.js +0 -441
- package/out/agentpack/manifest.js +0 -135
- package/out/agentpack/paths.js +0 -498
- package/out/agentpack/publish.js +0 -248
- package/out/agentpack/stores.js +0 -554
- package/out/analytics/dashboard/fleetStatusUtils.js +0 -30
- package/out/analytics/dashboard/fleetTitleUtils.js +0 -68
- package/out/analytics/dashboard/refreshPolicy.js +0 -16
- package/out/analytics/dashboard/scheduledFleetFingerprint.js +0 -22
- package/out/analytics/dashboard/scheduledFleetUtils.js +0 -22
- package/out/analytics/dashboard/sessionEventFleetStats.js +0 -118
- package/out/analytics/dashboard/viewsConfigMerge.js +0 -221
- package/out/analytics/dashboard/webview/codicon.ttf +0 -0
- package/out/analytics/identity.js +0 -0
- package/out/analytics/sessionEvents.js +0 -323
- package/out/auth/callbackUriParse.js +0 -59
- package/out/auth/types.js +0 -12
- package/out/auth-broker/config.js +0 -112
- package/out/auth-broker/jwt.js +0 -105
- package/out/auth-broker/pkce.js +0 -59
- package/out/auth-broker/server.js +0 -677
- package/out/auth-broker/store.js +0 -275
- package/out/authority/warrant.js +0 -206
- package/out/base-prompts/mcp-servers/.mcp.json +0 -13
- package/out/base-prompts/mcp-servers/langfuse-analytics/README.md +0 -142
- package/out/base-prompts/mcp-servers/langfuse-analytics/mcp.json +0 -13
- package/out/base-prompts/mcp-servers/langfuse-analytics/package-lock.json +0 -1192
- package/out/base-prompts/mcp-servers/langfuse-analytics/package.json +0 -23
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/run-with-env.sh +0 -12
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/sdk-test.js +0 -102
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/simple-test.js +0 -137
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-client.js +0 -118
- package/out/base-prompts/mcp-servers/langfuse-analytics/scripts/test-server.js +0 -209
- package/out/base-prompts/mcp-servers/langfuse-analytics/src/client.ts +0 -431
- package/out/base-prompts/mcp-servers/langfuse-analytics/src/index.ts +0 -270
- package/out/base-prompts/mcp-servers/langfuse-analytics/tsconfig.json +0 -18
- package/out/base-prompts/rules/AGENTS.md +0 -204
- package/out/base-prompts/skills/agent-browser/SKILL.md +0 -102
- package/out/base-prompts/skills/agent-builder/SKILL.md +0 -73
- package/out/base-prompts/skills/agent-builder/references/agent-pack.md +0 -63
- package/out/base-prompts/skills/agent-builder/references/crewai.md +0 -66
- package/out/base-prompts/skills/agent-builder/references/langchain.md +0 -60
- package/out/base-prompts/skills/agent-builder/references/raw-sdk.md +0 -73
- package/out/base-prompts/skills/agent-engine-creator/SKILL.md +0 -586
- package/out/base-prompts/skills/agent-engine-installer/SKILL.md +0 -106
- package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.mjs +0 -259
- package/out/base-prompts/skills/agent-engine-installer/scripts/install-engine.ps1 +0 -189
- package/out/base-prompts/skills/agenthippo-cli/SKILL.md +0 -69
- package/out/base-prompts/skills/agenthippo-cli/scripts/install.sh +0 -63
- package/out/base-prompts/skills/agentpack-creator/SKILL.md +0 -375
- package/out/base-prompts/skills/agentpack-creator/references/agent-templates.md +0 -261
- package/out/base-prompts/skills/agentpack-creator/references/agents-md-guide.md +0 -195
- package/out/base-prompts/skills/agentpack-creator/scripts/init_pack.py +0 -391
- package/out/base-prompts/skills/agentpack-creator/scripts/init_pack_test.py +0 -294
- package/out/base-prompts/skills/agentpack-testbench/SKILL.md +0 -135
- package/out/base-prompts/skills/algorithmic-art/LICENSE.txt +0 -202
- package/out/base-prompts/skills/algorithmic-art/SKILL.md +0 -405
- package/out/base-prompts/skills/algorithmic-art/templates/generator_template.js +0 -223
- package/out/base-prompts/skills/algorithmic-art/templates/viewer.html +0 -599
- package/out/base-prompts/skills/debug-agent/SKILL.md +0 -83
- package/out/base-prompts/skills/desktop-automation/SKILL.md +0 -166
- package/out/base-prompts/skills/desktop-automation/references/agenthippo-ui-recipes.md +0 -441
- package/out/base-prompts/skills/desktop-automation/scripts/windows-desktop-uia.psm1 +0 -280
- package/out/base-prompts/skills/docx/LICENSE.txt +0 -30
- package/out/base-prompts/skills/docx/SKILL.md +0 -197
- package/out/base-prompts/skills/docx/docx-js.md +0 -350
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/out/base-prompts/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/out/base-prompts/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/out/base-prompts/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/out/base-prompts/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/out/base-prompts/skills/docx/ooxml/scripts/pack.py +0 -159
- package/out/base-prompts/skills/docx/ooxml/scripts/unpack.py +0 -29
- package/out/base-prompts/skills/docx/ooxml/scripts/validate.py +0 -69
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/base.py +0 -951
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/docx.py +0 -274
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
- package/out/base-prompts/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
- package/out/base-prompts/skills/docx/ooxml.md +0 -610
- package/out/base-prompts/skills/docx/scripts/__init__.py +0 -1
- package/out/base-prompts/skills/docx/scripts/document.py +0 -1276
- package/out/base-prompts/skills/docx/scripts/templates/comments.xml +0 -3
- package/out/base-prompts/skills/docx/scripts/templates/commentsExtended.xml +0 -3
- package/out/base-prompts/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
- package/out/base-prompts/skills/docx/scripts/templates/commentsIds.xml +0 -3
- package/out/base-prompts/skills/docx/scripts/templates/people.xml +0 -3
- package/out/base-prompts/skills/docx/scripts/utilities.py +0 -374
- package/out/base-prompts/skills/gateway-outbound/SKILL.md +0 -136
- package/out/base-prompts/skills/mcp-builder/LICENSE.txt +0 -202
- package/out/base-prompts/skills/mcp-builder/SKILL.md +0 -328
- package/out/base-prompts/skills/mcp-builder/reference/evaluation.md +0 -602
- package/out/base-prompts/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
- package/out/base-prompts/skills/mcp-builder/reference/node_mcp_server.md +0 -970
- package/out/base-prompts/skills/mcp-builder/reference/python_mcp_server.md +0 -719
- package/out/base-prompts/skills/mcp-builder/scripts/connections.py +0 -151
- package/out/base-prompts/skills/mcp-builder/scripts/evaluation.py +0 -373
- package/out/base-prompts/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
- package/out/base-prompts/skills/mcp-builder/scripts/requirements.txt +0 -2
- package/out/base-prompts/skills/openclaw/SKILL.md +0 -406
- package/out/base-prompts/skills/openclaw/scripts/run-smoke.sh +0 -61
- package/out/base-prompts/skills/pdf/LICENSE.txt +0 -30
- package/out/base-prompts/skills/pdf/SKILL.md +0 -294
- package/out/base-prompts/skills/pdf/forms.md +0 -205
- package/out/base-prompts/skills/pdf/reference.md +0 -612
- package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes.py +0 -70
- package/out/base-prompts/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
- package/out/base-prompts/skills/pdf/scripts/check_fillable_fields.py +0 -12
- package/out/base-prompts/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
- package/out/base-prompts/skills/pdf/scripts/create_validation_image.py +0 -41
- package/out/base-prompts/skills/pdf/scripts/extract_form_field_info.py +0 -152
- package/out/base-prompts/skills/pdf/scripts/fill_fillable_fields.py +0 -114
- package/out/base-prompts/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
- package/out/base-prompts/skills/pptx/LICENSE.txt +0 -30
- package/out/base-prompts/skills/pptx/SKILL.md +0 -484
- package/out/base-prompts/skills/pptx/html2pptx.md +0 -625
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/out/base-prompts/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/out/base-prompts/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/out/base-prompts/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/out/base-prompts/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/out/base-prompts/skills/pptx/ooxml/scripts/pack.py +0 -159
- package/out/base-prompts/skills/pptx/ooxml/scripts/unpack.py +0 -29
- package/out/base-prompts/skills/pptx/ooxml/scripts/validate.py +0 -69
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/base.py +0 -951
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
- package/out/base-prompts/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
- package/out/base-prompts/skills/pptx/ooxml.md +0 -427
- package/out/base-prompts/skills/pptx/scripts/html2pptx.js +0 -984
- package/out/base-prompts/skills/pptx/scripts/inventory.py +0 -1020
- package/out/base-prompts/skills/pptx/scripts/rearrange.py +0 -231
- package/out/base-prompts/skills/pptx/scripts/replace.py +0 -385
- package/out/base-prompts/skills/pptx/scripts/thumbnail.py +0 -450
- package/out/base-prompts/skills/prompt-lab/SKILL.md +0 -149
- package/out/base-prompts/skills/prompt-lab/scripts/query-analytics.sh +0 -2551
- package/out/base-prompts/skills/skill-creator/LICENSE.txt +0 -202
- package/out/base-prompts/skills/skill-creator/SKILL.md +0 -371
- package/out/base-prompts/skills/skill-creator/references/output-patterns.md +0 -82
- package/out/base-prompts/skills/skill-creator/references/workflows.md +0 -28
- package/out/base-prompts/skills/skill-creator/scripts/init_skill.py +0 -303
- package/out/base-prompts/skills/skill-creator/scripts/package_skill.py +0 -110
- package/out/base-prompts/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/out/base-prompts/skills/skill-installer/SKILL.md +0 -251
- package/out/base-prompts/skills/skill-installer/references/store-api.md +0 -219
- package/out/base-prompts/skills/spotlight-dashboard/SKILL.md +0 -83
- package/out/base-prompts/skills/spotlight-insights/SKILL.md +0 -101
- package/out/base-prompts/skills/spotlight-optimize/SKILL.md +0 -93
- package/out/base-prompts/skills/spotlight-optimize/scripts/query-analytics.sh +0 -2551
- package/out/base-prompts/skills/spotlight-query/SKILL.md +0 -314
- package/out/base-prompts/skills/spotlight-query/references/otel-schema.md +0 -163
- package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.sh +0 -2551
- package/out/base-prompts/skills/spotlight-query/scripts/query-analytics.test.sh +0 -744
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/sessions/sess-test-1.jsonl +0 -14
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/.duckdb-index.json +0 -7
- package/out/base-prompts/skills/spotlight-query/scripts/test-fixtures/analytics/traces/sample.jsonl +0 -5
- package/out/base-prompts/skills/spotlight-report/SKILL.md +0 -86
- package/out/base-prompts/skills/spotlight-visualize/SKILL.md +0 -92
- package/out/base-prompts/skills/spotlight-visualize/scripts/query-analytics.sh +0 -2551
- package/out/base-prompts/skills/xlsx/LICENSE.txt +0 -30
- package/out/base-prompts/skills/xlsx/SKILL.md +0 -289
- package/out/base-prompts/skills/xlsx/recalc.py +0 -178
- package/out/branding.js +0 -49
- package/out/cli/commands/anywhere.js +0 -66
- package/out/cli/commands/ask.js +0 -246
- package/out/cli/commands/auth-broker.js +0 -24
- package/out/cli/commands/auth.js +0 -219
- package/out/cli/commands/chat.js +0 -357
- package/out/cli/commands/conformance.js +0 -249
- package/out/cli/commands/data-plane.js +0 -67
- package/out/cli/commands/deploy.js +0 -263
- package/out/cli/commands/gateway.js +0 -218
- package/out/cli/commands/idp.js +0 -85
- package/out/cli/commands/pack.js +0 -399
- package/out/cli/commands/probe-custom-engine.js +0 -82
- package/out/cli/commands/sandbox.js +0 -332
- package/out/cli/commands/serve.js +0 -1758
- package/out/cli/commands/store.js +0 -927
- package/out/cli/credential-context.js +0 -91
- package/out/cli/data-plane/broker.js +0 -78
- package/out/cli/data-plane/connector-host.js +0 -121
- package/out/cli/data-plane/egress.js +0 -189
- package/out/cli/data-plane/gateway.js +0 -218
- package/out/cli/data-plane/index.js +0 -152
- package/out/cli/data-plane/registry.js +0 -89
- package/out/cli/data-plane/remote.js +0 -106
- package/out/cli/data-plane/sidecar.js +0 -161
- package/out/cli/deploy/blueprints/registry.js +0 -84
- package/out/cli/deploy/layers/identity.js +0 -172
- package/out/cli/deploy-init.js +0 -3023
- package/out/cli/deps.js +0 -342
- package/out/cli/idp-init.js +0 -338
- package/out/cli/pack-install-ref.js +0 -15
- package/out/cli/pack-loader.js +0 -418
- package/out/cli/pack-runtime.js +0 -61
- package/out/cli/runtime.js +0 -450
- package/out/cli/serve-hardening.js +0 -607
- package/out/cli/state-sync.js +0 -424
- package/out/cli/utils.js +0 -231
- package/out/engines/base.js +0 -188
- package/out/engines/claude.js +0 -1254
- package/out/engines/codex.js +0 -862
- package/out/engines/custom.js +0 -674
- package/out/engines/customEngineIpc.js +0 -95
- package/out/engines/customEngineRunnerEmbed.js +0 -107
- package/out/engines/customRegistry.js +0 -274
- package/out/engines/embeddedCustomEngineRunner.generated.js +0 -9
- package/out/engines/engineApiKey.js +0 -138
- package/out/engines/install.js +0 -372
- package/out/engines/persistentEngineWorker.js +0 -320
- package/out/engines/publish.js +0 -341
- package/out/evidence/sessionShip.js +0 -610
- package/out/gateway/bridge.js +0 -843
- package/out/gateway/cli-agent-id.js +0 -36
- package/out/gateway/client.js +0 -336
- package/out/gateway/client.test.js +0 -395
- package/out/gateway/gateway-scope-errors.js +0 -14
- package/out/gateway/gatewayBackup.js +0 -76
- package/out/gateway/installSource.js +0 -68
- package/out/gateway/lifecycle.js +0 -3190
- package/out/gateway/openclaw-channel-routing.js +0 -317
- package/out/gateway/outboundHandles.js +0 -373
- package/out/gateway/outboundPaths.js +0 -75
- package/out/gateway/outboundSend.js +0 -254
- package/out/gateway/protocol.js +0 -48
- package/out/gateway/secretsPreflight.js +0 -90
- package/out/gateway/sessionRouting.js +0 -77
- package/out/headless/index.js +0 -539
- package/out/headless/sync.js +0 -473
- package/out/live-e2e/mcp-demo/server.mjs +0 -32
- package/out/live-probe/connector.mjs +0 -8
- package/out/live-probe/env-report.mjs +0 -8
- package/out/mcp.js +0 -654
- package/out/pack/caps.js +0 -271
- package/out/pack/governor.js +0 -309
- package/out/pack/lease-schema.js +0 -270
- package/out/pack/lease.js +0 -640
- package/out/pack/reconcile.js +0 -217
- package/out/pack/signature.js +0 -839
- package/out/permissions.js +0 -108
- package/out/permissions.mapping.yaml +0 -68
- package/out/registry/index.js +0 -332
- package/out/runner/host.js +0 -131
- package/out/runner/protocol.js +0 -108
- package/out/runner/remoteEngine.js +0 -130
- package/out/runtime/interfaces/config-provider.js +0 -32
- package/out/runtime/interfaces/edit-tracker.js +0 -24
- package/out/runtime/interfaces/index.js +0 -29
- package/out/runtime/interfaces/logger.js +0 -40
- package/out/runtime/interfaces/permission-handler.js +0 -66
- package/out/runtime/interfaces/session-store.js +0 -342
- package/out/runtime/vscode/vscode-session-store.js +0 -22
- package/out/sandbox/containerDriver.js +0 -570
- package/out/sandbox/processDriver.js +0 -315
- package/out/sandbox/sandboxRunner.js +0 -191
- package/out/sandbox/support.js +0 -301
- package/out/sandbox/types.js +0 -55
- package/out/scripts/analytics/fleet-local-adapter.js +0 -246
- package/out/scripts/analytics/live-fleet-4-collector.cjs +0 -315
- package/out/scripts/analytics/live-fleet-4-daemon.mjs +0 -134
- package/out/scripts/analytics/live-fleet-4-widget.cjs +0 -433
- package/out/scripts/gateway/Dockerfile.serve +0 -45
- package/out/scripts/gateway/docker-serve.sh +0 -248
- package/out/scripts/gateway/setup-gateway-server.ps1 +0 -953
- package/out/scripts/gateway/setup-gateway-server.sh +0 -935
- package/out/session.js +0 -272
- package/out/shared/agentEngines.js +0 -170
- package/out/shared/index.js +0 -109
- package/out/shared/models.js +0 -136
- package/out/shared/providers.js +0 -205
- package/out/spotlight/install.js +0 -345
- package/out/spotlight/publish.js +0 -544
- package/out/spotlight/yaml.js +0 -31
- package/out/store/index.js +0 -786
- package/out/store/shared.js +0 -241
- package/out/test/agentEnvFile.test.js +0 -97
- package/out/test/agentYaml.test.js +0 -373
- package/out/test/agentpack.test.js +0 -639
- package/out/test/analytics-lifecycle.test.js +0 -174
- package/out/test/analytics.test.js +0 -756
- package/out/test/auth-baseurl.test.js +0 -132
- package/out/test/auth-bootstrapApply.test.js +0 -123
- package/out/test/auth-broker-hardening.test.js +0 -227
- package/out/test/auth-broker.test.js +0 -541
- package/out/test/auth-callback.test.js +0 -62
- package/out/test/blueprint-registry.test.js +0 -105
- package/out/test/branding.test.js +0 -242
- package/out/test/caps-governor.test.js +0 -455
- package/out/test/cli-agent-id.test.js +0 -55
- package/out/test/codex-new-file-survival.test.js +0 -119
- package/out/test/configuration-scopes.test.js +0 -131
- package/out/test/credential-context.test.js +0 -160
- package/out/test/custom-env-layering.test.js +0 -151
- package/out/test/customEngineInstall.test.js +0 -100
- package/out/test/customRegistry.test.js +0 -122
- package/out/test/data-plane-engine-wiring.test.js +0 -250
- package/out/test/data-plane.test.js +0 -311
- package/out/test/deploy-init.test.js +0 -854
- package/out/test/deps-auto-install.test.js +0 -81
- package/out/test/egress-broker.test.js +0 -172
- package/out/test/engine-integration.test.js +0 -297
- package/out/test/enginePaths.test.js +0 -195
- package/out/test/enginePublish.test.js +0 -82
- package/out/test/fleetDisplayUtils.test.js +0 -100
- package/out/test/gateway-client.test.js +0 -409
- package/out/test/gateway-install-source.test.js +0 -111
- package/out/test/gateway-lifecycle.test.js +0 -608
- package/out/test/gateway-outbound.test.js +0 -538
- package/out/test/gateway-reset-mappings.test.js +0 -221
- package/out/test/gateway-route-index.test.js +0 -235
- package/out/test/gateway-secrets-preflight.test.js +0 -127
- package/out/test/gateway-session-routing.test.js +0 -65
- package/out/test/gateway-session-store.test.js +0 -216
- package/out/test/github.test.js +0 -232
- package/out/test/governor-hardening.test.js +0 -217
- package/out/test/headless-sync.test.js +0 -301
- package/out/test/helpers/manifest-fixtures.js +0 -27
- package/out/test/idp-init.test.js +0 -151
- package/out/test/lease-signature.test.js +0 -357
- package/out/test/lease-trust-root.test.js +0 -273
- package/out/test/lease-validation.test.js +0 -169
- package/out/test/lease.test.js +0 -114
- package/out/test/mcp-obo.test.js +0 -107
- package/out/test/mcp.test.js +0 -389
- package/out/test/model-routing.test.js +0 -133
- package/out/test/openclaw-channel-routing.test.js +0 -191
- package/out/test/pack-admission.test.js +0 -216
- package/out/test/pack-digest-parity.test.js +0 -140
- package/out/test/pack-reconcile.test.js +0 -183
- package/out/test/pack-signature-artifact.test.js +0 -103
- package/out/test/pack-signature.test.js +0 -176
- package/out/test/pack-trust-root.test.js +0 -202
- package/out/test/pathSafety.test.js +0 -63
- package/out/test/permissions.test.js +0 -175
- package/out/test/persistent-engine-worker.test.js +0 -220
- package/out/test/refreshPolicy.test.js +0 -60
- package/out/test/registry.test.js +0 -351
- package/out/test/remote-trust.test.js +0 -242
- package/out/test/runner-protocol.test.js +0 -249
- package/out/test/runtime.test.js +0 -349
- package/out/test/sandbox-driver.test.js +0 -553
- package/out/test/sandbox-hardening.test.js +0 -395
- package/out/test/sandbox-runner.test.js +0 -343
- package/out/test/scheduledFleetStorage.test.js +0 -72
- package/out/test/serve-gateway-turn.test.js +0 -267
- package/out/test/serve-hardening.test.js +0 -418
- package/out/test/serveClient.test.js +0 -209
- package/out/test/sessionJsonlFleet.test.js +0 -78
- package/out/test/sessionShip.test.js +0 -560
- package/out/test/shared.test.js +0 -173
- package/out/test/skills-mcp.test.js +0 -299
- package/out/test/spotlightPublish.test.js +0 -327
- package/out/test/spotlightYaml.test.js +0 -58
- package/out/test/state-sync-peer.test.js +0 -156
- package/out/test/store-install-safe.test.js +0 -69
- package/out/test/store.test.js +0 -331
- package/out/test/stores.test.js +0 -504
- package/out/test/sync-switch.test.js +0 -251
- package/out/test/teamViewDiscovery.test.js +0 -90
- package/out/test/tls-bypass.test.js +0 -90
- package/out/test/toolPath.test.js +0 -120
- package/out/test/utils.test.js +0 -308
- package/out/test/viewsConfigMerge.test.js +0 -180
- package/out/test/warrant.test.js +0 -138
- package/out/test/windows-command-line.test.js +0 -75
- package/out/utils/agentEnvFile.js +0 -131
- package/out/utils/binary.js +0 -175
- package/out/utils/index.js +0 -37
- package/out/utils/network.js +0 -74
- package/out/utils/paths.js +0 -116
- package/out/utils/pid.js +0 -180
- package/out/utils/resolveNodeBinary.js +0 -168
- package/out/utils/windowsCommandLine.js +0 -29
- package/out/utils.js +0 -968
|
@@ -1,1505 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (c) AgentHippo.ai. All rights reserved.
|
|
3
|
-
* -----------------------------------------------------------------------------
|
|
4
|
-
* Spotlight Dashboard - Default Panel Module
|
|
5
|
-
* Handles artifact display, rendering, and interactions.
|
|
6
|
-
* Uses panelApi (provided by runtime-bridge.js) instead of raw VS Code API.
|
|
7
|
-
*
|
|
8
|
-
* This bundled file is the ONLY panel.js ever executed (see provider.getHtmlContent).
|
|
9
|
-
* It is not seeded to .agent-hippo/analytics/panel/ — a copy there would never run.
|
|
10
|
-
* Dashboard UI is customized via panel.html / panel.css, which ARE read from that directory.
|
|
11
|
-
* ----------------------------------------------------------------------------- */
|
|
12
|
-
|
|
13
|
-
// @ts-check
|
|
14
|
-
/// <reference lib="dom" />
|
|
15
|
-
|
|
16
|
-
// @ts-ignore - provided by runtime-bridge.js
|
|
17
|
-
const panelApi = window.panelApi;
|
|
18
|
-
|
|
19
|
-
// Seed/version marker for deciding whether a user's locally seeded panel.js
|
|
20
|
-
// is compatible with the extension runtime (e.g. message forwarding fixes).
|
|
21
|
-
const AGENTIDE_PANEL_JS_VERSION = '2026.07.21';
|
|
22
|
-
try { window.__AGENTIDE_PANEL_JS_VERSION__ = AGENTIDE_PANEL_JS_VERSION; } catch { /* no-op */ }
|
|
23
|
-
|
|
24
|
-
// -----------------------------------------------------------------------------
|
|
25
|
-
// State
|
|
26
|
-
// -----------------------------------------------------------------------------
|
|
27
|
-
|
|
28
|
-
const PANEL_ID = 'default';
|
|
29
|
-
|
|
30
|
-
/** Host ↔ panel / iframe ↔ panel: view-owned export JSON live updates. */
|
|
31
|
-
const VIEW_EXPORT_SNAPSHOT = 'viewExportSnapshot';
|
|
32
|
-
const REQUEST_VIEW_EXPORT_SNAPSHOT = 'requestViewExportSnapshot';
|
|
33
|
-
/** @deprecated Renamed; widgets may still emit this until updated. */
|
|
34
|
-
const LEGACY_REQUEST_LIVE_FLEET_SNAPSHOT = 'requestLiveFleetSnapshot';
|
|
35
|
-
const LEGACY_VIEW_EXPORT_SNAPSHOT = 'liveFleetSnapshot';
|
|
36
|
-
const ADD_VIEW_OPTION_VALUE = '__add_view__';
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @typedef {{ order: number, hidden: boolean, height?: number, expanded?: boolean }} PanelChartState
|
|
40
|
-
* @typedef {{ version: 1, charts: Record<string, PanelChartState>, summaryHidden?: boolean }} PanelState
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/** @returns {PanelState} */
|
|
44
|
-
function createDefaultPanelState() {
|
|
45
|
-
return { version: 1, charts: {}, summaryHidden: false };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** @type {{ artifacts: object[], galleryIgnorePatterns: string[], summaryCards: object[] | null, manifest: object | null, isRefreshing: boolean, scope: 'global'|'workspace', projectId: string, agentId: string, agentIds: string[], views: Array<{ id: string, name: string, scope: 'global'|'workspace', system: boolean, layout?: 'fleet-dashboard'|'gallery', refreshOnNavigate?: 'always'|'when-empty', preserveFleetIframe?: boolean }>, activeViewId: string, disabledCharts: Set<string>, panelState: PanelState, panelStateLoaded: boolean, lastArtifactCatalogSignature: string, fleetAutoRefreshIntervalSeconds: number, fleetRefreshVersion: number, needsGalleryRender: boolean, pendingForceFreshHtml: boolean, refreshingViewId: string | null }} */
|
|
49
|
-
const state = {
|
|
50
|
-
artifacts: [],
|
|
51
|
-
galleryIgnorePatterns: [],
|
|
52
|
-
summaryCards: null,
|
|
53
|
-
manifest: null,
|
|
54
|
-
isRefreshing: false,
|
|
55
|
-
scope: 'global',
|
|
56
|
-
projectId: '',
|
|
57
|
-
agentId: '',
|
|
58
|
-
agentIds: [],
|
|
59
|
-
views: [],
|
|
60
|
-
activeViewId: 'global',
|
|
61
|
-
disabledCharts: new Set(),
|
|
62
|
-
panelState: createDefaultPanelState(),
|
|
63
|
-
panelStateLoaded: false,
|
|
64
|
-
lastArtifactCatalogSignature: '',
|
|
65
|
-
fleetAutoRefreshIntervalSeconds: 30,
|
|
66
|
-
fleetRefreshVersion: 0,
|
|
67
|
-
surfaceMode: 'spotlight',
|
|
68
|
-
// While a refresh is in flight, multiple artifactsUpdated bursts can arrive as scripts/
|
|
69
|
-
// watchers write files incrementally. Rendering on each one tears down and rebuilds the
|
|
70
|
-
// whole gallery (see renderGallery), which is visibly flickery. Defer to one render when
|
|
71
|
-
// the refresh actually ends (refreshFinished/refreshFailed/refreshNoData).
|
|
72
|
-
needsGalleryRender: false,
|
|
73
|
-
pendingForceFreshHtml: false,
|
|
74
|
-
// View id the in-flight refresh belongs to. Termination messages carry the viewId captured
|
|
75
|
-
// at refresh start, so after a mid-refresh view switch they no longer match activeViewId —
|
|
76
|
-
// match against this instead so isRefreshing cannot get stuck true.
|
|
77
|
-
refreshingViewId: null,
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/** Render the gallery now if a render was deferred mid-refresh. */
|
|
81
|
-
function flushPendingGalleryRender() {
|
|
82
|
-
if (!state.needsGalleryRender) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
state.needsGalleryRender = false;
|
|
86
|
-
const forceFreshHtml = state.pendingForceFreshHtml;
|
|
87
|
-
state.pendingForceFreshHtml = false;
|
|
88
|
-
renderGallery(state.artifacts, { forceFreshHtml });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Single entry point for gallery renders triggered by host messages. While a refresh is in
|
|
93
|
-
* flight, defer to one render at refresh termination instead of tearing down and rebuilding
|
|
94
|
-
* the gallery on every artifactsUpdated/manifestUpdated/disabledChartsUpdated burst.
|
|
95
|
-
* @param {{ forceFreshHtml?: boolean }} [options]
|
|
96
|
-
*/
|
|
97
|
-
function requestGalleryRender(options) {
|
|
98
|
-
if (state.isRefreshing) {
|
|
99
|
-
state.needsGalleryRender = true;
|
|
100
|
-
if (options?.forceFreshHtml) {
|
|
101
|
-
state.pendingForceFreshHtml = true;
|
|
102
|
-
}
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
renderGallery(state.artifacts, { forceFreshHtml: Boolean(options?.forceFreshHtml) });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* The active view changed while a refresh may be in flight: that refresh belongs to the view
|
|
110
|
-
* being left, so stop tracking it. The abandoned refresh's termination message is dropped by
|
|
111
|
-
* the viewId gates, and without this reset a deferred render would block the new view's first
|
|
112
|
-
* paint until that refresh ends (or forever, if no matching termination arrives).
|
|
113
|
-
*/
|
|
114
|
-
function resetRefreshTrackingForViewChange() {
|
|
115
|
-
if (!state.isRefreshing && !state.needsGalleryRender && !state.pendingForceFreshHtml) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
state.isRefreshing = false;
|
|
119
|
-
state.refreshingViewId = null;
|
|
120
|
-
state.needsGalleryRender = false;
|
|
121
|
-
state.pendingForceFreshHtml = false;
|
|
122
|
-
setRefreshButtonState(false);
|
|
123
|
-
setPerChartRefreshing(false);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function applySurfaceMode(mode) {
|
|
127
|
-
const team = mode === 'team';
|
|
128
|
-
state.surfaceMode = team ? 'team' : 'spotlight';
|
|
129
|
-
document.body.classList.toggle('spotlight-surface-team', team);
|
|
130
|
-
applyTeamViewSelectVisibility();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Fleet view without preserveFleetIframe: host bumps fleetRefreshVersion and this panel reloads agent-fleet.html.
|
|
135
|
-
* preserveFleetIframe views receive viewExportSnapshot postMessages instead.
|
|
136
|
-
* Session/export JSON shape: extensions/agentide/src/analytics/dashboard/FLEET_DATA_CONTRACT.md
|
|
137
|
-
*/
|
|
138
|
-
/** Timer for Fleet view auto-refresh; cleared when view changes or interval is 0. */
|
|
139
|
-
let fleetAutoRefreshTimerId = null;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Only auto-refresh Fleet when the user is at the top of the widget.
|
|
143
|
-
* We check both the outer card scroll container and the embedded iframe
|
|
144
|
-
* document scroll position because either can own scrolling depending on
|
|
145
|
-
* current layout/height.
|
|
146
|
-
* @returns {boolean}
|
|
147
|
-
*/
|
|
148
|
-
function isFleetWidgetAtTop() {
|
|
149
|
-
const fleetCard = /** @type {HTMLElement | null} */ (document.querySelector('.fleet-dashboard-full.artifact-card'));
|
|
150
|
-
if (!fleetCard) {
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const contentEl = /** @type {HTMLElement | null} */ (fleetCard.querySelector('.artifact-content'));
|
|
155
|
-
if (contentEl && contentEl.scrollTop > 4) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const iframe = /** @type {HTMLIFrameElement | null} */ (fleetCard.querySelector('.html-preview iframe'));
|
|
160
|
-
if (!iframe) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const iframeDoc = iframe.contentDocument;
|
|
166
|
-
const bodyTop = iframeDoc?.body?.scrollTop ?? 0;
|
|
167
|
-
const docTop = iframeDoc?.documentElement?.scrollTop ?? 0;
|
|
168
|
-
const winTop = iframe.contentWindow?.scrollY ?? 0;
|
|
169
|
-
return bodyTop <= 4 && docTop <= 4 && winTop <= 4;
|
|
170
|
-
} catch {
|
|
171
|
-
// If iframe scroll is unavailable, avoid blocking auto-refresh.
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Start or stop Fleet auto-refresh based on current view and configured interval.
|
|
178
|
-
* Call after activeViewId or fleetAutoRefreshIntervalSeconds changes.
|
|
179
|
-
*/
|
|
180
|
-
/** @returns {{ id: string, name: string, scope: 'global'|'workspace', system: boolean, layout?: string, refreshOnNavigate?: string, preserveFleetIframe?: boolean } | undefined} */
|
|
181
|
-
function getActiveViewConfig() {
|
|
182
|
-
return state.views.find(view => view.id === state.activeViewId);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function activeViewUsesFleetDashboardLayout() {
|
|
186
|
-
return getActiveViewConfig()?.layout === 'fleet-dashboard';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function activeViewPreservesFleetIframe() {
|
|
190
|
-
return getActiveViewConfig()?.preserveFleetIframe === true;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Iframe-only snapshot views — no gallery Open/Delete footer.
|
|
195
|
-
* Config-driven via `preserveFleetIframe` (covers Workflows and any fleet-dashboard view).
|
|
196
|
-
* The id pattern is a back-compat fallback for legacy live-fleet views whose view.yaml
|
|
197
|
-
* predates the flag and derives `preserveFleetIframe === false` host-side.
|
|
198
|
-
*/
|
|
199
|
-
function activeViewIsLiveFleetSnapshot() {
|
|
200
|
-
if (activeViewPreservesFleetIframe()) {
|
|
201
|
-
return true;
|
|
202
|
-
}
|
|
203
|
-
return /^live-fleet-\d+$/.test(String(state.activeViewId || ''));
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function applyFleetAutoRefresh() {
|
|
207
|
-
if (fleetAutoRefreshTimerId !== null) {
|
|
208
|
-
clearInterval(fleetAutoRefreshTimerId);
|
|
209
|
-
fleetAutoRefreshTimerId = null;
|
|
210
|
-
}
|
|
211
|
-
const intervalSec = state.fleetAutoRefreshIntervalSeconds;
|
|
212
|
-
const isLiveFleetView = state.activeViewId === 'fleet' || activeViewPreservesFleetIframe();
|
|
213
|
-
if (isLiveFleetView && typeof intervalSec === 'number' && intervalSec > 0) {
|
|
214
|
-
const ms = intervalSec * 1000;
|
|
215
|
-
fleetAutoRefreshTimerId = setInterval(() => {
|
|
216
|
-
if (!isFleetWidgetAtTop()) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (activeViewPreservesFleetIframe()) {
|
|
220
|
-
panelApi.postMessage({ type: REQUEST_VIEW_EXPORT_SNAPSHOT });
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
panelApi.postMessage({ type: 'refreshView' });
|
|
224
|
-
}, ms);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function applyTeamViewSelectVisibility() {
|
|
229
|
-
const viewSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('view-select'));
|
|
230
|
-
if (!viewSelect) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (state.surfaceMode === 'team') {
|
|
234
|
-
if (state.views.length > 1) {
|
|
235
|
-
viewSelect.style.setProperty('display', 'inline-block', 'important');
|
|
236
|
-
} else {
|
|
237
|
-
viewSelect.style.setProperty('display', 'none', 'important');
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
viewSelect.style.removeProperty('display');
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function applyViewOptions() {
|
|
245
|
-
const viewSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('view-select'));
|
|
246
|
-
if (!viewSelect) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
const previous = state.activeViewId || viewSelect.value || '';
|
|
250
|
-
viewSelect.innerHTML = '';
|
|
251
|
-
|
|
252
|
-
if (state.surfaceMode !== 'team') {
|
|
253
|
-
const addViewOption = document.createElement('option');
|
|
254
|
-
addViewOption.value = ADD_VIEW_OPTION_VALUE;
|
|
255
|
-
addViewOption.textContent = '+ Add view…';
|
|
256
|
-
viewSelect.appendChild(addViewOption);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
for (const view of state.views) {
|
|
260
|
-
const option = document.createElement('option');
|
|
261
|
-
option.value = view.id;
|
|
262
|
-
option.textContent = view.name;
|
|
263
|
-
viewSelect.appendChild(option);
|
|
264
|
-
}
|
|
265
|
-
const next = state.views.some((view) => view.id === state.activeViewId)
|
|
266
|
-
? state.activeViewId
|
|
267
|
-
: previous;
|
|
268
|
-
if (next && state.views.some((view) => view.id === next)) {
|
|
269
|
-
viewSelect.value = next;
|
|
270
|
-
state.activeViewId = next;
|
|
271
|
-
}
|
|
272
|
-
applyTeamViewSelectVisibility();
|
|
273
|
-
applyShareButtonState();
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const SHARE_ICON_HTML = '<span class="btn-icon" aria-hidden="true">↑</span>';
|
|
277
|
-
const INSTALL_ICON_HTML = '<span class="btn-icon" aria-hidden="true">↓</span>';
|
|
278
|
-
|
|
279
|
-
function onInstallViewClick() {
|
|
280
|
-
panelApi.postMessage({ type: 'installView' });
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function onShareViewClick() {
|
|
284
|
-
const activeView = getActiveView();
|
|
285
|
-
// Always forward to the extension host so built-in views get the explanatory toast.
|
|
286
|
-
panelApi.postMessage({
|
|
287
|
-
type: 'shareView',
|
|
288
|
-
viewId: activeView?.id ?? '',
|
|
289
|
-
bundle: 'full',
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function onShareScriptsOnlyClick() {
|
|
294
|
-
const activeView = getActiveView();
|
|
295
|
-
panelApi.postMessage({
|
|
296
|
-
type: 'shareView',
|
|
297
|
-
viewId: activeView?.id ?? '',
|
|
298
|
-
bundle: 'scripts-only',
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Insert share toolbar control when user's panel.html predates the share button.
|
|
304
|
-
*/
|
|
305
|
-
function ensureShareToolbarButton() {
|
|
306
|
-
let shareBtn = document.getElementById('share-view-btn');
|
|
307
|
-
if (!shareBtn) {
|
|
308
|
-
const refreshBtn = document.getElementById('refresh-charts-btn');
|
|
309
|
-
if (!refreshBtn?.parentElement) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
let iconGroup = refreshBtn.closest('.toolbar-icon-group');
|
|
313
|
-
if (!iconGroup) {
|
|
314
|
-
iconGroup = document.createElement('div');
|
|
315
|
-
iconGroup.className = 'toolbar-icon-group';
|
|
316
|
-
refreshBtn.parentElement.insertBefore(iconGroup, refreshBtn);
|
|
317
|
-
iconGroup.appendChild(refreshBtn);
|
|
318
|
-
}
|
|
319
|
-
shareBtn = document.createElement('button');
|
|
320
|
-
shareBtn.id = 'share-view-btn';
|
|
321
|
-
shareBtn.className = 'toolbar-btn icon-only';
|
|
322
|
-
shareBtn.title = 'Publish current view to store (full bundle)';
|
|
323
|
-
shareBtn.setAttribute('aria-label', shareBtn.title);
|
|
324
|
-
shareBtn.innerHTML = SHARE_ICON_HTML;
|
|
325
|
-
iconGroup.appendChild(shareBtn);
|
|
326
|
-
} else {
|
|
327
|
-
const refreshBtn = document.getElementById('refresh-charts-btn');
|
|
328
|
-
const icon = shareBtn.querySelector('.btn-icon');
|
|
329
|
-
if (icon && icon.textContent !== '↑') {
|
|
330
|
-
icon.outerHTML = SHARE_ICON_HTML;
|
|
331
|
-
}
|
|
332
|
-
if (refreshBtn && shareBtn.compareDocumentPosition(refreshBtn) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
333
|
-
refreshBtn.insertAdjacentElement('afterend', shareBtn);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
const boundShareBtn = document.getElementById('share-view-btn');
|
|
337
|
-
if (boundShareBtn && !boundShareBtn.dataset.boundShareClick) {
|
|
338
|
-
boundShareBtn.dataset.boundShareClick = '1';
|
|
339
|
-
boundShareBtn.addEventListener('click', onShareViewClick);
|
|
340
|
-
}
|
|
341
|
-
applyShareButtonState();
|
|
342
|
-
ensureInstallToolbarButton();
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Insert install toolbar control when user's panel.html predates the install button.
|
|
347
|
-
*/
|
|
348
|
-
function ensureInstallToolbarButton() {
|
|
349
|
-
let installBtn = document.getElementById('install-view-btn');
|
|
350
|
-
if (!installBtn) {
|
|
351
|
-
const shareBtn = document.getElementById('share-view-btn');
|
|
352
|
-
if (!shareBtn?.parentElement) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
let iconGroup = shareBtn.closest('.toolbar-icon-group');
|
|
356
|
-
if (!iconGroup) {
|
|
357
|
-
iconGroup = document.createElement('div');
|
|
358
|
-
iconGroup.className = 'toolbar-icon-group';
|
|
359
|
-
shareBtn.parentElement.insertBefore(iconGroup, shareBtn);
|
|
360
|
-
iconGroup.appendChild(shareBtn);
|
|
361
|
-
}
|
|
362
|
-
installBtn = document.createElement('button');
|
|
363
|
-
installBtn.id = 'install-view-btn';
|
|
364
|
-
installBtn.className = 'toolbar-btn icon-only';
|
|
365
|
-
installBtn.title = 'Install Spotlight view from store';
|
|
366
|
-
installBtn.setAttribute('aria-label', installBtn.title);
|
|
367
|
-
installBtn.innerHTML = INSTALL_ICON_HTML;
|
|
368
|
-
shareBtn.insertAdjacentElement('afterend', installBtn);
|
|
369
|
-
} else {
|
|
370
|
-
const shareBtn = document.getElementById('share-view-btn');
|
|
371
|
-
const icon = installBtn.querySelector('.btn-icon');
|
|
372
|
-
if (icon && icon.textContent !== '↓') {
|
|
373
|
-
icon.outerHTML = INSTALL_ICON_HTML;
|
|
374
|
-
}
|
|
375
|
-
if (shareBtn && installBtn.compareDocumentPosition(shareBtn) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
376
|
-
shareBtn.insertAdjacentElement('afterend', installBtn);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const boundInstallBtn = document.getElementById('install-view-btn');
|
|
380
|
-
if (boundInstallBtn && !boundInstallBtn.dataset.boundInstallClick) {
|
|
381
|
-
boundInstallBtn.dataset.boundInstallClick = '1';
|
|
382
|
-
boundInstallBtn.addEventListener('click', onInstallViewClick);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
function applyShareButtonState() {
|
|
387
|
-
const shareBtn = document.getElementById('share-view-btn');
|
|
388
|
-
if (!shareBtn) {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
const activeView = getActiveView();
|
|
392
|
-
const canShare = Boolean(activeView && !activeView.system);
|
|
393
|
-
shareBtn.classList.toggle('share-unavailable', !canShare);
|
|
394
|
-
shareBtn.title = canShare
|
|
395
|
-
? 'Publish current view to store (full bundle)'
|
|
396
|
-
: 'Built-in views cannot be shared (duplicate or create a custom view)';
|
|
397
|
-
shareBtn.setAttribute('aria-label', shareBtn.title);
|
|
398
|
-
|
|
399
|
-
const scriptsOnlyItem = document.getElementById('share-scripts-only-menu-item');
|
|
400
|
-
if (scriptsOnlyItem) {
|
|
401
|
-
// Keep clickable so the host can show the same built-in-view explanation.
|
|
402
|
-
scriptsOnlyItem.disabled = false;
|
|
403
|
-
scriptsOnlyItem.classList.toggle('share-unavailable', !canShare);
|
|
404
|
-
scriptsOnlyItem.title = canShare
|
|
405
|
-
? 'Publish widget scripts only (no charts or exports)'
|
|
406
|
-
: 'Built-in views cannot be shared (duplicate or create a custom view)';
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
function getActiveView() {
|
|
411
|
-
return state.views.find((view) => view.id === state.activeViewId);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* @param {string} nextViewId
|
|
416
|
-
*/
|
|
417
|
-
function switchToView(nextViewId) {
|
|
418
|
-
if (!nextViewId || nextViewId === state.activeViewId) {
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
state.activeViewId = nextViewId;
|
|
422
|
-
resetRefreshTrackingForViewChange();
|
|
423
|
-
state.panelStateLoaded = false;
|
|
424
|
-
state.panelState = createDefaultPanelState();
|
|
425
|
-
const viewSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('view-select'));
|
|
426
|
-
if (viewSelect && state.views.some((view) => view.id === nextViewId)) {
|
|
427
|
-
viewSelect.value = nextViewId;
|
|
428
|
-
}
|
|
429
|
-
applyFleetAutoRefresh();
|
|
430
|
-
applyShareButtonState();
|
|
431
|
-
panelApi.postMessage({ type: 'setActiveView', viewId: nextViewId });
|
|
432
|
-
panelApi.postMessage({ type: 'requestPanelState', panelId: PANEL_ID });
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* Show the "New view name" modal. Used instead of prompt() because
|
|
437
|
-
* window.prompt() is not available in VS Code webviews.
|
|
438
|
-
* @param {() => void} [onResetSelect] - Optional callback to reset view dropdown (e.g. when opened from "+ Add view…").
|
|
439
|
-
*/
|
|
440
|
-
function showNewViewModal(onResetSelect) {
|
|
441
|
-
const overlay = document.getElementById('new-view-modal');
|
|
442
|
-
const input = document.getElementById('new-view-name-input');
|
|
443
|
-
const okBtn = document.getElementById('new-view-modal-ok');
|
|
444
|
-
const cancelBtn = document.getElementById('new-view-modal-cancel');
|
|
445
|
-
if (!overlay || !input || !okBtn || !cancelBtn) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
if (typeof onResetSelect === 'function') {
|
|
449
|
-
onResetSelect();
|
|
450
|
-
}
|
|
451
|
-
input.value = '';
|
|
452
|
-
overlay.style.display = 'flex';
|
|
453
|
-
overlay.setAttribute('aria-hidden', 'false');
|
|
454
|
-
input.focus();
|
|
455
|
-
|
|
456
|
-
function hide() {
|
|
457
|
-
overlay.style.display = 'none';
|
|
458
|
-
overlay.setAttribute('aria-hidden', 'true');
|
|
459
|
-
overlay.removeEventListener('click', handleOverlayClick);
|
|
460
|
-
document.removeEventListener('keydown', handleKeydown);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function submit() {
|
|
464
|
-
const trimmed = input.value.trim();
|
|
465
|
-
hide();
|
|
466
|
-
if (trimmed) {
|
|
467
|
-
panelApi.postMessage({ type: 'createView', name: trimmed });
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function handleOverlayClick(e) {
|
|
472
|
-
if (e.target === overlay) {
|
|
473
|
-
hide();
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function handleKeydown(e) {
|
|
478
|
-
if (e.key === 'Escape') {
|
|
479
|
-
hide();
|
|
480
|
-
e.preventDefault();
|
|
481
|
-
} else if (e.key === 'Enter') {
|
|
482
|
-
submit();
|
|
483
|
-
e.preventDefault();
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
overlay.addEventListener('click', handleOverlayClick);
|
|
488
|
-
document.addEventListener('keydown', handleKeydown);
|
|
489
|
-
|
|
490
|
-
okBtn.onclick = () => submit();
|
|
491
|
-
cancelBtn.onclick = () => hide();
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
function promptCreateView() {
|
|
495
|
-
showNewViewModal();
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function initViews() {
|
|
499
|
-
const viewSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('view-select'));
|
|
500
|
-
viewSelect?.addEventListener('change', () => {
|
|
501
|
-
const nextViewId = viewSelect.value || '';
|
|
502
|
-
if (!nextViewId) {
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
if (nextViewId === ADD_VIEW_OPTION_VALUE) {
|
|
506
|
-
showNewViewModal(() => {
|
|
507
|
-
viewSelect.value = state.activeViewId || '';
|
|
508
|
-
});
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
if (nextViewId === state.activeViewId) {
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
switchToView(nextViewId);
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
function refreshCurrentView() {
|
|
519
|
-
const btn = document.getElementById('refresh-charts-btn');
|
|
520
|
-
if (btn && !btn.classList.contains('refreshing')) {
|
|
521
|
-
setRefreshButtonState(true);
|
|
522
|
-
panelApi.postMessage({ type: 'refreshView' });
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// -----------------------------------------------------------------------------
|
|
527
|
-
// Utility Functions
|
|
528
|
-
// -----------------------------------------------------------------------------
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Format a date as relative time (e.g., "2 min ago")
|
|
532
|
-
* @param {Date} date
|
|
533
|
-
* @returns {string}
|
|
534
|
-
*/
|
|
535
|
-
function formatTimeAgo(date) {
|
|
536
|
-
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
|
|
537
|
-
if (seconds < 60) {
|
|
538
|
-
return 'just now';
|
|
539
|
-
}
|
|
540
|
-
if (seconds < 3600) {
|
|
541
|
-
return `${Math.floor(seconds / 60)} min ago`;
|
|
542
|
-
}
|
|
543
|
-
if (seconds < 86400) {
|
|
544
|
-
return `${Math.floor(seconds / 3600)}h ago`;
|
|
545
|
-
}
|
|
546
|
-
return `${Math.floor(seconds / 86400)}d ago`;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Format file size in human-readable form
|
|
551
|
-
* @param {number} bytes
|
|
552
|
-
* @returns {string}
|
|
553
|
-
*/
|
|
554
|
-
function formatSize(bytes) {
|
|
555
|
-
if (bytes < 1024) {
|
|
556
|
-
return `${bytes} B`;
|
|
557
|
-
}
|
|
558
|
-
if (bytes < 1024 * 1024) {
|
|
559
|
-
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
560
|
-
}
|
|
561
|
-
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Escape HTML special characters
|
|
566
|
-
* @param {string} text
|
|
567
|
-
* @returns {string}
|
|
568
|
-
*/
|
|
569
|
-
function escapeHtml(text) {
|
|
570
|
-
const div = document.createElement('div');
|
|
571
|
-
div.textContent = text;
|
|
572
|
-
return div.innerHTML;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Simple markdown rendering
|
|
577
|
-
* @param {string} text
|
|
578
|
-
* @returns {string}
|
|
579
|
-
*/
|
|
580
|
-
function renderMarkdown(text) {
|
|
581
|
-
return text
|
|
582
|
-
.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code class="language-$1">$2</code></pre>')
|
|
583
|
-
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
|
584
|
-
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
585
|
-
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
586
|
-
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
|
587
|
-
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
|
588
|
-
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
|
589
|
-
.replace(/\n/g, '<br>');
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
/**
|
|
593
|
-
* @param {string} value
|
|
594
|
-
* @returns {string}
|
|
595
|
-
*/
|
|
596
|
-
function normalizeFilename(value) {
|
|
597
|
-
return String(value || '').trim().toLowerCase();
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* @param {unknown} raw
|
|
602
|
-
* @returns {PanelState}
|
|
603
|
-
*/
|
|
604
|
-
function normalizePanelState(raw) {
|
|
605
|
-
const parsed = raw && typeof raw === 'object' ? /** @type {Record<string, unknown>} */ (raw) : {};
|
|
606
|
-
const rawCharts = parsed.charts && typeof parsed.charts === 'object'
|
|
607
|
-
? /** @type {Record<string, unknown>} */ (parsed.charts)
|
|
608
|
-
: {};
|
|
609
|
-
/** @type {Record<string, PanelChartState>} */
|
|
610
|
-
const charts = {};
|
|
611
|
-
let nextOrder = 1;
|
|
612
|
-
for (const [key, value] of Object.entries(rawCharts)) {
|
|
613
|
-
const filenameKey = normalizeFilename(key);
|
|
614
|
-
if (!filenameKey) {
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
|
-
const entry = value && typeof value === 'object' ? /** @type {Record<string, unknown>} */ (value) : {};
|
|
618
|
-
const parsedOrder = Number(entry.order);
|
|
619
|
-
const order = Number.isFinite(parsedOrder) && parsedOrder > 0 ? parsedOrder : nextOrder;
|
|
620
|
-
const hidden = entry.hidden === true;
|
|
621
|
-
const height = Number(entry.height);
|
|
622
|
-
const expanded = entry.expanded === true;
|
|
623
|
-
charts[filenameKey] = {
|
|
624
|
-
order,
|
|
625
|
-
hidden,
|
|
626
|
-
height: Number.isFinite(height) && height >= 120 ? height : undefined,
|
|
627
|
-
expanded,
|
|
628
|
-
};
|
|
629
|
-
nextOrder = Math.max(nextOrder, order + 1);
|
|
630
|
-
}
|
|
631
|
-
const summaryHidden = parsed.summaryHidden === true;
|
|
632
|
-
return { version: 1, charts, summaryHidden };
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* @returns {number}
|
|
637
|
-
*/
|
|
638
|
-
function getNextChartOrder() {
|
|
639
|
-
const entries = Object.values(state.panelState.charts);
|
|
640
|
-
if (entries.length === 0) {
|
|
641
|
-
return 1;
|
|
642
|
-
}
|
|
643
|
-
return entries.reduce((max, item) => Math.max(max, item.order), 0) + 1;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Ensure every discovered chart has a panel-state entry.
|
|
648
|
-
* @param {Array<object>} artifacts
|
|
649
|
-
* @returns {boolean}
|
|
650
|
-
*/
|
|
651
|
-
function ensurePanelStateForArtifacts(artifacts) {
|
|
652
|
-
let changed = false;
|
|
653
|
-
let nextOrder = getNextChartOrder();
|
|
654
|
-
for (const artifact of artifacts) {
|
|
655
|
-
if (artifact.type !== 'chart' && artifact.type !== 'image') {
|
|
656
|
-
continue;
|
|
657
|
-
}
|
|
658
|
-
const key = normalizeFilename(String(artifact.filename || ''));
|
|
659
|
-
if (!key) {
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
if (!state.panelState.charts[key]) {
|
|
663
|
-
state.panelState.charts[key] = { order: nextOrder++, hidden: false, height: undefined, expanded: false };
|
|
664
|
-
changed = true;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return changed;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* @param {string} filename
|
|
672
|
-
* @returns {PanelChartState}
|
|
673
|
-
*/
|
|
674
|
-
function getChartPanelState(filename) {
|
|
675
|
-
const key = normalizeFilename(filename);
|
|
676
|
-
if (!state.panelState.charts[key]) {
|
|
677
|
-
state.panelState.charts[key] = { order: getNextChartOrder(), hidden: false, height: undefined, expanded: false };
|
|
678
|
-
}
|
|
679
|
-
return state.panelState.charts[key];
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function setChartHeight(filename, heightPx) {
|
|
683
|
-
const chartState = getChartPanelState(filename);
|
|
684
|
-
chartState.height = heightPx >= 120 && heightPx <= 2000 ? heightPx : undefined;
|
|
685
|
-
savePanelState();
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
function setChartExpanded(filename, expanded) {
|
|
689
|
-
const chartState = getChartPanelState(filename);
|
|
690
|
-
chartState.expanded = expanded === true;
|
|
691
|
-
savePanelState();
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Auto-fit Fleet iframe content on first load when no explicit panel height
|
|
696
|
-
* has been saved yet. This prevents an oversized empty area at the bottom
|
|
697
|
-
* while preserving click-to-expand behavior.
|
|
698
|
-
* @param {HTMLElement} card
|
|
699
|
-
*/
|
|
700
|
-
function autoFitFleetCardHeight(card) {
|
|
701
|
-
const filename = card?.dataset?.filename || '';
|
|
702
|
-
if (!filename) {
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
const chartState = getChartPanelState(filename);
|
|
706
|
-
if (typeof chartState.height === 'number' && Number.isFinite(chartState.height)) {
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
const content = /** @type {HTMLElement | null} */ (card.querySelector('.artifact-content'));
|
|
710
|
-
const iframe = /** @type {HTMLIFrameElement | null} */ (card.querySelector('.html-preview iframe'));
|
|
711
|
-
if (!content || !iframe) {
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
let docHeight = 0;
|
|
715
|
-
try {
|
|
716
|
-
const doc = iframe.contentDocument;
|
|
717
|
-
const body = doc?.body;
|
|
718
|
-
const html = doc?.documentElement;
|
|
719
|
-
docHeight = Math.max(
|
|
720
|
-
body?.scrollHeight || 0,
|
|
721
|
-
body?.offsetHeight || 0,
|
|
722
|
-
html?.scrollHeight || 0,
|
|
723
|
-
html?.offsetHeight || 0,
|
|
724
|
-
html?.clientHeight || 0,
|
|
725
|
-
);
|
|
726
|
-
} catch {
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
if (!Number.isFinite(docHeight) || docHeight <= 0) {
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
const computed = window.getComputedStyle(content);
|
|
733
|
-
const paddingTop = Number.parseFloat(computed.paddingTop || '0') || 0;
|
|
734
|
-
const paddingBottom = Number.parseFloat(computed.paddingBottom || '0') || 0;
|
|
735
|
-
const targetHeight = Math.round(Math.max(320, Math.min(2000, docHeight + paddingTop + paddingBottom)));
|
|
736
|
-
content.style.height = `${targetHeight}px`;
|
|
737
|
-
content.style.minHeight = `${targetHeight}px`;
|
|
738
|
-
content.style.overflow = 'hidden';
|
|
739
|
-
syncEmbeddedPreviewSize(content);
|
|
740
|
-
setChartHeight(filename, targetHeight);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* Keep embedded HTML previews sized to the resized card and trigger a resize
|
|
745
|
-
* event inside iframe widgets so responsive layouts can relayout.
|
|
746
|
-
* @param {HTMLElement} content
|
|
747
|
-
*/
|
|
748
|
-
function syncEmbeddedPreviewSize(content) {
|
|
749
|
-
const preview = content.querySelector('.html-preview');
|
|
750
|
-
if (preview instanceof HTMLElement) {
|
|
751
|
-
preview.style.height = '100%';
|
|
752
|
-
preview.style.minHeight = '0';
|
|
753
|
-
}
|
|
754
|
-
const iframe = content.querySelector('.html-preview iframe');
|
|
755
|
-
if (iframe instanceof HTMLIFrameElement) {
|
|
756
|
-
iframe.style.height = '100%';
|
|
757
|
-
iframe.style.minHeight = '0';
|
|
758
|
-
iframe.style.display = 'block';
|
|
759
|
-
try {
|
|
760
|
-
iframe.contentWindow?.dispatchEvent(new Event('resize'));
|
|
761
|
-
} catch {
|
|
762
|
-
// Cross-origin frame or transient load state; ignore.
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/** @param {Element | null} card @param {string} filename */
|
|
768
|
-
function attachResizeHandle(card, filename) {
|
|
769
|
-
if (!card || !filename) return;
|
|
770
|
-
const resizeHandle = card.querySelector('.resize-handle');
|
|
771
|
-
const contentEl = card.querySelector('.artifact-content');
|
|
772
|
-
if (!resizeHandle || !contentEl) return;
|
|
773
|
-
const cardEl = /** @type {HTMLElement} */ (card);
|
|
774
|
-
const content = /** @type {HTMLElement} */ (contentEl);
|
|
775
|
-
const minH = 120;
|
|
776
|
-
const maxH = 2000;
|
|
777
|
-
resizeHandle.addEventListener('mousedown', (e) => {
|
|
778
|
-
e.preventDefault();
|
|
779
|
-
e.stopPropagation();
|
|
780
|
-
const startY = e.clientY;
|
|
781
|
-
const rect = content.getBoundingClientRect();
|
|
782
|
-
const startHeight = rect.height;
|
|
783
|
-
let didResize = false;
|
|
784
|
-
let rafId = 0;
|
|
785
|
-
const schedulePreviewResize = () => {
|
|
786
|
-
if (rafId) {
|
|
787
|
-
cancelAnimationFrame(rafId);
|
|
788
|
-
}
|
|
789
|
-
rafId = requestAnimationFrame(() => {
|
|
790
|
-
rafId = 0;
|
|
791
|
-
syncEmbeddedPreviewSize(content);
|
|
792
|
-
});
|
|
793
|
-
};
|
|
794
|
-
const onMove = (moveEvent) => {
|
|
795
|
-
const dy = moveEvent.clientY - startY;
|
|
796
|
-
if (Math.abs(dy) > 2) {
|
|
797
|
-
didResize = true;
|
|
798
|
-
}
|
|
799
|
-
let h = Math.round(startHeight + dy);
|
|
800
|
-
h = Math.max(minH, Math.min(maxH, h));
|
|
801
|
-
content.style.height = `${h}px`;
|
|
802
|
-
content.style.minHeight = `${h}px`;
|
|
803
|
-
content.style.overflow = 'hidden';
|
|
804
|
-
schedulePreviewResize();
|
|
805
|
-
};
|
|
806
|
-
const onUp = () => {
|
|
807
|
-
document.removeEventListener('mousemove', onMove);
|
|
808
|
-
document.removeEventListener('mouseup', onUp);
|
|
809
|
-
if (rafId) {
|
|
810
|
-
cancelAnimationFrame(rafId);
|
|
811
|
-
rafId = 0;
|
|
812
|
-
}
|
|
813
|
-
syncEmbeddedPreviewSize(content);
|
|
814
|
-
if (didResize) {
|
|
815
|
-
const finalHeight = content.getBoundingClientRect().height;
|
|
816
|
-
setChartHeight(filename, Math.round(finalHeight));
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
const nextExpanded = !cardEl.classList.contains('expanded');
|
|
820
|
-
cardEl.classList.toggle('expanded', nextExpanded);
|
|
821
|
-
setChartExpanded(filename, nextExpanded);
|
|
822
|
-
};
|
|
823
|
-
document.addEventListener('mousemove', onMove);
|
|
824
|
-
document.addEventListener('mouseup', onUp);
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
function toggleSummarySection() {
|
|
829
|
-
state.panelState.summaryHidden = !state.panelState.summaryHidden;
|
|
830
|
-
applySummarySectionVisibility();
|
|
831
|
-
savePanelState();
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
function applySummarySectionVisibility() {
|
|
835
|
-
const section = document.getElementById('summary-section');
|
|
836
|
-
const btn = document.getElementById('summary-toggle-btn');
|
|
837
|
-
if (section) {
|
|
838
|
-
section.classList.toggle('collapsed', state.panelState.summaryHidden === true);
|
|
839
|
-
}
|
|
840
|
-
if (btn) {
|
|
841
|
-
btn.textContent = state.panelState.summaryHidden ? 'Show' : 'Hide';
|
|
842
|
-
btn.title = state.panelState.summaryHidden ? 'Show summary section' : 'Hide summary section';
|
|
843
|
-
btn.setAttribute('aria-label', state.panelState.summaryHidden ? 'Show summary' : 'Hide summary');
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
function savePanelState() {
|
|
848
|
-
panelApi.postMessage({
|
|
849
|
-
type: 'savePanelState',
|
|
850
|
-
panelId: PANEL_ID,
|
|
851
|
-
state: state.panelState,
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* @param {string} filename
|
|
857
|
-
* @param {'up' | 'down'} direction
|
|
858
|
-
* @param {string[]} activeChartKeys
|
|
859
|
-
*/
|
|
860
|
-
function moveChartInPanelState(filename, direction, activeChartKeys) {
|
|
861
|
-
const targetKey = normalizeFilename(filename);
|
|
862
|
-
if (!targetKey) {
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
getChartPanelState(filename);
|
|
866
|
-
const orderedKeys = Object.entries(state.panelState.charts)
|
|
867
|
-
.sort((a, b) => a[1].order - b[1].order || a[0].localeCompare(b[0]))
|
|
868
|
-
.map(([key]) => key);
|
|
869
|
-
const index = orderedKeys.indexOf(targetKey);
|
|
870
|
-
if (index < 0) {
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
const normalizedActiveKeys = new Set(
|
|
874
|
-
(activeChartKeys || []).map(key => normalizeFilename(key)).filter(Boolean),
|
|
875
|
-
);
|
|
876
|
-
normalizedActiveKeys.add(targetKey);
|
|
877
|
-
const step = direction === 'up' ? -1 : 1;
|
|
878
|
-
let swapIndex = index + step;
|
|
879
|
-
while (swapIndex >= 0 && swapIndex < orderedKeys.length) {
|
|
880
|
-
if (normalizedActiveKeys.has(orderedKeys[swapIndex])) {
|
|
881
|
-
break;
|
|
882
|
-
}
|
|
883
|
-
swapIndex += step;
|
|
884
|
-
}
|
|
885
|
-
if (swapIndex < 0 || swapIndex >= orderedKeys.length || swapIndex === index) {
|
|
886
|
-
return;
|
|
887
|
-
}
|
|
888
|
-
const [entry] = orderedKeys.splice(index, 1);
|
|
889
|
-
orderedKeys.splice(swapIndex, 0, entry);
|
|
890
|
-
orderedKeys.forEach((key, orderIndex) => {
|
|
891
|
-
const chart = state.panelState.charts[key];
|
|
892
|
-
chart.order = orderIndex + 1;
|
|
893
|
-
});
|
|
894
|
-
savePanelState();
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/**
|
|
898
|
-
* @param {string} filename
|
|
899
|
-
*/
|
|
900
|
-
function toggleChartHiddenInPanelState(filename) {
|
|
901
|
-
const chartState = getChartPanelState(filename);
|
|
902
|
-
chartState.hidden = !chartState.hidden;
|
|
903
|
-
savePanelState();
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// -----------------------------------------------------------------------------
|
|
907
|
-
// Summary Cards
|
|
908
|
-
// -----------------------------------------------------------------------------
|
|
909
|
-
|
|
910
|
-
/** Last rendered summary-cards payload, to skip no-op rebuilds of the summary strip. */
|
|
911
|
-
let lastSummaryCardsSignature = '';
|
|
912
|
-
|
|
913
|
-
/**
|
|
914
|
-
* Render summary cards in the header
|
|
915
|
-
* @param {Array<{label: string, value: string, icon: string}>} cards
|
|
916
|
-
*/
|
|
917
|
-
function renderSummaryCards(cards) {
|
|
918
|
-
const container = document.getElementById('summary-cards');
|
|
919
|
-
if (!container) {
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
if (!cards || cards.length === 0) {
|
|
923
|
-
lastSummaryCardsSignature = '';
|
|
924
|
-
renderSummaryPlaceholders();
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// The host posts summaryCards more than once per refresh; skip the rebuild (and its
|
|
929
|
-
// visible flash) when the payload is identical to what is already rendered.
|
|
930
|
-
const signature = JSON.stringify(cards);
|
|
931
|
-
if (signature === lastSummaryCardsSignature && !container.classList.contains('loading')) {
|
|
932
|
-
return;
|
|
933
|
-
}
|
|
934
|
-
lastSummaryCardsSignature = signature;
|
|
935
|
-
|
|
936
|
-
container.style.display = 'grid';
|
|
937
|
-
container.classList.remove('loading');
|
|
938
|
-
container.innerHTML = cards.map(card => `
|
|
1
|
+
/*! Copyright (c) 2026 AgentHippo.ai. All rights reserved. Proprietary; see LICENSE. */
|
|
2
|
+
"use strict";const panelApi=window.panelApi,AGENTIDE_PANEL_JS_VERSION="2026.07.21";try{window.__AGENTIDE_PANEL_JS_VERSION__=AGENTIDE_PANEL_JS_VERSION}catch{}const PANEL_ID="default",VIEW_EXPORT_SNAPSHOT="viewExportSnapshot",REQUEST_VIEW_EXPORT_SNAPSHOT="requestViewExportSnapshot",LEGACY_REQUEST_LIVE_FLEET_SNAPSHOT="requestLiveFleetSnapshot",LEGACY_VIEW_EXPORT_SNAPSHOT="liveFleetSnapshot",ADD_VIEW_OPTION_VALUE="__add_view__";function createDefaultPanelState(){return{version:1,charts:{},summaryHidden:!1}}const state={artifacts:[],galleryIgnorePatterns:[],summaryCards:null,manifest:null,isRefreshing:!1,scope:"global",projectId:"",agentId:"",agentIds:[],views:[],activeViewId:"global",disabledCharts:new Set,panelState:createDefaultPanelState(),panelStateLoaded:!1,lastArtifactCatalogSignature:"",fleetAutoRefreshIntervalSeconds:30,fleetRefreshVersion:0,surfaceMode:"spotlight",needsGalleryRender:!1,pendingForceFreshHtml:!1,refreshingViewId:null};function flushPendingGalleryRender(){if(!state.needsGalleryRender)return;state.needsGalleryRender=!1;const e=state.pendingForceFreshHtml;state.pendingForceFreshHtml=!1,renderGallery(state.artifacts,{forceFreshHtml:e})}function requestGalleryRender(e){if(state.isRefreshing){state.needsGalleryRender=!0,e?.forceFreshHtml&&(state.pendingForceFreshHtml=!0);return}renderGallery(state.artifacts,{forceFreshHtml:!!e?.forceFreshHtml})}function resetRefreshTrackingForViewChange(){!state.isRefreshing&&!state.needsGalleryRender&&!state.pendingForceFreshHtml||(state.isRefreshing=!1,state.refreshingViewId=null,state.needsGalleryRender=!1,state.pendingForceFreshHtml=!1,setRefreshButtonState(!1),setPerChartRefreshing(!1))}function applySurfaceMode(e){const t=e==="team";state.surfaceMode=t?"team":"spotlight",document.body.classList.toggle("spotlight-surface-team",t),applyTeamViewSelectVisibility()}let fleetAutoRefreshTimerId=null;function isFleetWidgetAtTop(){const e=document.querySelector(".fleet-dashboard-full.artifact-card");if(!e)return!0;const t=e.querySelector(".artifact-content");if(t&&t.scrollTop>4)return!1;const n=e.querySelector(".html-preview iframe");if(!n)return!0;try{const a=n.contentDocument,r=a?.body?.scrollTop??0,s=a?.documentElement?.scrollTop??0,o=n.contentWindow?.scrollY??0;return r<=4&&s<=4&&o<=4}catch{return!0}}function getActiveViewConfig(){return state.views.find(e=>e.id===state.activeViewId)}function activeViewUsesFleetDashboardLayout(){return getActiveViewConfig()?.layout==="fleet-dashboard"}function activeViewPreservesFleetIframe(){return getActiveViewConfig()?.preserveFleetIframe===!0}function activeViewIsLiveFleetSnapshot(){return activeViewPreservesFleetIframe()?!0:/^live-fleet-\d+$/.test(String(state.activeViewId||""))}function applyFleetAutoRefresh(){fleetAutoRefreshTimerId!==null&&(clearInterval(fleetAutoRefreshTimerId),fleetAutoRefreshTimerId=null);const e=state.fleetAutoRefreshIntervalSeconds;if((state.activeViewId==="fleet"||activeViewPreservesFleetIframe())&&typeof e=="number"&&e>0){const n=e*1e3;fleetAutoRefreshTimerId=setInterval(()=>{if(isFleetWidgetAtTop()){if(activeViewPreservesFleetIframe()){panelApi.postMessage({type:REQUEST_VIEW_EXPORT_SNAPSHOT});return}panelApi.postMessage({type:"refreshView"})}},n)}}function applyTeamViewSelectVisibility(){const e=document.getElementById("view-select");e&&(state.surfaceMode==="team"?state.views.length>1?e.style.setProperty("display","inline-block","important"):e.style.setProperty("display","none","important"):e.style.removeProperty("display"))}function applyViewOptions(){const e=document.getElementById("view-select");if(!e)return;const t=state.activeViewId||e.value||"";if(e.innerHTML="",state.surfaceMode!=="team"){const a=document.createElement("option");a.value=ADD_VIEW_OPTION_VALUE,a.textContent="+ Add view\u2026",e.appendChild(a)}for(const a of state.views){const r=document.createElement("option");r.value=a.id,r.textContent=a.name,e.appendChild(r)}const n=state.views.some(a=>a.id===state.activeViewId)?state.activeViewId:t;n&&state.views.some(a=>a.id===n)&&(e.value=n,state.activeViewId=n),applyTeamViewSelectVisibility(),applyShareButtonState()}const SHARE_ICON_HTML='<span class="btn-icon" aria-hidden="true">↑</span>',INSTALL_ICON_HTML='<span class="btn-icon" aria-hidden="true">↓</span>';function onInstallViewClick(){panelApi.postMessage({type:"installView"})}function onShareViewClick(){const e=getActiveView();panelApi.postMessage({type:"shareView",viewId:e?.id??"",bundle:"full"})}function onShareScriptsOnlyClick(){const e=getActiveView();panelApi.postMessage({type:"shareView",viewId:e?.id??"",bundle:"scripts-only"})}function ensureShareToolbarButton(){let e=document.getElementById("share-view-btn");if(e){const n=document.getElementById("refresh-charts-btn"),a=e.querySelector(".btn-icon");a&&a.textContent!=="\u2191"&&(a.outerHTML=SHARE_ICON_HTML),n&&e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING&&n.insertAdjacentElement("afterend",e)}else{const n=document.getElementById("refresh-charts-btn");if(!n?.parentElement)return;let a=n.closest(".toolbar-icon-group");a||(a=document.createElement("div"),a.className="toolbar-icon-group",n.parentElement.insertBefore(a,n),a.appendChild(n)),e=document.createElement("button"),e.id="share-view-btn",e.className="toolbar-btn icon-only",e.title="Publish current view to store (full bundle)",e.setAttribute("aria-label",e.title),e.innerHTML=SHARE_ICON_HTML,a.appendChild(e)}const t=document.getElementById("share-view-btn");t&&!t.dataset.boundShareClick&&(t.dataset.boundShareClick="1",t.addEventListener("click",onShareViewClick)),applyShareButtonState(),ensureInstallToolbarButton()}function ensureInstallToolbarButton(){let e=document.getElementById("install-view-btn");if(e){const n=document.getElementById("share-view-btn"),a=e.querySelector(".btn-icon");a&&a.textContent!=="\u2193"&&(a.outerHTML=INSTALL_ICON_HTML),n&&e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING&&n.insertAdjacentElement("afterend",e)}else{const n=document.getElementById("share-view-btn");if(!n?.parentElement)return;let a=n.closest(".toolbar-icon-group");a||(a=document.createElement("div"),a.className="toolbar-icon-group",n.parentElement.insertBefore(a,n),a.appendChild(n)),e=document.createElement("button"),e.id="install-view-btn",e.className="toolbar-btn icon-only",e.title="Install Spotlight view from store",e.setAttribute("aria-label",e.title),e.innerHTML=INSTALL_ICON_HTML,n.insertAdjacentElement("afterend",e)}const t=document.getElementById("install-view-btn");t&&!t.dataset.boundInstallClick&&(t.dataset.boundInstallClick="1",t.addEventListener("click",onInstallViewClick))}function applyShareButtonState(){const e=document.getElementById("share-view-btn");if(!e)return;const t=getActiveView(),n=!!(t&&!t.system);e.classList.toggle("share-unavailable",!n),e.title=n?"Publish current view to store (full bundle)":"Built-in views cannot be shared (duplicate or create a custom view)",e.setAttribute("aria-label",e.title);const a=document.getElementById("share-scripts-only-menu-item");a&&(a.disabled=!1,a.classList.toggle("share-unavailable",!n),a.title=n?"Publish widget scripts only (no charts or exports)":"Built-in views cannot be shared (duplicate or create a custom view)")}function getActiveView(){return state.views.find(e=>e.id===state.activeViewId)}function switchToView(e){if(!e||e===state.activeViewId)return;state.activeViewId=e,resetRefreshTrackingForViewChange(),state.panelStateLoaded=!1,state.panelState=createDefaultPanelState();const t=document.getElementById("view-select");t&&state.views.some(n=>n.id===e)&&(t.value=e),applyFleetAutoRefresh(),applyShareButtonState(),panelApi.postMessage({type:"setActiveView",viewId:e}),panelApi.postMessage({type:"requestPanelState",panelId:PANEL_ID})}function showNewViewModal(e){const t=document.getElementById("new-view-modal"),n=document.getElementById("new-view-name-input"),a=document.getElementById("new-view-modal-ok"),r=document.getElementById("new-view-modal-cancel");if(!t||!n||!a||!r)return;typeof e=="function"&&e(),n.value="",t.style.display="flex",t.setAttribute("aria-hidden","false"),n.focus();function s(){t.style.display="none",t.setAttribute("aria-hidden","true"),t.removeEventListener("click",f),document.removeEventListener("keydown",l)}function o(){const c=n.value.trim();s(),c&&panelApi.postMessage({type:"createView",name:c})}function f(c){c.target===t&&s()}function l(c){c.key==="Escape"?(s(),c.preventDefault()):c.key==="Enter"&&(o(),c.preventDefault())}t.addEventListener("click",f),document.addEventListener("keydown",l),a.onclick=()=>o(),r.onclick=()=>s()}function promptCreateView(){showNewViewModal()}function initViews(){const e=document.getElementById("view-select");e?.addEventListener("change",()=>{const t=e.value||"";if(t){if(t===ADD_VIEW_OPTION_VALUE){showNewViewModal(()=>{e.value=state.activeViewId||""});return}t!==state.activeViewId&&switchToView(t)}})}function refreshCurrentView(){const e=document.getElementById("refresh-charts-btn");e&&!e.classList.contains("refreshing")&&(setRefreshButtonState(!0),panelApi.postMessage({type:"refreshView"}))}function formatTimeAgo(e){const t=Math.floor((Date.now()-e.getTime())/1e3);return t<60?"just now":t<3600?`${Math.floor(t/60)} min ago`:t<86400?`${Math.floor(t/3600)}h ago`:`${Math.floor(t/86400)}d ago`}function formatSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function renderMarkdown(e){return e.replace(/```(\w*)\n([\s\S]*?)```/g,'<pre><code class="language-$1">$2</code></pre>').replace(/`([^`]+)`/g,"<code>$1</code>").replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>").replace(/\*(.+?)\*/g,"<em>$1</em>").replace(/^### (.+)$/gm,"<h3>$1</h3>").replace(/^## (.+)$/gm,"<h2>$1</h2>").replace(/^# (.+)$/gm,"<h1>$1</h1>").replace(/\n/g,"<br>")}function normalizeFilename(e){return String(e||"").trim().toLowerCase()}function normalizePanelState(e){const t=e&&typeof e=="object"?e:{},n=t.charts&&typeof t.charts=="object"?t.charts:{},a={};let r=1;for(const[o,f]of Object.entries(n)){const l=normalizeFilename(o);if(!l)continue;const c=f&&typeof f=="object"?f:{},p=Number(c.order),v=Number.isFinite(p)&&p>0?p:r,L=c.hidden===!0,S=Number(c.height),x=c.expanded===!0;a[l]={order:v,hidden:L,height:Number.isFinite(S)&&S>=120?S:void 0,expanded:x},r=Math.max(r,v+1)}const s=t.summaryHidden===!0;return{version:1,charts:a,summaryHidden:s}}function getNextChartOrder(){const e=Object.values(state.panelState.charts);return e.length===0?1:e.reduce((t,n)=>Math.max(t,n.order),0)+1}function ensurePanelStateForArtifacts(e){let t=!1,n=getNextChartOrder();for(const a of e){if(a.type!=="chart"&&a.type!=="image")continue;const r=normalizeFilename(String(a.filename||""));r&&(state.panelState.charts[r]||(state.panelState.charts[r]={order:n++,hidden:!1,height:void 0,expanded:!1},t=!0))}return t}function getChartPanelState(e){const t=normalizeFilename(e);return state.panelState.charts[t]||(state.panelState.charts[t]={order:getNextChartOrder(),hidden:!1,height:void 0,expanded:!1}),state.panelState.charts[t]}function setChartHeight(e,t){const n=getChartPanelState(e);n.height=t>=120&&t<=2e3?t:void 0,savePanelState()}function setChartExpanded(e,t){const n=getChartPanelState(e);n.expanded=t===!0,savePanelState()}function autoFitFleetCardHeight(e){const t=e?.dataset?.filename||"";if(!t)return;const n=getChartPanelState(t);if(typeof n.height=="number"&&Number.isFinite(n.height))return;const a=e.querySelector(".artifact-content"),r=e.querySelector(".html-preview iframe");if(!a||!r)return;let s=0;try{const p=r.contentDocument,v=p?.body,L=p?.documentElement;s=Math.max(v?.scrollHeight||0,v?.offsetHeight||0,L?.scrollHeight||0,L?.offsetHeight||0,L?.clientHeight||0)}catch{return}if(!Number.isFinite(s)||s<=0)return;const o=window.getComputedStyle(a),f=Number.parseFloat(o.paddingTop||"0")||0,l=Number.parseFloat(o.paddingBottom||"0")||0,c=Math.round(Math.max(320,Math.min(2e3,s+f+l)));a.style.height=`${c}px`,a.style.minHeight=`${c}px`,a.style.overflow="hidden",syncEmbeddedPreviewSize(a),setChartHeight(t,c)}function syncEmbeddedPreviewSize(e){const t=e.querySelector(".html-preview");t instanceof HTMLElement&&(t.style.height="100%",t.style.minHeight="0");const n=e.querySelector(".html-preview iframe");if(n instanceof HTMLIFrameElement){n.style.height="100%",n.style.minHeight="0",n.style.display="block";try{n.contentWindow?.dispatchEvent(new Event("resize"))}catch{}}}function attachResizeHandle(e,t){if(!e||!t)return;const n=e.querySelector(".resize-handle"),a=e.querySelector(".artifact-content");if(!n||!a)return;const r=e,s=a,o=120,f=2e3;n.addEventListener("mousedown",l=>{l.preventDefault(),l.stopPropagation();const c=l.clientY,v=s.getBoundingClientRect().height;let L=!1,S=0;const x=()=>{S&&cancelAnimationFrame(S),S=requestAnimationFrame(()=>{S=0,syncEmbeddedPreviewSize(s)})},k=M=>{const T=M.clientY-c;Math.abs(T)>2&&(L=!0);let i=Math.round(v+T);i=Math.max(o,Math.min(f,i)),s.style.height=`${i}px`,s.style.minHeight=`${i}px`,s.style.overflow="hidden",x()},H=()=>{if(document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",H),S&&(cancelAnimationFrame(S),S=0),syncEmbeddedPreviewSize(s),L){const T=s.getBoundingClientRect().height;setChartHeight(t,Math.round(T));return}const M=!r.classList.contains("expanded");r.classList.toggle("expanded",M),setChartExpanded(t,M)};document.addEventListener("mousemove",k),document.addEventListener("mouseup",H)})}function toggleSummarySection(){state.panelState.summaryHidden=!state.panelState.summaryHidden,applySummarySectionVisibility(),savePanelState()}function applySummarySectionVisibility(){const e=document.getElementById("summary-section"),t=document.getElementById("summary-toggle-btn");e&&e.classList.toggle("collapsed",state.panelState.summaryHidden===!0),t&&(t.textContent=state.panelState.summaryHidden?"Show":"Hide",t.title=state.panelState.summaryHidden?"Show summary section":"Hide summary section",t.setAttribute("aria-label",state.panelState.summaryHidden?"Show summary":"Hide summary"))}function savePanelState(){panelApi.postMessage({type:"savePanelState",panelId:PANEL_ID,state:state.panelState})}function moveChartInPanelState(e,t,n){const a=normalizeFilename(e);if(!a)return;getChartPanelState(e);const r=Object.entries(state.panelState.charts).sort((p,v)=>p[1].order-v[1].order||p[0].localeCompare(v[0])).map(([p])=>p),s=r.indexOf(a);if(s<0)return;const o=new Set((n||[]).map(p=>normalizeFilename(p)).filter(Boolean));o.add(a);const f=t==="up"?-1:1;let l=s+f;for(;l>=0&&l<r.length&&!o.has(r[l]);)l+=f;if(l<0||l>=r.length||l===s)return;const[c]=r.splice(s,1);r.splice(l,0,c),r.forEach((p,v)=>{const L=state.panelState.charts[p];L.order=v+1}),savePanelState()}function toggleChartHiddenInPanelState(e){const t=getChartPanelState(e);t.hidden=!t.hidden,savePanelState()}let lastSummaryCardsSignature="";function renderSummaryCards(e){const t=document.getElementById("summary-cards");if(!t)return;if(!e||e.length===0){lastSummaryCardsSignature="",renderSummaryPlaceholders();return}const n=JSON.stringify(e);n===lastSummaryCardsSignature&&!t.classList.contains("loading")||(lastSummaryCardsSignature=n,t.style.display="grid",t.classList.remove("loading"),t.innerHTML=e.map(a=>`
|
|
939
3
|
<div class="metric-card">
|
|
940
|
-
<div class="metric-icon">${
|
|
941
|
-
<div class="metric-value">${escapeHtml(
|
|
942
|
-
<div class="metric-label">${escapeHtml(
|
|
4
|
+
<div class="metric-icon">${a.icon}</div>
|
|
5
|
+
<div class="metric-value">${escapeHtml(a.value)}</div>
|
|
6
|
+
<div class="metric-label">${escapeHtml(a.label)}</div>
|
|
943
7
|
</div>
|
|
944
|
-
`).join(
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
/**
|
|
948
|
-
* Render summary placeholders while data is loading.
|
|
949
|
-
*/
|
|
950
|
-
function renderSummaryPlaceholders() {
|
|
951
|
-
const container = document.getElementById('summary-cards');
|
|
952
|
-
if (!container) {
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
container.style.display = 'grid';
|
|
957
|
-
container.classList.add('loading');
|
|
958
|
-
container.innerHTML = Array.from({ length: 4 }).map(() => `
|
|
8
|
+
`).join(""))}function renderSummaryPlaceholders(){const e=document.getElementById("summary-cards");e&&(e.style.display="grid",e.classList.add("loading"),e.innerHTML=Array.from({length:4}).map(()=>`
|
|
959
9
|
<div class="metric-card skeleton">
|
|
960
10
|
<div class="skeleton-line skeleton-icon"></div>
|
|
961
11
|
<div class="skeleton-line skeleton-value"></div>
|
|
962
12
|
<div class="skeleton-line skeleton-label"></div>
|
|
963
13
|
</div>
|
|
964
|
-
`).join(
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
// Gallery Rendering
|
|
969
|
-
// -----------------------------------------------------------------------------
|
|
970
|
-
|
|
971
|
-
/**
|
|
972
|
-
* Show a specific gallery state
|
|
973
|
-
* @param {'loading' | 'empty' | 'generating' | 'failed' | 'content'} stateName
|
|
974
|
-
*/
|
|
975
|
-
function showGalleryState(stateName) {
|
|
976
|
-
const states = ['loading-state', 'empty-state', 'generating-state', 'failed-state', 'gallery-content'];
|
|
977
|
-
for (const id of states) {
|
|
978
|
-
const el = document.getElementById(id);
|
|
979
|
-
if (el) {
|
|
980
|
-
el.style.display = id === `${stateName}-state` || id === `${stateName}` ? 'flex' : 'none';
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
// gallery-content needs 'block' not 'flex'
|
|
985
|
-
const content = document.getElementById('gallery-content');
|
|
986
|
-
if (content) {
|
|
987
|
-
content.style.display = stateName === 'content' ? 'block' : 'none';
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* Render the artifact gallery
|
|
993
|
-
* @param {Array<object>} artifacts
|
|
994
|
-
* @param {{ forceFreshHtml?: boolean }} [options]
|
|
995
|
-
*/
|
|
996
|
-
function renderGallery(artifacts, options) {
|
|
997
|
-
const forceFreshHtml = options?.forceFreshHtml === true;
|
|
998
|
-
const container = document.getElementById('gallery-content');
|
|
999
|
-
if (!container) {
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
// Preserve existing HTML iframes across incremental refreshes when the
|
|
1003
|
-
// artifact content version (modifiedAt) did not change.
|
|
1004
|
-
/** @type {Map<string, HTMLIFrameElement>} */
|
|
1005
|
-
const reusableHtmlPreviews = new Map();
|
|
1006
|
-
container.querySelectorAll('.artifact-card').forEach((cardEl) => {
|
|
1007
|
-
const card = /** @type {HTMLElement} */ (cardEl);
|
|
1008
|
-
const path = card.dataset.path || '';
|
|
1009
|
-
const modifiedAt = card.dataset.modifiedAt || '';
|
|
1010
|
-
if (!path || !modifiedAt) {
|
|
1011
|
-
return;
|
|
1012
|
-
}
|
|
1013
|
-
const iframe = /** @type {HTMLIFrameElement | null} */ (card.querySelector('.html-preview iframe'));
|
|
1014
|
-
if (!iframe) {
|
|
1015
|
-
return;
|
|
1016
|
-
}
|
|
1017
|
-
reusableHtmlPreviews.set(`${path}::${modifiedAt}`, iframe);
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
const layoutChanged = ensurePanelStateForArtifacts(artifacts);
|
|
1021
|
-
if (layoutChanged && state.panelStateLoaded) {
|
|
1022
|
-
savePanelState();
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
const visibleArtifacts = artifacts.filter((artifact) => {
|
|
1026
|
-
const filename = String(artifact.filename || '').trim().toLowerCase();
|
|
1027
|
-
// Hide artifacts matching galleryIgnorePatterns (suffix or exact name); list is from disabled-charts.yaml
|
|
1028
|
-
const ignored = state.galleryIgnorePatterns.some((p) => {
|
|
1029
|
-
const pattern = String(p).trim().toLowerCase();
|
|
1030
|
-
return pattern && (filename.endsWith(pattern) || filename === pattern);
|
|
1031
|
-
});
|
|
1032
|
-
if (ignored) {
|
|
1033
|
-
return false;
|
|
1034
|
-
}
|
|
1035
|
-
// Live Fleet iframe views: export JSON is pushed via viewExportSnapshot — skip gallery cards (Open/Delete).
|
|
1036
|
-
if (activeViewIsLiveFleetSnapshot() && artifact.type !== 'chart' && artifact.type !== 'image') {
|
|
1037
|
-
return false;
|
|
1038
|
-
}
|
|
1039
|
-
if (artifact.type !== 'chart' && artifact.type !== 'image') {
|
|
1040
|
-
return true;
|
|
1041
|
-
}
|
|
1042
|
-
return !state.disabledCharts.has(filename);
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
const chartArtifacts = visibleArtifacts
|
|
1046
|
-
.filter((artifact) => artifact.type === 'chart' || artifact.type === 'image')
|
|
1047
|
-
.map((artifact) => ({
|
|
1048
|
-
...artifact,
|
|
1049
|
-
_panel: getChartPanelState(String(artifact.filename || '')),
|
|
1050
|
-
}))
|
|
1051
|
-
.sort((a, b) => {
|
|
1052
|
-
if (a._panel.hidden !== b._panel.hidden) {
|
|
1053
|
-
return a._panel.hidden ? 1 : -1;
|
|
1054
|
-
}
|
|
1055
|
-
if (a._panel.order !== b._panel.order) {
|
|
1056
|
-
return a._panel.order - b._panel.order;
|
|
1057
|
-
}
|
|
1058
|
-
return new Date(b.modifiedAt).getTime() - new Date(a.modifiedAt).getTime();
|
|
1059
|
-
});
|
|
1060
|
-
const nonChartArtifacts = visibleArtifacts
|
|
1061
|
-
.filter((artifact) => artifact.type !== 'chart')
|
|
1062
|
-
.sort((a, b) => new Date(b.modifiedAt).getTime() - new Date(a.modifiedAt).getTime());
|
|
1063
|
-
const orderedArtifacts = [...chartArtifacts, ...nonChartArtifacts];
|
|
1064
|
-
|
|
1065
|
-
if (orderedArtifacts.length === 0) {
|
|
1066
|
-
showGalleryState('empty');
|
|
1067
|
-
return;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
// Export JSON alongside the chart is normal for live fleet views — do not fall back to gallery layout.
|
|
1071
|
-
const nonChartNonExportArtifacts = nonChartArtifacts.filter((artifact) => artifact.type !== 'export');
|
|
1072
|
-
const fleetHtmlCharts = chartArtifacts.filter((artifact) => artifact.format === 'html');
|
|
1073
|
-
const isFleetSingleHtml =
|
|
1074
|
-
(fleetHtmlCharts.length >= 1 && activeViewIsLiveFleetSnapshot())
|
|
1075
|
-
|| (activeViewUsesFleetDashboardLayout() &&
|
|
1076
|
-
chartArtifacts.length === 1 &&
|
|
1077
|
-
chartArtifacts[0].format === 'html' &&
|
|
1078
|
-
nonChartNonExportArtifacts.length === 0);
|
|
1079
|
-
if (isFleetSingleHtml) {
|
|
1080
|
-
const artifact = fleetHtmlCharts[0];
|
|
1081
|
-
const path = artifact.localPath || '';
|
|
1082
|
-
const modifiedAt = String(artifact.modifiedAt || '');
|
|
1083
|
-
const fleetFilename = String(artifact.filename || '').trim() || '__fleet__';
|
|
1084
|
-
const chartState = getChartPanelState(fleetFilename);
|
|
1085
|
-
const fleetExpandedClass = chartState.expanded ? ' expanded' : '';
|
|
1086
|
-
const fleetHeightStyle = chartState.height
|
|
1087
|
-
? `style="height: ${chartState.height}px; min-height: ${chartState.height}px; overflow: auto;"`
|
|
1088
|
-
: '';
|
|
1089
|
-
const existingFleetCard = /** @type {HTMLElement | null} */ (
|
|
1090
|
-
container.querySelector('.fleet-dashboard-full.artifact-card')
|
|
1091
|
-
);
|
|
1092
|
-
// preserveFleetIframe views: keep the iframe mounted; data updates arrive via viewExportSnapshot postMessage.
|
|
1093
|
-
let fleetIframeHasSnapshotShell = false;
|
|
1094
|
-
if (activeViewPreservesFleetIframe() && existingFleetCard) {
|
|
1095
|
-
const fleetIframe = existingFleetCard.querySelector('.html-preview iframe');
|
|
1096
|
-
if (fleetIframe instanceof HTMLIFrameElement) {
|
|
1097
|
-
try {
|
|
1098
|
-
const doc = fleetIframe.contentDocument;
|
|
1099
|
-
fleetIframeHasSnapshotShell =
|
|
1100
|
-
doc?.body?.dataset?.fleetSnapshotShell === '1'
|
|
1101
|
-
|| doc?.documentElement?.hasAttribute('data-live-fleet-shell');
|
|
1102
|
-
} catch {
|
|
1103
|
-
fleetIframeHasSnapshotShell = false;
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
if (
|
|
1108
|
-
activeViewPreservesFleetIframe()
|
|
1109
|
-
&& existingFleetCard
|
|
1110
|
-
&& existingFleetCard.dataset.path === path
|
|
1111
|
-
&& existingFleetCard.querySelector('.html-preview iframe')
|
|
1112
|
-
&& fleetIframeHasSnapshotShell
|
|
1113
|
-
&& !forceFreshHtml
|
|
1114
|
-
) {
|
|
1115
|
-
showGalleryState('content');
|
|
1116
|
-
existingFleetCard.dataset.modifiedAt = modifiedAt;
|
|
1117
|
-
attachResizeHandle(existingFleetCard, fleetFilename);
|
|
1118
|
-
return;
|
|
1119
|
-
}
|
|
1120
|
-
const reusable = forceFreshHtml ? undefined : reusableHtmlPreviews.get(`${path}::${modifiedAt}`);
|
|
1121
|
-
showGalleryState('content');
|
|
1122
|
-
container.innerHTML = `
|
|
1123
|
-
<div class="fleet-dashboard-full artifact-card${fleetExpandedClass}" data-path="${escapeHtml(path)}" data-filename="${escapeHtml(fleetFilename)}" data-modified-at="${escapeHtml(modifiedAt)}">
|
|
1124
|
-
<div class="artifact-content" ${fleetHeightStyle}>
|
|
1125
|
-
<div class="html-preview">${reusable ? '' : '<div class="html-preview-loading">Loading Fleet Operations...</div>'}</div>
|
|
14
|
+
`).join(""))}function showGalleryState(e){const t=["loading-state","empty-state","generating-state","failed-state","gallery-content"];for(const a of t){const r=document.getElementById(a);r&&(r.style.display=a===`${e}-state`||a===`${e}`?"flex":"none")}const n=document.getElementById("gallery-content");n&&(n.style.display=e==="content"?"block":"none")}function renderGallery(e,t){const n=t?.forceFreshHtml===!0,a=document.getElementById("gallery-content");if(!a)return;const r=new Map;a.querySelectorAll(".artifact-card").forEach(i=>{const d=i,b=d.dataset.path||"",g=d.dataset.modifiedAt||"";if(!b||!g)return;const m=d.querySelector(".html-preview iframe");m&&r.set(`${b}::${g}`,m)}),ensurePanelStateForArtifacts(e)&&state.panelStateLoaded&&savePanelState();const o=e.filter(i=>{const d=String(i.filename||"").trim().toLowerCase();return state.galleryIgnorePatterns.some(g=>{const m=String(g).trim().toLowerCase();return m&&(d.endsWith(m)||d===m)})||activeViewIsLiveFleetSnapshot()&&i.type!=="chart"&&i.type!=="image"?!1:i.type!=="chart"&&i.type!=="image"?!0:!state.disabledCharts.has(d)}),f=o.filter(i=>i.type==="chart"||i.type==="image").map(i=>({...i,_panel:getChartPanelState(String(i.filename||""))})).sort((i,d)=>i._panel.hidden!==d._panel.hidden?i._panel.hidden?1:-1:i._panel.order!==d._panel.order?i._panel.order-d._panel.order:new Date(d.modifiedAt).getTime()-new Date(i.modifiedAt).getTime()),l=o.filter(i=>i.type!=="chart").sort((i,d)=>new Date(d.modifiedAt).getTime()-new Date(i.modifiedAt).getTime()),c=[...f,...l];if(c.length===0){showGalleryState("empty");return}const p=l.filter(i=>i.type!=="export"),v=f.filter(i=>i.format==="html");if(v.length>=1&&activeViewIsLiveFleetSnapshot()||activeViewUsesFleetDashboardLayout()&&f.length===1&&f[0].format==="html"&&p.length===0){const i=v[0],d=i.localPath||"",b=String(i.modifiedAt||""),g=String(i.filename||"").trim()||"__fleet__",m=getChartPanelState(g),I=m.expanded?" expanded":"",E=m.height?`style="height: ${m.height}px; min-height: ${m.height}px; overflow: auto;"`:"",u=a.querySelector(".fleet-dashboard-full.artifact-card");let A=!1;if(activeViewPreservesFleetIframe()&&u){const h=u.querySelector(".html-preview iframe");if(h instanceof HTMLIFrameElement)try{const C=h.contentDocument;A=C?.body?.dataset?.fleetSnapshotShell==="1"||C?.documentElement?.hasAttribute("data-live-fleet-shell")}catch{A=!1}}if(activeViewPreservesFleetIframe()&&u&&u.dataset.path===d&&u.querySelector(".html-preview iframe")&&A&&!n){showGalleryState("content"),u.dataset.modifiedAt=b,attachResizeHandle(u,g);return}const w=n?void 0:r.get(`${d}::${b}`);if(showGalleryState("content"),a.innerHTML=`
|
|
15
|
+
<div class="fleet-dashboard-full artifact-card${I}" data-path="${escapeHtml(d)}" data-filename="${escapeHtml(g)}" data-modified-at="${escapeHtml(b)}">
|
|
16
|
+
<div class="artifact-content" ${E}>
|
|
17
|
+
<div class="html-preview">${w?"":'<div class="html-preview-loading">Loading Fleet Operations...</div>'}</div>
|
|
1126
18
|
</div>
|
|
1127
|
-
<div class="resize-handle" data-filename="${escapeHtml(
|
|
19
|
+
<div class="resize-handle" data-filename="${escapeHtml(g)}" title="Drag to resize height" role="separator"></div>
|
|
1128
20
|
</div>
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
const host = container.querySelector('.html-preview');
|
|
1132
|
-
if (host) {
|
|
1133
|
-
host.classList.add('ready');
|
|
1134
|
-
host.appendChild(reusable);
|
|
1135
|
-
}
|
|
1136
|
-
} else {
|
|
1137
|
-
requestHtmlPreviewContents([artifact]);
|
|
1138
|
-
}
|
|
1139
|
-
const fleetCard = container.querySelector('.artifact-card');
|
|
1140
|
-
attachResizeHandle(fleetCard, fleetFilename);
|
|
1141
|
-
if (fleetCard instanceof HTMLElement) {
|
|
1142
|
-
fleetCard.addEventListener('click', (event) => {
|
|
1143
|
-
const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null);
|
|
1144
|
-
if (target?.closest('button,.resize-handle')) {
|
|
1145
|
-
return;
|
|
1146
|
-
}
|
|
1147
|
-
const nextExpanded = !fleetCard.classList.contains('expanded');
|
|
1148
|
-
fleetCard.classList.toggle('expanded', nextExpanded);
|
|
1149
|
-
setChartExpanded(fleetFilename, nextExpanded);
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
showGalleryState('content');
|
|
1156
|
-
|
|
1157
|
-
const buildCardHtml = (artifact) => {
|
|
1158
|
-
const timeAgo = formatTimeAgo(new Date(artifact.modifiedAt));
|
|
1159
|
-
const sizeFormatted = formatSize(artifact.size);
|
|
1160
|
-
const isChart = artifact.type === 'chart';
|
|
1161
|
-
const isImage = artifact.type === 'image';
|
|
1162
|
-
const isVisual = isChart || isImage;
|
|
1163
|
-
const chartState = isVisual ? artifact._panel : undefined;
|
|
1164
|
-
const isHidden = chartState?.hidden === true;
|
|
1165
|
-
const isExpanded = chartState?.expanded === true;
|
|
1166
|
-
const order = Number.isFinite(chartState?.order) ? chartState.order : undefined;
|
|
1167
|
-
|
|
1168
|
-
// Render based on format
|
|
1169
|
-
let content = '';
|
|
1170
|
-
switch (artifact.format) {
|
|
1171
|
-
case 'png':
|
|
1172
|
-
case 'svg':
|
|
1173
|
-
case 'jpg':
|
|
1174
|
-
content = `<img src="${artifact.webviewUri}" alt="${escapeHtml(artifact.filename)}" loading="lazy" />`;
|
|
1175
|
-
break;
|
|
1176
|
-
case 'html':
|
|
1177
|
-
content = `
|
|
1178
|
-
<div class="html-preview" data-path="${escapeHtml(artifact.localPath)}">
|
|
21
|
+
`,w){const h=a.querySelector(".html-preview");h&&(h.classList.add("ready"),h.appendChild(w))}else requestHtmlPreviewContents([i]);const y=a.querySelector(".artifact-card");attachResizeHandle(y,g),y instanceof HTMLElement&&y.addEventListener("click",h=>{if((h.target instanceof HTMLElement?h.target:null)?.closest("button,.resize-handle"))return;const V=!y.classList.contains("expanded");y.classList.toggle("expanded",V),setChartExpanded(g,V)});return}showGalleryState("content");const S=i=>{const d=formatTimeAgo(new Date(i.modifiedAt)),b=formatSize(i.size),g=i.type==="chart",m=i.type==="image",I=g||m,E=I?i._panel:void 0,u=E?.hidden===!0,A=E?.expanded===!0,w=Number.isFinite(E?.order)?E.order:void 0;let y="";switch(i.format){case"png":case"svg":case"jpg":y=`<img src="${i.webviewUri}" alt="${escapeHtml(i.filename)}" loading="lazy" />`;break;case"html":y=`
|
|
22
|
+
<div class="html-preview" data-path="${escapeHtml(i.localPath)}">
|
|
1179
23
|
<div class="html-preview-loading">Loading preview...</div>
|
|
1180
24
|
</div>
|
|
1181
|
-
`;
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
case 'csv':
|
|
1187
|
-
case 'json':
|
|
1188
|
-
content = `<div class="data-preview"><code>${escapeHtml(artifact.filename)}</code></div>`;
|
|
1189
|
-
break;
|
|
1190
|
-
default:
|
|
1191
|
-
content = `<div class="data-preview"><code>${escapeHtml(artifact.filename)}</code></div>`;
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
// Find manifest entry for this artifact
|
|
1195
|
-
const manifestEntry = state.manifest?.artifacts?.find(e => e.filename === artifact.filename);
|
|
1196
|
-
const title = manifestEntry?.title || artifact.filename;
|
|
1197
|
-
const generatorBadge = artifact.generator
|
|
1198
|
-
? `<span class="generator-badge">${escapeHtml(artifact.generator)}</span>`
|
|
1199
|
-
: '';
|
|
1200
|
-
const sourceBadge = manifestEntry?.source === 'default'
|
|
1201
|
-
? '<span class="source-badge">Auto</span>'
|
|
1202
|
-
: '';
|
|
1203
|
-
const hiddenBadge = isVisual && isHidden
|
|
1204
|
-
? '<span class="layout-badge disabled">Hidden</span>'
|
|
1205
|
-
: '';
|
|
1206
|
-
const orderBadge = isVisual && Number.isFinite(order)
|
|
1207
|
-
? `<span class="layout-badge">#${order}</span>`
|
|
1208
|
-
: '';
|
|
1209
|
-
const layoutActions = isVisual
|
|
1210
|
-
? `
|
|
1211
|
-
<button class="action-btn move-up-btn" title="Move up">↑</button>
|
|
1212
|
-
<button class="action-btn move-down-btn" title="Move down">↓</button>
|
|
1213
|
-
<button class="action-btn toggle-enabled-btn" title="${isHidden ? 'Show chart' : 'Hide chart'}">
|
|
1214
|
-
${isHidden ? 'Show' : 'Hide'}
|
|
25
|
+
`;break;case"md":y=`<div class="markdown-preview" data-path="${escapeHtml(i.localPath)}">Loading...</div>`;break;case"csv":case"json":y=`<div class="data-preview"><code>${escapeHtml(i.filename)}</code></div>`;break;default:y=`<div class="data-preview"><code>${escapeHtml(i.filename)}</code></div>`}const h=state.manifest?.artifacts?.find(_=>_.filename===i.filename),C=h?.title||i.filename,V=i.generator?`<span class="generator-badge">${escapeHtml(i.generator)}</span>`:"",F=h?.source==="default"?'<span class="source-badge">Auto</span>':"",B=I&&u?'<span class="layout-badge disabled">Hidden</span>':"",$=I&&Number.isFinite(w)?`<span class="layout-badge">#${w}</span>`:"",q=I?`
|
|
26
|
+
<button class="action-btn move-up-btn" title="Move up">\u2191</button>
|
|
27
|
+
<button class="action-btn move-down-btn" title="Move down">\u2193</button>
|
|
28
|
+
<button class="action-btn toggle-enabled-btn" title="${u?"Show chart":"Hide chart"}">
|
|
29
|
+
${u?"Show":"Hide"}
|
|
1215
30
|
</button>
|
|
1216
|
-
`
|
|
1217
|
-
:
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
: '';
|
|
1221
|
-
const resizeHandle = isVisual
|
|
1222
|
-
? `<div class="resize-handle" data-filename="${escapeHtml(artifact.filename)}" title="Drag to resize height" role="separator"></div>`
|
|
1223
|
-
: '';
|
|
1224
|
-
|
|
1225
|
-
return `
|
|
1226
|
-
<div class="artifact-card ${isVisual && isHidden ? 'layout-disabled' : ''}${isExpanded ? ' expanded' : ''}" data-path="${escapeHtml(artifact.localPath)}" data-type="${artifact.type}" data-filename="${escapeHtml(artifact.filename)}" data-modified-at="${escapeHtml(String(artifact.modifiedAt || ''))}">
|
|
1227
|
-
<div class="artifact-content" ${contentHeightStyle}>
|
|
1228
|
-
${content}
|
|
31
|
+
`:"",P=I&&E?.height?`style="height: ${E.height}px; min-height: ${E.height}px; overflow: auto;"`:"",R=I?`<div class="resize-handle" data-filename="${escapeHtml(i.filename)}" title="Drag to resize height" role="separator"></div>`:"";return`
|
|
32
|
+
<div class="artifact-card ${I&&u?"layout-disabled":""}${A?" expanded":""}" data-path="${escapeHtml(i.localPath)}" data-type="${i.type}" data-filename="${escapeHtml(i.filename)}" data-modified-at="${escapeHtml(String(i.modifiedAt||""))}">
|
|
33
|
+
<div class="artifact-content" ${P}>
|
|
34
|
+
${y}
|
|
1229
35
|
</div>
|
|
1230
36
|
<div class="artifact-meta">
|
|
1231
|
-
<span class="artifact-name" title="${escapeHtml(
|
|
1232
|
-
${
|
|
1233
|
-
${
|
|
1234
|
-
${
|
|
1235
|
-
${
|
|
1236
|
-
<span class="artifact-time">${
|
|
1237
|
-
<span class="artifact-size">${
|
|
37
|
+
<span class="artifact-name" title="${escapeHtml(i.filename)}">${escapeHtml(C)}</span>
|
|
38
|
+
${F}
|
|
39
|
+
${B}
|
|
40
|
+
${$}
|
|
41
|
+
${V}
|
|
42
|
+
<span class="artifact-time">${d}</span>
|
|
43
|
+
<span class="artifact-size">${b}</span>
|
|
1238
44
|
</div>
|
|
1239
45
|
<div class="artifact-actions">
|
|
1240
46
|
<button class="action-btn open-btn" title="Open in editor">Open</button>
|
|
1241
47
|
<button class="action-btn delete-btn" title="Delete artifact">Delete</button>
|
|
1242
|
-
${
|
|
48
|
+
${q}
|
|
1243
49
|
</div>
|
|
1244
|
-
${
|
|
50
|
+
${R}
|
|
1245
51
|
</div>
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
// Keyed card reuse: diff incoming artifacts against existing cards by localPath and only
|
|
1249
|
-
// rebuild what changed. Rebuilding a card destroys its iframe/img and re-fetches content —
|
|
1250
|
-
// that teardown is the visible blink — so unchanged cards must not be touched at all.
|
|
1251
|
-
/** @type {Map<string, HTMLElement>} */
|
|
1252
|
-
const existingCards = new Map();
|
|
1253
|
-
Array.from(container.children).forEach((childEl) => {
|
|
1254
|
-
const child = /** @type {HTMLElement} */ (childEl);
|
|
1255
|
-
const childPath = child.dataset.path || '';
|
|
1256
|
-
const reusableAsCard =
|
|
1257
|
-
child.classList.contains('artifact-card')
|
|
1258
|
-
&& !child.classList.contains('fleet-dashboard-full') // fleet layout card: different structure
|
|
1259
|
-
&& !child.classList.contains('deleting')
|
|
1260
|
-
&& childPath
|
|
1261
|
-
&& !existingCards.has(childPath);
|
|
1262
|
-
if (!reusableAsCard) {
|
|
1263
|
-
child.remove();
|
|
1264
|
-
return;
|
|
1265
|
-
}
|
|
1266
|
-
existingCards.set(childPath, child);
|
|
1267
|
-
});
|
|
1268
|
-
|
|
1269
|
-
/** @type {Array<object>} */
|
|
1270
|
-
const htmlArtifactsNeedingFetch = [];
|
|
1271
|
-
/** @type {Array<object>} */
|
|
1272
|
-
const markdownArtifactsNeedingFetch = [];
|
|
1273
|
-
/** @type {HTMLElement[]} */
|
|
1274
|
-
const orderedCards = [];
|
|
1275
|
-
for (const artifact of orderedArtifacts) {
|
|
1276
|
-
const path = String(artifact.localPath || '');
|
|
1277
|
-
const modifiedAt = String(artifact.modifiedAt || '');
|
|
1278
|
-
const isVisual = artifact.type === 'chart' || artifact.type === 'image';
|
|
1279
|
-
const chartState = isVisual ? artifact._panel : undefined;
|
|
1280
|
-
const signature = computeCardRenderSignature(artifact);
|
|
1281
|
-
const forceHtmlReload = forceFreshHtml && artifact.format === 'html';
|
|
1282
|
-
const existing = existingCards.get(path);
|
|
1283
|
-
existingCards.delete(path);
|
|
1284
|
-
|
|
1285
|
-
if (existing && existing.dataset.cardSignature === signature && !forceHtmlReload) {
|
|
1286
|
-
// Unchanged: leave the DOM (and any live iframe) alone. Expanded/height are kept
|
|
1287
|
-
// out of the signature and applied in place so toggling them never reloads content.
|
|
1288
|
-
if (isVisual) {
|
|
1289
|
-
existing.classList.toggle('expanded', chartState?.expanded === true);
|
|
1290
|
-
const contentEl = /** @type {HTMLElement | null} */ (existing.querySelector('.artifact-content'));
|
|
1291
|
-
if (contentEl && chartState?.height) {
|
|
1292
|
-
contentEl.style.height = `${chartState.height}px`;
|
|
1293
|
-
contentEl.style.minHeight = `${chartState.height}px`;
|
|
1294
|
-
contentEl.style.overflow = 'auto';
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
const timeEl = existing.querySelector('.artifact-time');
|
|
1298
|
-
if (timeEl) {
|
|
1299
|
-
timeEl.textContent = formatTimeAgo(new Date(artifact.modifiedAt));
|
|
1300
|
-
}
|
|
1301
|
-
orderedCards.push(existing);
|
|
1302
|
-
continue;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
const template = document.createElement('template');
|
|
1306
|
-
template.innerHTML = buildCardHtml(artifact).trim();
|
|
1307
|
-
const card = /** @type {HTMLElement | null} */ (template.content.firstElementChild);
|
|
1308
|
-
if (!card) {
|
|
1309
|
-
continue;
|
|
1310
|
-
}
|
|
1311
|
-
card.dataset.cardSignature = signature;
|
|
1312
|
-
const htmlHost = /** @type {HTMLElement | null} */ (card.querySelector('.html-preview'));
|
|
1313
|
-
if (htmlHost) {
|
|
1314
|
-
const reusable = forceHtmlReload ? undefined : reusableHtmlPreviews.get(`${path}::${modifiedAt}`);
|
|
1315
|
-
if (reusable) {
|
|
1316
|
-
htmlHost.classList.add('ready');
|
|
1317
|
-
htmlHost.innerHTML = '';
|
|
1318
|
-
htmlHost.appendChild(reusable);
|
|
1319
|
-
} else if (artifact.format === 'html') {
|
|
1320
|
-
htmlArtifactsNeedingFetch.push(artifact);
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
if (card.querySelector('.markdown-preview')) {
|
|
1324
|
-
markdownArtifactsNeedingFetch.push(artifact);
|
|
1325
|
-
}
|
|
1326
|
-
attachArtifactCardHandlers(card);
|
|
1327
|
-
if (existing) {
|
|
1328
|
-
existing.replaceWith(card);
|
|
1329
|
-
}
|
|
1330
|
-
orderedCards.push(card);
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
// Cards whose artifacts disappeared.
|
|
1334
|
-
existingCards.forEach((card) => card.remove());
|
|
1335
|
-
|
|
1336
|
-
// Minimal-move reorder: re-inserting a node reloads its iframe, so only move cards that
|
|
1337
|
-
// are actually out of position.
|
|
1338
|
-
let cursor = container.firstElementChild;
|
|
1339
|
-
for (const card of orderedCards) {
|
|
1340
|
-
if (card === cursor) {
|
|
1341
|
-
cursor = cursor.nextElementSibling;
|
|
1342
|
-
continue;
|
|
1343
|
-
}
|
|
1344
|
-
container.insertBefore(card, cursor);
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
requestHtmlPreviewContents(htmlArtifactsNeedingFetch);
|
|
1348
|
-
requestMarkdownPreviewContents(markdownArtifactsNeedingFetch);
|
|
1349
|
-
|
|
1350
|
-
// Markdown previews are loaded via host message passing (artifactContent)
|
|
1351
|
-
// to avoid fetch restrictions for local report files.
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
/**
|
|
1355
|
-
* Per-card render signature: every input that affects a card's DOM except expanded/height,
|
|
1356
|
-
* which renderGallery applies in place so toggling them never rebuilds the card.
|
|
1357
|
-
* @param {object} artifact
|
|
1358
|
-
* @returns {string}
|
|
1359
|
-
*/
|
|
1360
|
-
function computeCardRenderSignature(artifact) {
|
|
1361
|
-
const isVisual = artifact.type === 'chart' || artifact.type === 'image';
|
|
1362
|
-
const chartState = isVisual ? artifact._panel : undefined;
|
|
1363
|
-
const manifestEntry = state.manifest?.artifacts?.find(e => e.filename === artifact.filename);
|
|
1364
|
-
return [
|
|
1365
|
-
String(artifact.localPath || ''),
|
|
1366
|
-
String(artifact.filename || ''),
|
|
1367
|
-
String(artifact.modifiedAt || ''),
|
|
1368
|
-
String(artifact.size || ''),
|
|
1369
|
-
String(artifact.type || ''),
|
|
1370
|
-
String(artifact.format || ''),
|
|
1371
|
-
String(artifact.generator || ''),
|
|
1372
|
-
String(manifestEntry?.title || ''),
|
|
1373
|
-
String(manifestEntry?.source || ''),
|
|
1374
|
-
chartState?.hidden === true ? '1' : '0',
|
|
1375
|
-
Number.isFinite(chartState?.order) ? String(chartState.order) : '',
|
|
1376
|
-
].join('|');
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
/**
|
|
1380
|
-
* Chart/image ordering keys derived from current DOM order — computed at click time so
|
|
1381
|
-
* handlers on long-lived cards never act on a stale snapshot.
|
|
1382
|
-
* @returns {string[]}
|
|
1383
|
-
*/
|
|
1384
|
-
function getInteractiveChartKeysFromDom() {
|
|
1385
|
-
const container = document.getElementById('gallery-content');
|
|
1386
|
-
if (!container) {
|
|
1387
|
-
return [];
|
|
1388
|
-
}
|
|
1389
|
-
return Array.from(container.querySelectorAll('.artifact-card'))
|
|
1390
|
-
.filter((cardEl) => {
|
|
1391
|
-
const card = /** @type {HTMLElement} */ (cardEl);
|
|
1392
|
-
return card.dataset.type === 'chart' || card.dataset.type === 'image';
|
|
1393
|
-
})
|
|
1394
|
-
.map((cardEl) => normalizeFilename(String(/** @type {HTMLElement} */ (cardEl).dataset.filename || '')))
|
|
1395
|
-
.filter(Boolean);
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
/**
|
|
1399
|
-
* Wire interactive behaviors for one gallery card (open/delete, layout buttons, expand on
|
|
1400
|
-
* click, resize handle). Called once per created card; reused cards keep their listeners.
|
|
1401
|
-
* @param {HTMLElement} card
|
|
1402
|
-
*/
|
|
1403
|
-
function attachArtifactCardHandlers(card) {
|
|
1404
|
-
const path = card.dataset.path;
|
|
1405
|
-
const filename = card.dataset.filename;
|
|
1406
|
-
const isChart = card.dataset.type === 'chart';
|
|
1407
|
-
const isVisual = card.dataset.type === 'chart' || card.dataset.type === 'image';
|
|
1408
|
-
|
|
1409
|
-
card.querySelector('.open-btn')?.addEventListener('click', (e) => {
|
|
1410
|
-
e.stopPropagation();
|
|
1411
|
-
panelApi.postMessage({ type: 'openArtifact', path });
|
|
1412
|
-
});
|
|
1413
|
-
|
|
1414
|
-
card.querySelector('.delete-btn')?.addEventListener('click', (e) => {
|
|
1415
|
-
e.stopPropagation();
|
|
1416
|
-
panelApi.postMessage({ type: 'deleteArtifact', path });
|
|
1417
|
-
});
|
|
1418
|
-
|
|
1419
|
-
if (isChart && filename) {
|
|
1420
|
-
card.querySelector('.move-up-btn')?.addEventListener('click', (e) => {
|
|
1421
|
-
e.stopPropagation();
|
|
1422
|
-
moveChartInPanelState(filename, 'up', getInteractiveChartKeysFromDom());
|
|
1423
|
-
renderGallery(state.artifacts);
|
|
1424
|
-
});
|
|
1425
|
-
|
|
1426
|
-
card.querySelector('.move-down-btn')?.addEventListener('click', (e) => {
|
|
1427
|
-
e.stopPropagation();
|
|
1428
|
-
moveChartInPanelState(filename, 'down', getInteractiveChartKeysFromDom());
|
|
1429
|
-
renderGallery(state.artifacts);
|
|
1430
|
-
});
|
|
1431
|
-
|
|
1432
|
-
card.querySelector('.toggle-enabled-btn')?.addEventListener('click', (e) => {
|
|
1433
|
-
e.stopPropagation();
|
|
1434
|
-
toggleChartHiddenInPanelState(filename);
|
|
1435
|
-
renderGallery(state.artifacts);
|
|
1436
|
-
});
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
// Click on card to expand/collapse
|
|
1440
|
-
card.addEventListener('click', (event) => {
|
|
1441
|
-
const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null);
|
|
1442
|
-
if (target?.closest('button,.resize-handle')) {
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
const nextExpanded = !card.classList.contains('expanded');
|
|
1446
|
-
card.classList.toggle('expanded', nextExpanded);
|
|
1447
|
-
if (isVisual && filename) {
|
|
1448
|
-
setChartExpanded(filename, nextExpanded);
|
|
1449
|
-
}
|
|
1450
|
-
});
|
|
1451
|
-
|
|
1452
|
-
if (filename) {
|
|
1453
|
-
attachResizeHandle(card, filename);
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
/**
|
|
1458
|
-
* Build a compact signature for artifact catalog identity.
|
|
1459
|
-
* Used to avoid expensive no-op rerenders on duplicate updates.
|
|
1460
|
-
* @param {Array<object>} artifacts
|
|
1461
|
-
* @returns {string}
|
|
1462
|
-
*/
|
|
1463
|
-
function getArtifactCatalogSignature(artifacts) {
|
|
1464
|
-
return artifacts
|
|
1465
|
-
.map((artifact) => [
|
|
1466
|
-
String(artifact.localPath || ''),
|
|
1467
|
-
String(artifact.modifiedAt || ''),
|
|
1468
|
-
String(artifact.size || ''),
|
|
1469
|
-
String(artifact.format || ''),
|
|
1470
|
-
String(artifact.type || ''),
|
|
1471
|
-
].join('|'))
|
|
1472
|
-
.sort()
|
|
1473
|
-
.join('\n');
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
/** Signature ignoring export files — chart HTML identity for preserveFleetIframe fast path. */
|
|
1477
|
-
function getArtifactCatalogSignatureExcludingExports(artifacts) {
|
|
1478
|
-
return getArtifactCatalogSignature(artifacts.filter((artifact) => artifact.type !== 'export'));
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* Add nonce to inline script tags so they can run in srcdoc.
|
|
1483
|
-
* @param {string} html
|
|
1484
|
-
* @param {string} nonce
|
|
1485
|
-
* @returns {string}
|
|
1486
|
-
*/
|
|
1487
|
-
function injectNonceIntoInlineScripts(html, nonce) {
|
|
1488
|
-
if (!nonce) {
|
|
1489
|
-
return html;
|
|
1490
|
-
}
|
|
1491
|
-
return html.replace(/<script(?![^>]*\bnonce=)([^>]*)>/gi, `<script nonce="${nonce}"$1>`);
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
/**
|
|
1495
|
-
* Inject a keyboard shortcut bridge for embedded iframe widgets so common
|
|
1496
|
-
* shortcuts (Ctrl/Cmd+A/C/X/V) work reliably in webview sandboxes.
|
|
1497
|
-
* @param {string} html
|
|
1498
|
-
* @param {string} nonce
|
|
1499
|
-
* @returns {string}
|
|
1500
|
-
*/
|
|
1501
|
-
function injectIframeKeyboardShortcutBridge(html, nonce) {
|
|
1502
|
-
const bridge = `<script nonce="${nonce}">(function(){
|
|
52
|
+
`},x=new Map;Array.from(a.children).forEach(i=>{const d=i,b=d.dataset.path||"";if(!(d.classList.contains("artifact-card")&&!d.classList.contains("fleet-dashboard-full")&&!d.classList.contains("deleting")&&b&&!x.has(b))){d.remove();return}x.set(b,d)});const k=[],H=[],M=[];for(const i of c){const d=String(i.localPath||""),b=String(i.modifiedAt||""),g=i.type==="chart"||i.type==="image",m=g?i._panel:void 0,I=computeCardRenderSignature(i),E=n&&i.format==="html",u=x.get(d);if(x.delete(d),u&&u.dataset.cardSignature===I&&!E){if(g){u.classList.toggle("expanded",m?.expanded===!0);const C=u.querySelector(".artifact-content");C&&m?.height&&(C.style.height=`${m.height}px`,C.style.minHeight=`${m.height}px`,C.style.overflow="auto")}const h=u.querySelector(".artifact-time");h&&(h.textContent=formatTimeAgo(new Date(i.modifiedAt))),M.push(u);continue}const A=document.createElement("template");A.innerHTML=S(i).trim();const w=A.content.firstElementChild;if(!w)continue;w.dataset.cardSignature=I;const y=w.querySelector(".html-preview");if(y){const h=E?void 0:r.get(`${d}::${b}`);h?(y.classList.add("ready"),y.innerHTML="",y.appendChild(h)):i.format==="html"&&k.push(i)}w.querySelector(".markdown-preview")&&H.push(i),attachArtifactCardHandlers(w),u&&u.replaceWith(w),M.push(w)}x.forEach(i=>i.remove());let T=a.firstElementChild;for(const i of M){if(i===T){T=T.nextElementSibling;continue}a.insertBefore(i,T)}requestHtmlPreviewContents(k),requestMarkdownPreviewContents(H)}function computeCardRenderSignature(e){const n=e.type==="chart"||e.type==="image"?e._panel:void 0,a=state.manifest?.artifacts?.find(r=>r.filename===e.filename);return[String(e.localPath||""),String(e.filename||""),String(e.modifiedAt||""),String(e.size||""),String(e.type||""),String(e.format||""),String(e.generator||""),String(a?.title||""),String(a?.source||""),n?.hidden===!0?"1":"0",Number.isFinite(n?.order)?String(n.order):""].join("|")}function getInteractiveChartKeysFromDom(){const e=document.getElementById("gallery-content");return e?Array.from(e.querySelectorAll(".artifact-card")).filter(t=>{const n=t;return n.dataset.type==="chart"||n.dataset.type==="image"}).map(t=>normalizeFilename(String(t.dataset.filename||""))).filter(Boolean):[]}function attachArtifactCardHandlers(e){const t=e.dataset.path,n=e.dataset.filename,a=e.dataset.type==="chart",r=e.dataset.type==="chart"||e.dataset.type==="image";e.querySelector(".open-btn")?.addEventListener("click",s=>{s.stopPropagation(),panelApi.postMessage({type:"openArtifact",path:t})}),e.querySelector(".delete-btn")?.addEventListener("click",s=>{s.stopPropagation(),panelApi.postMessage({type:"deleteArtifact",path:t})}),a&&n&&(e.querySelector(".move-up-btn")?.addEventListener("click",s=>{s.stopPropagation(),moveChartInPanelState(n,"up",getInteractiveChartKeysFromDom()),renderGallery(state.artifacts)}),e.querySelector(".move-down-btn")?.addEventListener("click",s=>{s.stopPropagation(),moveChartInPanelState(n,"down",getInteractiveChartKeysFromDom()),renderGallery(state.artifacts)}),e.querySelector(".toggle-enabled-btn")?.addEventListener("click",s=>{s.stopPropagation(),toggleChartHiddenInPanelState(n),renderGallery(state.artifacts)})),e.addEventListener("click",s=>{if((s.target instanceof HTMLElement?s.target:null)?.closest("button,.resize-handle"))return;const f=!e.classList.contains("expanded");e.classList.toggle("expanded",f),r&&n&&setChartExpanded(n,f)}),n&&attachResizeHandle(e,n)}function getArtifactCatalogSignature(e){return e.map(t=>[String(t.localPath||""),String(t.modifiedAt||""),String(t.size||""),String(t.format||""),String(t.type||"")].join("|")).sort().join(`
|
|
53
|
+
`)}function getArtifactCatalogSignatureExcludingExports(e){return getArtifactCatalogSignature(e.filter(t=>t.type!=="export"))}function injectNonceIntoInlineScripts(e,t){return t?e.replace(/<script(?![^>]*\bnonce=)([^>]*)>/gi,`<script nonce="${t}"$1>`):e}function injectIframeKeyboardShortcutBridge(e,t){const n=`<script nonce="${t}">(function(){
|
|
1503
54
|
try {
|
|
1504
55
|
var pending = new Map();
|
|
1505
56
|
function requestClipboardText() {
|
|
@@ -1668,839 +219,4 @@ function injectIframeKeyboardShortcutBridge(html, nonce) {
|
|
|
1668
219
|
} catch (err) {
|
|
1669
220
|
// no-op
|
|
1670
221
|
}
|
|
1671
|
-
})();</script>`;
|
|
1672
|
-
if (/<\/body>/i.test(html)) {
|
|
1673
|
-
return html.replace(/<\/body>/i, `${bridge}</body>`);
|
|
1674
|
-
}
|
|
1675
|
-
return `${html}${bridge}`;
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
/**
|
|
1679
|
-
* Ask host to read HTML artifact contents by local path.
|
|
1680
|
-
* This avoids webview URL fetch/DNS issues for nested iframe previews.
|
|
1681
|
-
* @param {Array<object>} artifacts
|
|
1682
|
-
*/
|
|
1683
|
-
function requestHtmlPreviewContents(artifacts) {
|
|
1684
|
-
for (const artifact of artifacts) {
|
|
1685
|
-
if (artifact.format !== 'html' || !artifact.localPath) {
|
|
1686
|
-
continue;
|
|
1687
|
-
}
|
|
1688
|
-
panelApi.postMessage({
|
|
1689
|
-
type: 'requestArtifactContent',
|
|
1690
|
-
path: artifact.localPath,
|
|
1691
|
-
format: 'html',
|
|
1692
|
-
});
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
/**
|
|
1697
|
-
* Ask host to read markdown artifact contents by local path.
|
|
1698
|
-
* @param {Array<object>} artifacts
|
|
1699
|
-
*/
|
|
1700
|
-
function requestMarkdownPreviewContents(artifacts) {
|
|
1701
|
-
for (const artifact of artifacts) {
|
|
1702
|
-
if (artifact.format !== 'md' || !artifact.localPath) {
|
|
1703
|
-
continue;
|
|
1704
|
-
}
|
|
1705
|
-
panelApi.postMessage({
|
|
1706
|
-
type: 'requestArtifactContent',
|
|
1707
|
-
path: artifact.localPath,
|
|
1708
|
-
format: 'md',
|
|
1709
|
-
});
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
/**
|
|
1714
|
-
* Render HTML preview for one artifact path from host-provided content.
|
|
1715
|
-
* @param {string} path
|
|
1716
|
-
* @param {string | undefined} content
|
|
1717
|
-
* @param {string | undefined} error
|
|
1718
|
-
*/
|
|
1719
|
-
function renderHtmlPreview(path, content, error) {
|
|
1720
|
-
const card = Array.from(document.querySelectorAll('.artifact-card')).find((cardEl) => {
|
|
1721
|
-
const element = /** @type {HTMLElement} */ (cardEl);
|
|
1722
|
-
return element.dataset.path === path;
|
|
1723
|
-
});
|
|
1724
|
-
const host = /** @type {HTMLElement | null} */ (card?.querySelector('.html-preview'));
|
|
1725
|
-
if (!host) {
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
if (error || !content) {
|
|
1730
|
-
const reason = error || 'No preview content available.';
|
|
1731
|
-
host.innerHTML = `<div class="html-preview-fallback">Preview unavailable (${escapeHtml(reason)}). Use <strong>Open</strong> to inspect the artifact.</div>`;
|
|
1732
|
-
return;
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
const scriptNonce = document.querySelector('script[nonce]')?.getAttribute('nonce') || '';
|
|
1736
|
-
const iframe = document.createElement('iframe');
|
|
1737
|
-
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
1738
|
-
iframe.setAttribute('allow', 'clipboard-read; clipboard-write');
|
|
1739
|
-
iframe.setAttribute('loading', 'lazy');
|
|
1740
|
-
iframe.tabIndex = 0;
|
|
1741
|
-
const contentWithNonce = injectNonceIntoInlineScripts(content, scriptNonce);
|
|
1742
|
-
iframe.srcdoc = injectIframeKeyboardShortcutBridge(contentWithNonce, scriptNonce);
|
|
1743
|
-
iframe.addEventListener('load', () => {
|
|
1744
|
-
host.classList.add('ready');
|
|
1745
|
-
const parentCard = host.closest('.artifact-card');
|
|
1746
|
-
if (parentCard instanceof HTMLElement && parentCard.classList.contains('fleet-dashboard-full')) {
|
|
1747
|
-
autoFitFleetCardHeight(parentCard);
|
|
1748
|
-
}
|
|
1749
|
-
});
|
|
1750
|
-
host.innerHTML = '';
|
|
1751
|
-
host.appendChild(iframe);
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
// -----------------------------------------------------------------------------
|
|
1755
|
-
// Quick Prompts & Ask AI
|
|
1756
|
-
// -----------------------------------------------------------------------------
|
|
1757
|
-
|
|
1758
|
-
function initQuickPrompts() {
|
|
1759
|
-
// Quick prompt buttons in empty state
|
|
1760
|
-
document.querySelectorAll('.quick-prompt').forEach(buttonEl => {
|
|
1761
|
-
const btn = /** @type {HTMLElement} */ (buttonEl);
|
|
1762
|
-
btn.addEventListener('click', () => {
|
|
1763
|
-
const prompt = btn.dataset.prompt;
|
|
1764
|
-
if (prompt) {
|
|
1765
|
-
panelApi.postMessage({ type: 'openChatWithPrompt', prompt });
|
|
1766
|
-
}
|
|
1767
|
-
});
|
|
1768
|
-
});
|
|
1769
|
-
|
|
1770
|
-
// Main "Ask AI" button
|
|
1771
|
-
document.getElementById('ask-ai-btn')?.addEventListener('click', () => {
|
|
1772
|
-
panelApi.postMessage({ type: 'openChat' });
|
|
1773
|
-
});
|
|
1774
|
-
|
|
1775
|
-
// Refresh button
|
|
1776
|
-
document.getElementById('refresh-charts-btn')?.addEventListener('click', () => {
|
|
1777
|
-
refreshCurrentView();
|
|
1778
|
-
});
|
|
1779
|
-
|
|
1780
|
-
// Remove legacy Expand/Shrink buttons if a user-customized panel.html still contains them.
|
|
1781
|
-
document.getElementById('expand-sidebar-btn')?.remove();
|
|
1782
|
-
document.getElementById('shrink-sidebar-btn')?.remove();
|
|
1783
|
-
|
|
1784
|
-
document.getElementById('summary-toggle-btn')?.addEventListener('click', (e) => {
|
|
1785
|
-
e.stopPropagation();
|
|
1786
|
-
toggleSummarySection();
|
|
1787
|
-
});
|
|
1788
|
-
applySummarySectionVisibility();
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
// -----------------------------------------------------------------------------
|
|
1792
|
-
// Filters
|
|
1793
|
-
// -----------------------------------------------------------------------------
|
|
1794
|
-
|
|
1795
|
-
function applyFiltersToControls() {
|
|
1796
|
-
const agentSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('agent-filter-select'));
|
|
1797
|
-
if (agentSelect) {
|
|
1798
|
-
agentSelect.innerHTML = '<option value="">All agents</option>';
|
|
1799
|
-
for (const agentId of state.agentIds) {
|
|
1800
|
-
const option = document.createElement('option');
|
|
1801
|
-
option.value = agentId;
|
|
1802
|
-
option.textContent = agentId;
|
|
1803
|
-
agentSelect.appendChild(option);
|
|
1804
|
-
}
|
|
1805
|
-
agentSelect.value = state.agentId || '';
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
function postFilterUpdate() {
|
|
1810
|
-
panelApi.postMessage({
|
|
1811
|
-
type: 'updateFilters',
|
|
1812
|
-
agentId: state.agentId || '',
|
|
1813
|
-
});
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
function initFilters() {
|
|
1817
|
-
const agentSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('agent-filter-select'));
|
|
1818
|
-
agentSelect?.addEventListener('change', () => {
|
|
1819
|
-
state.agentId = agentSelect.value || '';
|
|
1820
|
-
postFilterUpdate();
|
|
1821
|
-
});
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
// -----------------------------------------------------------------------------
|
|
1825
|
-
// State Actions
|
|
1826
|
-
// -----------------------------------------------------------------------------
|
|
1827
|
-
|
|
1828
|
-
function initStateActions() {
|
|
1829
|
-
// Cancel generation
|
|
1830
|
-
document.getElementById('cancel-generate-btn')?.addEventListener('click', () => {
|
|
1831
|
-
panelApi.postMessage({ type: 'cancelGeneration' });
|
|
1832
|
-
});
|
|
1833
|
-
|
|
1834
|
-
// Retry generation
|
|
1835
|
-
document.getElementById('retry-generate-btn')?.addEventListener('click', () => {
|
|
1836
|
-
panelApi.postMessage({ type: 'retryGeneration' });
|
|
1837
|
-
});
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
// -----------------------------------------------------------------------------
|
|
1841
|
-
// Toolbar Menu
|
|
1842
|
-
// -----------------------------------------------------------------------------
|
|
1843
|
-
|
|
1844
|
-
function initToolbarMenu() {
|
|
1845
|
-
const menuBtn = document.getElementById('toolbar-menu-btn');
|
|
1846
|
-
const dropdown = document.getElementById('toolbar-menu-dropdown');
|
|
1847
|
-
|
|
1848
|
-
if (!menuBtn || !dropdown) {
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
/**
|
|
1853
|
-
* Toggle dropdown visibility.
|
|
1854
|
-
* @param {boolean} [forceOpen]
|
|
1855
|
-
*/
|
|
1856
|
-
function toggleMenu(forceOpen) {
|
|
1857
|
-
const isOpen = forceOpen ?? !dropdown.classList.contains('open');
|
|
1858
|
-
dropdown.classList.toggle('open', isOpen);
|
|
1859
|
-
dropdown.setAttribute('aria-hidden', String(!isOpen));
|
|
1860
|
-
menuBtn.setAttribute('aria-expanded', String(isOpen));
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
// Toggle on button click
|
|
1864
|
-
menuBtn.addEventListener('click', (e) => {
|
|
1865
|
-
e.stopPropagation();
|
|
1866
|
-
toggleMenu();
|
|
1867
|
-
});
|
|
1868
|
-
|
|
1869
|
-
// Close when clicking outside
|
|
1870
|
-
document.addEventListener('click', (e) => {
|
|
1871
|
-
if (!dropdown.contains(/** @type {Node} */(e.target)) && e.target !== menuBtn) {
|
|
1872
|
-
toggleMenu(false);
|
|
1873
|
-
}
|
|
1874
|
-
});
|
|
1875
|
-
|
|
1876
|
-
// Close on Escape
|
|
1877
|
-
document.addEventListener('keydown', (e) => {
|
|
1878
|
-
if (e.key === 'Escape' && dropdown.classList.contains('open')) {
|
|
1879
|
-
toggleMenu(false);
|
|
1880
|
-
menuBtn.focus();
|
|
1881
|
-
}
|
|
1882
|
-
});
|
|
1883
|
-
|
|
1884
|
-
// Handle menu item clicks
|
|
1885
|
-
dropdown.querySelectorAll('.dropdown-item[data-action]').forEach((itemEl) => {
|
|
1886
|
-
const item = /** @type {HTMLElement} */ (itemEl);
|
|
1887
|
-
item.addEventListener('click', () => {
|
|
1888
|
-
const action = item.dataset.action;
|
|
1889
|
-
toggleMenu(false);
|
|
1890
|
-
const activeView = getActiveView();
|
|
1891
|
-
|
|
1892
|
-
switch (action) {
|
|
1893
|
-
case 'new-view':
|
|
1894
|
-
promptCreateView();
|
|
1895
|
-
break;
|
|
1896
|
-
|
|
1897
|
-
case 'duplicate-view':
|
|
1898
|
-
if (activeView?.id) {
|
|
1899
|
-
panelApi.postMessage({ type: 'duplicateView', viewId: activeView.id });
|
|
1900
|
-
}
|
|
1901
|
-
break;
|
|
1902
|
-
|
|
1903
|
-
case 'rename-view': {
|
|
1904
|
-
if (!activeView || activeView.system) {
|
|
1905
|
-
break;
|
|
1906
|
-
}
|
|
1907
|
-
panelApi.postMessage({ type: 'requestRenameView', viewId: activeView.id });
|
|
1908
|
-
break;
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
case 'delete-view': {
|
|
1912
|
-
if (!activeView || activeView.system) {
|
|
1913
|
-
break;
|
|
1914
|
-
}
|
|
1915
|
-
panelApi.postMessage({ type: 'requestDeleteView', viewId: activeView.id });
|
|
1916
|
-
break;
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
case 'edit-view-scripts':
|
|
1920
|
-
panelApi.postMessage({ type: 'editViewScripts', viewId: activeView?.id });
|
|
1921
|
-
break;
|
|
1922
|
-
|
|
1923
|
-
case 'share-scripts-only':
|
|
1924
|
-
onShareScriptsOnlyClick();
|
|
1925
|
-
break;
|
|
1926
|
-
|
|
1927
|
-
case 'refresh-all-views':
|
|
1928
|
-
panelApi.postMessage({ type: 'refreshAllViews' });
|
|
1929
|
-
break;
|
|
1930
|
-
|
|
1931
|
-
case 'reset-home':
|
|
1932
|
-
if (confirm('Reset all charts and scripts in your home analytics folder? This will delete generated charts and user scripts, then regenerate defaults.')) {
|
|
1933
|
-
panelApi.postMessage({ type: 'resetChartsHome' });
|
|
1934
|
-
}
|
|
1935
|
-
break;
|
|
1936
|
-
|
|
1937
|
-
case 'reset-workspace':
|
|
1938
|
-
if (confirm('Reset all charts and scripts in this workspace? This will delete generated charts and user scripts for the current workspace, then regenerate defaults.')) {
|
|
1939
|
-
panelApi.postMessage({ type: 'resetChartsWorkspace' });
|
|
1940
|
-
}
|
|
1941
|
-
break;
|
|
1942
|
-
|
|
1943
|
-
case 'reenable-charts':
|
|
1944
|
-
panelApi.postMessage({ type: 'reenableAllCharts' });
|
|
1945
|
-
break;
|
|
1946
|
-
}
|
|
1947
|
-
});
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
/**
|
|
1952
|
-
* Push a view export snapshot into embedded dashboard iframes (no iframe reload).
|
|
1953
|
-
* Only when the active view has preserveFleetIframe (host already gates pushes).
|
|
1954
|
-
* @param {{ payload?: object, meta?: object }} message
|
|
1955
|
-
*/
|
|
1956
|
-
function postViewExportSnapshotToDashboardIframes(message) {
|
|
1957
|
-
const payload = message.payload;
|
|
1958
|
-
const meta = message.meta;
|
|
1959
|
-
document.querySelectorAll('.html-preview iframe').forEach((frameEl) => {
|
|
1960
|
-
const iframe = /** @type {HTMLIFrameElement} */ (frameEl);
|
|
1961
|
-
try {
|
|
1962
|
-
iframe.contentWindow?.postMessage({ type: VIEW_EXPORT_SNAPSHOT, payload, meta }, '*');
|
|
1963
|
-
// Legacy widgets (e.g. live-fleet-2.html) still listen for liveFleetSnapshot.
|
|
1964
|
-
iframe.contentWindow?.postMessage({ type: LEGACY_VIEW_EXPORT_SNAPSHOT, payload, meta }, '*');
|
|
1965
|
-
} catch {
|
|
1966
|
-
// Cross-origin or unloaded iframe — ignore.
|
|
1967
|
-
}
|
|
1968
|
-
});
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
/**
|
|
1972
|
-
* Bridge postMessage events from embedded HTML widgets.
|
|
1973
|
-
* Allows widgets to trigger host actions (e.g. copy session id).
|
|
1974
|
-
*/
|
|
1975
|
-
function initEmbeddedWidgetBridge() {
|
|
1976
|
-
window.addEventListener('message', (event) => {
|
|
1977
|
-
const data = event.data;
|
|
1978
|
-
if (!data || typeof data !== 'object') {
|
|
1979
|
-
return;
|
|
1980
|
-
}
|
|
1981
|
-
if (data.source !== 'agentide-wow-widget') {
|
|
1982
|
-
return;
|
|
1983
|
-
}
|
|
1984
|
-
if (data.type === 'copySessionId' && typeof data.sessionId === 'string') {
|
|
1985
|
-
const sessionId = data.sessionId.trim();
|
|
1986
|
-
if (sessionId) {
|
|
1987
|
-
panelApi.postMessage({ type: 'copySessionId', sessionId });
|
|
1988
|
-
}
|
|
1989
|
-
return;
|
|
1990
|
-
}
|
|
1991
|
-
if (data.type === 'requestClipboardText' && typeof data.requestId === 'string') {
|
|
1992
|
-
const requestId = data.requestId.trim();
|
|
1993
|
-
if (requestId) {
|
|
1994
|
-
panelApi.postMessage({ type: 'requestClipboardText', requestId });
|
|
1995
|
-
}
|
|
1996
|
-
return;
|
|
1997
|
-
}
|
|
1998
|
-
if (data.type === 'writeClipboardText' && typeof data.text === 'string') {
|
|
1999
|
-
panelApi.postMessage({ type: 'writeClipboardText', text: data.text });
|
|
2000
|
-
return;
|
|
2001
|
-
}
|
|
2002
|
-
if (data.type === 'openArtifact' && typeof data.path === 'string') {
|
|
2003
|
-
const artifactPath = data.path.trim();
|
|
2004
|
-
if (artifactPath) {
|
|
2005
|
-
panelApi.postMessage({ type: 'openArtifact', path: artifactPath });
|
|
2006
|
-
}
|
|
2007
|
-
return;
|
|
2008
|
-
}
|
|
2009
|
-
if (data.type === 'openChatWithPrompt' && typeof data.prompt === 'string') {
|
|
2010
|
-
const prompt = data.prompt.trim();
|
|
2011
|
-
if (prompt) {
|
|
2012
|
-
panelApi.postMessage({
|
|
2013
|
-
type: 'openChatWithPrompt',
|
|
2014
|
-
prompt: prompt.slice(0, 12_000),
|
|
2015
|
-
});
|
|
2016
|
-
}
|
|
2017
|
-
return;
|
|
2018
|
-
}
|
|
2019
|
-
if (data.type === 'disconnectFleetChannel' && typeof data.sessionId === 'string') {
|
|
2020
|
-
const sessionId = data.sessionId.trim();
|
|
2021
|
-
if (sessionId) {
|
|
2022
|
-
panelApi.postMessage({
|
|
2023
|
-
type: 'disconnectFleetChannel',
|
|
2024
|
-
sessionId,
|
|
2025
|
-
channelType: typeof data.channelType === 'string' ? data.channelType : '',
|
|
2026
|
-
channelTarget: typeof data.channelTarget === 'string' ? data.channelTarget : '',
|
|
2027
|
-
});
|
|
2028
|
-
}
|
|
2029
|
-
return;
|
|
2030
|
-
}
|
|
2031
|
-
if (data.type === 'updateFleetCardTitle' && typeof data.sessionId === 'string' && typeof data.cardTitle === 'string') {
|
|
2032
|
-
const sessionId = data.sessionId.trim();
|
|
2033
|
-
const sourceId = typeof data.sourceId === 'string' ? data.sourceId.trim() : 'local';
|
|
2034
|
-
if (sessionId) {
|
|
2035
|
-
panelApi.postMessage({
|
|
2036
|
-
type: 'updateFleetCardTitle',
|
|
2037
|
-
sourceId,
|
|
2038
|
-
sessionId,
|
|
2039
|
-
cardTitle: data.cardTitle,
|
|
2040
|
-
});
|
|
2041
|
-
}
|
|
2042
|
-
return;
|
|
2043
|
-
}
|
|
2044
|
-
if (data.type === 'openSpotlightForSession' && typeof data.sessionId === 'string') {
|
|
2045
|
-
const sessionId = data.sessionId.trim();
|
|
2046
|
-
if (sessionId) {
|
|
2047
|
-
panelApi.postMessage({
|
|
2048
|
-
type: 'openSpotlightForSession',
|
|
2049
|
-
sessionId,
|
|
2050
|
-
channelType: typeof data.channelType === 'string' ? data.channelType : '',
|
|
2051
|
-
channelTarget: typeof data.channelTarget === 'string' ? data.channelTarget : '',
|
|
2052
|
-
model: typeof data.model === 'string' ? data.model : '',
|
|
2053
|
-
engine: typeof data.engine === 'string' ? data.engine : '',
|
|
2054
|
-
agentId: typeof data.agentId === 'string' ? data.agentId : '',
|
|
2055
|
-
});
|
|
2056
|
-
}
|
|
2057
|
-
return;
|
|
2058
|
-
}
|
|
2059
|
-
if (data.type === 'refreshView') {
|
|
2060
|
-
panelApi.postMessage({ type: 'refreshView' });
|
|
2061
|
-
return;
|
|
2062
|
-
}
|
|
2063
|
-
if (data.type === 'refreshFleetWidget') {
|
|
2064
|
-
panelApi.postMessage({ type: 'refreshFleetWidget' });
|
|
2065
|
-
return;
|
|
2066
|
-
}
|
|
2067
|
-
if (data.type === 'refreshWidget') {
|
|
2068
|
-
const script = typeof data.script === 'string' ? data.script.trim() : '';
|
|
2069
|
-
const scripts = Array.isArray(data.scripts)
|
|
2070
|
-
? data.scripts.filter((s) => typeof s === 'string').map((s) => s.trim()).filter(Boolean)
|
|
2071
|
-
: [];
|
|
2072
|
-
if (!script && scripts.length === 0) {
|
|
2073
|
-
return;
|
|
2074
|
-
}
|
|
2075
|
-
panelApi.postMessage({
|
|
2076
|
-
type: 'refreshWidget',
|
|
2077
|
-
script: script || undefined,
|
|
2078
|
-
scripts: scripts.length > 0 ? scripts : undefined,
|
|
2079
|
-
});
|
|
2080
|
-
return;
|
|
2081
|
-
}
|
|
2082
|
-
if (data.type === REQUEST_VIEW_EXPORT_SNAPSHOT || data.type === LEGACY_REQUEST_LIVE_FLEET_SNAPSHOT) {
|
|
2083
|
-
panelApi.postMessage({ type: REQUEST_VIEW_EXPORT_SNAPSHOT });
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
if (data.type === 'openChat') {
|
|
2087
|
-
panelApi.postMessage({ type: 'openChat' });
|
|
2088
|
-
}
|
|
2089
|
-
});
|
|
2090
|
-
|
|
2091
|
-
// Fallback: forward openSpotlightForSession when message is from a frame that didn't set
|
|
2092
|
-
// source (e.g. fleet iframe in some contexts) so card click always opens chat
|
|
2093
|
-
window.addEventListener('message', (event) => {
|
|
2094
|
-
const data = event.data;
|
|
2095
|
-
if (!data || typeof data !== 'object' || data.type !== 'openSpotlightForSession') {
|
|
2096
|
-
return;
|
|
2097
|
-
}
|
|
2098
|
-
if (data.source === 'agentide-wow-widget') {
|
|
2099
|
-
return; // already handled above
|
|
2100
|
-
}
|
|
2101
|
-
if (typeof data.sessionId !== 'string') {
|
|
2102
|
-
return;
|
|
2103
|
-
}
|
|
2104
|
-
const sessionId = data.sessionId.trim();
|
|
2105
|
-
if (!sessionId) {
|
|
2106
|
-
return;
|
|
2107
|
-
}
|
|
2108
|
-
panelApi.postMessage({
|
|
2109
|
-
type: 'openSpotlightForSession',
|
|
2110
|
-
sessionId,
|
|
2111
|
-
channelType: typeof data.channelType === 'string' ? data.channelType : '',
|
|
2112
|
-
channelTarget: typeof data.channelTarget === 'string' ? data.channelTarget : '',
|
|
2113
|
-
model: typeof data.model === 'string' ? data.model : '',
|
|
2114
|
-
engine: typeof data.engine === 'string' ? data.engine : '',
|
|
2115
|
-
agentId: typeof data.agentId === 'string' ? data.agentId : '',
|
|
2116
|
-
});
|
|
2117
|
-
});
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
/**
|
|
2121
|
-
* Show generating state
|
|
2122
|
-
*/
|
|
2123
|
-
function showGeneratingState() {
|
|
2124
|
-
showGalleryState('generating');
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
/**
|
|
2128
|
-
* Show failed state with error message
|
|
2129
|
-
* @param {string} errorMessage
|
|
2130
|
-
*/
|
|
2131
|
-
function showFailedState(errorMessage) {
|
|
2132
|
-
const errorEl = document.getElementById('error-message');
|
|
2133
|
-
if (errorEl) {
|
|
2134
|
-
errorEl.textContent = errorMessage;
|
|
2135
|
-
}
|
|
2136
|
-
showGalleryState('failed');
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
/**
|
|
2140
|
-
* Show refresh hint
|
|
2141
|
-
*/
|
|
2142
|
-
function showRefreshHint() {
|
|
2143
|
-
const hint = document.getElementById('refresh-hint');
|
|
2144
|
-
if (hint) {
|
|
2145
|
-
hint.style.display = 'flex';
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
|
|
2149
|
-
/**
|
|
2150
|
-
* Hide refresh hint
|
|
2151
|
-
*/
|
|
2152
|
-
function hideRefreshHint() {
|
|
2153
|
-
const hint = document.getElementById('refresh-hint');
|
|
2154
|
-
if (hint) {
|
|
2155
|
-
hint.style.display = 'none';
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
/**
|
|
2160
|
-
* Show/hide per-chart refresh indicator.
|
|
2161
|
-
* @param {boolean} isRefreshing
|
|
2162
|
-
*/
|
|
2163
|
-
function setPerChartRefreshing(isRefreshing) {
|
|
2164
|
-
document.querySelectorAll('.artifact-card[data-type="chart"]').forEach(card => {
|
|
2165
|
-
card.classList.toggle('chart-refreshing', isRefreshing);
|
|
2166
|
-
let indicator = card.querySelector('.artifact-refresh-indicator');
|
|
2167
|
-
|
|
2168
|
-
if (isRefreshing) {
|
|
2169
|
-
if (!indicator) {
|
|
2170
|
-
indicator = document.createElement('div');
|
|
2171
|
-
indicator.className = 'artifact-refresh-indicator';
|
|
2172
|
-
indicator.textContent = 'Refreshing';
|
|
2173
|
-
card.appendChild(indicator);
|
|
2174
|
-
}
|
|
2175
|
-
} else if (indicator) {
|
|
2176
|
-
indicator.remove();
|
|
2177
|
-
}
|
|
2178
|
-
});
|
|
2179
|
-
}
|
|
2180
|
-
|
|
2181
|
-
/**
|
|
2182
|
-
* Toggle refresh button busy state.
|
|
2183
|
-
* @param {boolean} isRefreshing
|
|
2184
|
-
*/
|
|
2185
|
-
function setRefreshButtonState(isRefreshing) {
|
|
2186
|
-
const btn = document.getElementById('refresh-charts-btn');
|
|
2187
|
-
if (!btn) {
|
|
2188
|
-
return;
|
|
2189
|
-
}
|
|
2190
|
-
btn.classList.toggle('refreshing', isRefreshing);
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
// -----------------------------------------------------------------------------
|
|
2194
|
-
// Message Handling
|
|
2195
|
-
// -----------------------------------------------------------------------------
|
|
2196
|
-
|
|
2197
|
-
panelApi.onMessage(msg => {
|
|
2198
|
-
switch (msg.type) {
|
|
2199
|
-
case 'artifactsUpdated': {
|
|
2200
|
-
const nextSignature = getArtifactCatalogSignature(msg.artifacts);
|
|
2201
|
-
const nextActiveViewId = typeof msg.activeViewId === 'string' ? msg.activeViewId : state.activeViewId;
|
|
2202
|
-
const nextFleetRefreshVersion = typeof msg.fleetRefreshVersion === 'number'
|
|
2203
|
-
? Math.max(0, Math.floor(msg.fleetRefreshVersion))
|
|
2204
|
-
: state.fleetRefreshVersion;
|
|
2205
|
-
const nextGalleryIgnore = Array.isArray(msg.galleryIgnorePatterns)
|
|
2206
|
-
? msg.galleryIgnorePatterns.filter((p) => typeof p === 'string').map((p) => String(p).trim()).filter(Boolean)
|
|
2207
|
-
: [];
|
|
2208
|
-
const isFleetView = nextActiveViewId === 'fleet';
|
|
2209
|
-
const exportOnlyCatalogChange =
|
|
2210
|
-
activeViewPreservesFleetIframe()
|
|
2211
|
-
&& nextSignature !== state.lastArtifactCatalogSignature
|
|
2212
|
-
&& getArtifactCatalogSignatureExcludingExports(msg.artifacts)
|
|
2213
|
-
=== getArtifactCatalogSignatureExcludingExports(state.artifacts);
|
|
2214
|
-
// preserveFleetIframe views (default for fleet-dashboard layout) keep the iframe mounted
|
|
2215
|
-
// and rely on viewExportSnapshot postMessages for updates — the widget's DOM-diff
|
|
2216
|
-
// renderer applies them in-place. Non-preserve flows still reload when version bumps.
|
|
2217
|
-
const hasFleetVersionUpdate =
|
|
2218
|
-
isFleetView
|
|
2219
|
-
&& nextFleetRefreshVersion > state.fleetRefreshVersion
|
|
2220
|
-
&& !activeViewPreservesFleetIframe();
|
|
2221
|
-
// Skip only when signature unchanged and not refreshing, unless Fleet explicitly signaled fresher data.
|
|
2222
|
-
if (nextSignature === state.lastArtifactCatalogSignature && !state.isRefreshing && !hasFleetVersionUpdate) {
|
|
2223
|
-
break;
|
|
2224
|
-
}
|
|
2225
|
-
state.lastArtifactCatalogSignature = nextSignature;
|
|
2226
|
-
state.artifacts = msg.artifacts;
|
|
2227
|
-
state.galleryIgnorePatterns = nextGalleryIgnore;
|
|
2228
|
-
// View selection is owned by viewsLoaded; do not let artifact batches revert the dropdown.
|
|
2229
|
-
const prevActiveViewId = state.activeViewId;
|
|
2230
|
-
if (
|
|
2231
|
-
nextActiveViewId === state.activeViewId
|
|
2232
|
-
|| !state.views.some((view) => view.id === state.activeViewId)
|
|
2233
|
-
) {
|
|
2234
|
-
state.activeViewId = nextActiveViewId;
|
|
2235
|
-
}
|
|
2236
|
-
if (state.activeViewId !== prevActiveViewId) {
|
|
2237
|
-
// Host-initiated view change (e.g. openWithView): any in-flight refresh belongs
|
|
2238
|
-
// to the previous view — render now instead of deferring behind it.
|
|
2239
|
-
resetRefreshTrackingForViewChange();
|
|
2240
|
-
}
|
|
2241
|
-
state.fleetRefreshVersion = nextFleetRefreshVersion;
|
|
2242
|
-
applyFleetAutoRefresh();
|
|
2243
|
-
if (exportOnlyCatalogChange) {
|
|
2244
|
-
// Export JSON changed; host already pushes viewExportSnapshot — avoid gallery/iframe rebuild.
|
|
2245
|
-
break;
|
|
2246
|
-
}
|
|
2247
|
-
// Fleet JSON can change without agent-fleet.html mtime changing if the host
|
|
2248
|
-
// did not re-run the widget script; bumping fleetRefreshVersion means data is
|
|
2249
|
-
// fresher — force a preview reload so the iframe is not reused with stale HTML.
|
|
2250
|
-
if (state.isRefreshing) {
|
|
2251
|
-
// Mid-refresh burst: keep spinners on; requestGalleryRender defers the rebuild.
|
|
2252
|
-
setPerChartRefreshing(true);
|
|
2253
|
-
}
|
|
2254
|
-
requestGalleryRender({ forceFreshHtml: hasFleetVersionUpdate });
|
|
2255
|
-
break;
|
|
2256
|
-
}
|
|
2257
|
-
|
|
2258
|
-
case 'artifactDeleted': {
|
|
2259
|
-
// Remove from gallery with animation
|
|
2260
|
-
const card = document.querySelector(`[data-path="${msg.path}"]`);
|
|
2261
|
-
if (card) {
|
|
2262
|
-
card.classList.add('deleting');
|
|
2263
|
-
setTimeout(() => card.remove(), 300);
|
|
2264
|
-
|
|
2265
|
-
// Update state
|
|
2266
|
-
state.artifacts = state.artifacts.filter(a => a.localPath !== msg.path);
|
|
2267
|
-
|
|
2268
|
-
// Check if gallery is now empty
|
|
2269
|
-
if (state.artifacts.length === 0) {
|
|
2270
|
-
showGalleryState('empty');
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
break;
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
case 'summaryCards':
|
|
2277
|
-
state.summaryCards = msg.cards;
|
|
2278
|
-
renderSummaryCards(msg.cards);
|
|
2279
|
-
break;
|
|
2280
|
-
|
|
2281
|
-
case 'manifestUpdated':
|
|
2282
|
-
state.manifest = msg.manifest;
|
|
2283
|
-
// Re-render gallery with new manifest data
|
|
2284
|
-
if (state.artifacts.length > 0) {
|
|
2285
|
-
requestGalleryRender();
|
|
2286
|
-
}
|
|
2287
|
-
break;
|
|
2288
|
-
|
|
2289
|
-
case VIEW_EXPORT_SNAPSHOT:
|
|
2290
|
-
case LEGACY_VIEW_EXPORT_SNAPSHOT:
|
|
2291
|
-
postViewExportSnapshotToDashboardIframes(msg);
|
|
2292
|
-
break;
|
|
2293
|
-
|
|
2294
|
-
case 'artifactContent':
|
|
2295
|
-
if (msg.path && msg.format === 'html') {
|
|
2296
|
-
renderHtmlPreview(msg.path, msg.content, msg.error);
|
|
2297
|
-
}
|
|
2298
|
-
if (msg.path && msg.format === 'md') {
|
|
2299
|
-
const card = Array.from(document.querySelectorAll('.artifact-card')).find((cardEl) => {
|
|
2300
|
-
const element = /** @type {HTMLElement} */ (cardEl);
|
|
2301
|
-
return element.dataset.path === msg.path;
|
|
2302
|
-
});
|
|
2303
|
-
const host = /** @type {HTMLElement | null} */ (card?.querySelector('.markdown-preview'));
|
|
2304
|
-
if (host) {
|
|
2305
|
-
if (msg.error || !msg.content) {
|
|
2306
|
-
host.innerHTML = '<em>Failed to load preview</em>';
|
|
2307
|
-
} else {
|
|
2308
|
-
host.innerHTML = renderMarkdown(msg.content);
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
2312
|
-
break;
|
|
2313
|
-
|
|
2314
|
-
case 'clipboardText':
|
|
2315
|
-
document.querySelectorAll('.html-preview iframe').forEach((frame) => {
|
|
2316
|
-
const iframe = /** @type {HTMLIFrameElement} */ (frame);
|
|
2317
|
-
iframe.contentWindow?.postMessage({
|
|
2318
|
-
source: 'agentide-panel',
|
|
2319
|
-
type: 'clipboardText',
|
|
2320
|
-
requestId: msg.requestId,
|
|
2321
|
-
text: typeof msg.text === 'string' ? msg.text : '',
|
|
2322
|
-
}, '*');
|
|
2323
|
-
});
|
|
2324
|
-
break;
|
|
2325
|
-
|
|
2326
|
-
case 'generatingStarted':
|
|
2327
|
-
setRefreshButtonState(true);
|
|
2328
|
-
state.isRefreshing = false;
|
|
2329
|
-
state.refreshingViewId = null;
|
|
2330
|
-
// Drop any deferred render — a later flush would stomp the generating state.
|
|
2331
|
-
state.needsGalleryRender = false;
|
|
2332
|
-
state.pendingForceFreshHtml = false;
|
|
2333
|
-
setPerChartRefreshing(false);
|
|
2334
|
-
showGeneratingState();
|
|
2335
|
-
break;
|
|
2336
|
-
|
|
2337
|
-
case 'generatingCancelled':
|
|
2338
|
-
setRefreshButtonState(false);
|
|
2339
|
-
state.isRefreshing = false;
|
|
2340
|
-
state.refreshingViewId = null;
|
|
2341
|
-
state.needsGalleryRender = false;
|
|
2342
|
-
state.pendingForceFreshHtml = false;
|
|
2343
|
-
setPerChartRefreshing(false);
|
|
2344
|
-
// Go back to empty or content state
|
|
2345
|
-
if (state.artifacts.length > 0) {
|
|
2346
|
-
renderGallery(state.artifacts);
|
|
2347
|
-
} else {
|
|
2348
|
-
showGalleryState('empty');
|
|
2349
|
-
}
|
|
2350
|
-
break;
|
|
2351
|
-
|
|
2352
|
-
case 'generatingFailed':
|
|
2353
|
-
setRefreshButtonState(false);
|
|
2354
|
-
state.isRefreshing = false;
|
|
2355
|
-
state.refreshingViewId = null;
|
|
2356
|
-
state.needsGalleryRender = false;
|
|
2357
|
-
state.pendingForceFreshHtml = false;
|
|
2358
|
-
setPerChartRefreshing(false);
|
|
2359
|
-
showFailedState(msg.error);
|
|
2360
|
-
break;
|
|
2361
|
-
|
|
2362
|
-
case 'refreshStarted':
|
|
2363
|
-
if (!msg.viewId || msg.viewId === state.activeViewId) {
|
|
2364
|
-
setRefreshButtonState(true);
|
|
2365
|
-
state.isRefreshing = true;
|
|
2366
|
-
state.refreshingViewId = typeof msg.viewId === 'string' && msg.viewId ? msg.viewId : null;
|
|
2367
|
-
setPerChartRefreshing(true);
|
|
2368
|
-
}
|
|
2369
|
-
break;
|
|
2370
|
-
|
|
2371
|
-
case 'refreshFinished':
|
|
2372
|
-
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2373
|
-
setRefreshButtonState(false);
|
|
2374
|
-
state.isRefreshing = false;
|
|
2375
|
-
state.refreshingViewId = null;
|
|
2376
|
-
setPerChartRefreshing(false);
|
|
2377
|
-
flushPendingGalleryRender();
|
|
2378
|
-
if (activeViewPreservesFleetIframe()) {
|
|
2379
|
-
document.querySelectorAll('.html-preview iframe').forEach((frameEl) => {
|
|
2380
|
-
const iframe = /** @type {HTMLIFrameElement} */ (frameEl);
|
|
2381
|
-
try {
|
|
2382
|
-
iframe.contentWindow?.postMessage({ type: 'fleetRefreshComplete' }, '*');
|
|
2383
|
-
} catch {
|
|
2384
|
-
// Cross-origin or unloaded iframe — ignore.
|
|
2385
|
-
}
|
|
2386
|
-
});
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
break;
|
|
2390
|
-
|
|
2391
|
-
case 'viewsLoaded': {
|
|
2392
|
-
if (msg.surfaceMode === 'team' || msg.surfaceMode === 'spotlight') {
|
|
2393
|
-
applySurfaceMode(msg.surfaceMode);
|
|
2394
|
-
}
|
|
2395
|
-
const prevViewsLoadedViewId = state.activeViewId;
|
|
2396
|
-
state.views = Array.isArray(msg.views) ? msg.views : [];
|
|
2397
|
-
state.activeViewId = typeof msg.activeViewId === 'string' ? msg.activeViewId : state.activeViewId;
|
|
2398
|
-
if (state.activeViewId !== prevViewsLoadedViewId) {
|
|
2399
|
-
resetRefreshTrackingForViewChange();
|
|
2400
|
-
}
|
|
2401
|
-
applyViewOptions();
|
|
2402
|
-
applyFleetAutoRefresh();
|
|
2403
|
-
break;
|
|
2404
|
-
}
|
|
2405
|
-
|
|
2406
|
-
case 'refreshNoData':
|
|
2407
|
-
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2408
|
-
setRefreshButtonState(false);
|
|
2409
|
-
state.isRefreshing = false;
|
|
2410
|
-
state.refreshingViewId = null;
|
|
2411
|
-
setPerChartRefreshing(false);
|
|
2412
|
-
flushPendingGalleryRender();
|
|
2413
|
-
}
|
|
2414
|
-
break;
|
|
2415
|
-
|
|
2416
|
-
case 'refreshFailed':
|
|
2417
|
-
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2418
|
-
setRefreshButtonState(false);
|
|
2419
|
-
state.isRefreshing = false;
|
|
2420
|
-
state.refreshingViewId = null;
|
|
2421
|
-
setPerChartRefreshing(false);
|
|
2422
|
-
flushPendingGalleryRender();
|
|
2423
|
-
if (state.artifacts.length === 0) {
|
|
2424
|
-
showFailedState(msg.error);
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
break;
|
|
2428
|
-
|
|
2429
|
-
case 'filtersUpdated':
|
|
2430
|
-
state.scope = msg.scope === 'workspace' ? 'workspace' : 'global';
|
|
2431
|
-
state.projectId = msg.projectId || '';
|
|
2432
|
-
state.agentId = msg.agentId || '';
|
|
2433
|
-
state.agentIds = Array.isArray(msg.agentIds) ? msg.agentIds : [];
|
|
2434
|
-
// Note: Don't override activeViewId from filtersUpdated. This prevents race conditions
|
|
2435
|
-
// where filtersUpdated (sent last) overwrites the correct activeViewId set by viewsLoaded.
|
|
2436
|
-
// We still call applyViewOptions() to keep the dropdown UI in sync with the views list.
|
|
2437
|
-
applyViewOptions();
|
|
2438
|
-
applyFleetAutoRefresh();
|
|
2439
|
-
applyFiltersToControls();
|
|
2440
|
-
break;
|
|
2441
|
-
|
|
2442
|
-
case 'panelStateLoaded':
|
|
2443
|
-
if (msg.panelId && msg.panelId !== PANEL_ID) {
|
|
2444
|
-
break;
|
|
2445
|
-
}
|
|
2446
|
-
if (msg.surfaceMode === 'team' || msg.surfaceMode === 'spotlight') {
|
|
2447
|
-
applySurfaceMode(msg.surfaceMode);
|
|
2448
|
-
}
|
|
2449
|
-
state.panelState = normalizePanelState(msg.state);
|
|
2450
|
-
state.panelStateLoaded = true;
|
|
2451
|
-
applySummarySectionVisibility();
|
|
2452
|
-
if (typeof msg.fleetAutoRefreshIntervalSeconds === 'number') {
|
|
2453
|
-
state.fleetAutoRefreshIntervalSeconds = Math.max(0, msg.fleetAutoRefreshIntervalSeconds);
|
|
2454
|
-
}
|
|
2455
|
-
applyFleetAutoRefresh();
|
|
2456
|
-
if (ensurePanelStateForArtifacts(state.artifacts)) {
|
|
2457
|
-
savePanelState();
|
|
2458
|
-
}
|
|
2459
|
-
if (state.artifacts.length > 0) {
|
|
2460
|
-
renderGallery(state.artifacts);
|
|
2461
|
-
}
|
|
2462
|
-
break;
|
|
2463
|
-
|
|
2464
|
-
case 'disabledChartsUpdated':
|
|
2465
|
-
state.disabledCharts = new Set(
|
|
2466
|
-
(Array.isArray(msg.charts) ? msg.charts : [])
|
|
2467
|
-
.map((name) => String(name || '').trim().toLowerCase())
|
|
2468
|
-
.filter(Boolean),
|
|
2469
|
-
);
|
|
2470
|
-
requestGalleryRender();
|
|
2471
|
-
break;
|
|
2472
|
-
|
|
2473
|
-
case 'dataStale':
|
|
2474
|
-
showRefreshHint();
|
|
2475
|
-
break;
|
|
2476
|
-
|
|
2477
|
-
case 'dataFresh':
|
|
2478
|
-
hideRefreshHint();
|
|
2479
|
-
break;
|
|
2480
|
-
}
|
|
2481
|
-
});
|
|
2482
|
-
|
|
2483
|
-
// -----------------------------------------------------------------------------
|
|
2484
|
-
// Initialization
|
|
2485
|
-
// -----------------------------------------------------------------------------
|
|
2486
|
-
|
|
2487
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
2488
|
-
if (document.body.classList.contains('spotlight-surface-team')) {
|
|
2489
|
-
applySurfaceMode('team');
|
|
2490
|
-
}
|
|
2491
|
-
ensureShareToolbarButton();
|
|
2492
|
-
initQuickPrompts();
|
|
2493
|
-
initStateActions();
|
|
2494
|
-
initEmbeddedWidgetBridge();
|
|
2495
|
-
initFilters();
|
|
2496
|
-
initViews();
|
|
2497
|
-
initToolbarMenu();
|
|
2498
|
-
renderSummaryPlaceholders();
|
|
2499
|
-
|
|
2500
|
-
// Request initial data
|
|
2501
|
-
panelApi.postMessage({ type: 'requestViews' });
|
|
2502
|
-
panelApi.postMessage({ type: 'requestPanelState', panelId: PANEL_ID });
|
|
2503
|
-
panelApi.postMessage({ type: 'requestArtifacts' });
|
|
2504
|
-
panelApi.postMessage({ type: 'requestSummary' });
|
|
2505
|
-
panelApi.postMessage({ type: 'requestFilters' });
|
|
2506
|
-
});
|
|
222
|
+
})();</script>`;return/<\/body>/i.test(e)?e.replace(/<\/body>/i,`${n}</body>`):`${e}${n}`}function requestHtmlPreviewContents(e){for(const t of e)t.format!=="html"||!t.localPath||panelApi.postMessage({type:"requestArtifactContent",path:t.localPath,format:"html"})}function requestMarkdownPreviewContents(e){for(const t of e)t.format!=="md"||!t.localPath||panelApi.postMessage({type:"requestArtifactContent",path:t.localPath,format:"md"})}function renderHtmlPreview(e,t,n){const r=Array.from(document.querySelectorAll(".artifact-card")).find(l=>l.dataset.path===e)?.querySelector(".html-preview");if(!r)return;if(n||!t){const l=n||"No preview content available.";r.innerHTML=`<div class="html-preview-fallback">Preview unavailable (${escapeHtml(l)}). Use <strong>Open</strong> to inspect the artifact.</div>`;return}const s=document.querySelector("script[nonce]")?.getAttribute("nonce")||"",o=document.createElement("iframe");o.setAttribute("sandbox","allow-scripts allow-same-origin"),o.setAttribute("allow","clipboard-read; clipboard-write"),o.setAttribute("loading","lazy"),o.tabIndex=0;const f=injectNonceIntoInlineScripts(t,s);o.srcdoc=injectIframeKeyboardShortcutBridge(f,s),o.addEventListener("load",()=>{r.classList.add("ready");const l=r.closest(".artifact-card");l instanceof HTMLElement&&l.classList.contains("fleet-dashboard-full")&&autoFitFleetCardHeight(l)}),r.innerHTML="",r.appendChild(o)}function initQuickPrompts(){document.querySelectorAll(".quick-prompt").forEach(e=>{const t=e;t.addEventListener("click",()=>{const n=t.dataset.prompt;n&&panelApi.postMessage({type:"openChatWithPrompt",prompt:n})})}),document.getElementById("ask-ai-btn")?.addEventListener("click",()=>{panelApi.postMessage({type:"openChat"})}),document.getElementById("refresh-charts-btn")?.addEventListener("click",()=>{refreshCurrentView()}),document.getElementById("expand-sidebar-btn")?.remove(),document.getElementById("shrink-sidebar-btn")?.remove(),document.getElementById("summary-toggle-btn")?.addEventListener("click",e=>{e.stopPropagation(),toggleSummarySection()}),applySummarySectionVisibility()}function applyFiltersToControls(){const e=document.getElementById("agent-filter-select");if(e){e.innerHTML='<option value="">All agents</option>';for(const t of state.agentIds){const n=document.createElement("option");n.value=t,n.textContent=t,e.appendChild(n)}e.value=state.agentId||""}}function postFilterUpdate(){panelApi.postMessage({type:"updateFilters",agentId:state.agentId||""})}function initFilters(){const e=document.getElementById("agent-filter-select");e?.addEventListener("change",()=>{state.agentId=e.value||"",postFilterUpdate()})}function initStateActions(){document.getElementById("cancel-generate-btn")?.addEventListener("click",()=>{panelApi.postMessage({type:"cancelGeneration"})}),document.getElementById("retry-generate-btn")?.addEventListener("click",()=>{panelApi.postMessage({type:"retryGeneration"})})}function initToolbarMenu(){const e=document.getElementById("toolbar-menu-btn"),t=document.getElementById("toolbar-menu-dropdown");if(!e||!t)return;function n(a){const r=a??!t.classList.contains("open");t.classList.toggle("open",r),t.setAttribute("aria-hidden",String(!r)),e.setAttribute("aria-expanded",String(r))}e.addEventListener("click",a=>{a.stopPropagation(),n()}),document.addEventListener("click",a=>{!t.contains(a.target)&&a.target!==e&&n(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&t.classList.contains("open")&&(n(!1),e.focus())}),t.querySelectorAll(".dropdown-item[data-action]").forEach(a=>{const r=a;r.addEventListener("click",()=>{const s=r.dataset.action;n(!1);const o=getActiveView();switch(s){case"new-view":promptCreateView();break;case"duplicate-view":o?.id&&panelApi.postMessage({type:"duplicateView",viewId:o.id});break;case"rename-view":{if(!o||o.system)break;panelApi.postMessage({type:"requestRenameView",viewId:o.id});break}case"delete-view":{if(!o||o.system)break;panelApi.postMessage({type:"requestDeleteView",viewId:o.id});break}case"edit-view-scripts":panelApi.postMessage({type:"editViewScripts",viewId:o?.id});break;case"share-scripts-only":onShareScriptsOnlyClick();break;case"refresh-all-views":panelApi.postMessage({type:"refreshAllViews"});break;case"reset-home":confirm("Reset all charts and scripts in your home analytics folder? This will delete generated charts and user scripts, then regenerate defaults.")&&panelApi.postMessage({type:"resetChartsHome"});break;case"reset-workspace":confirm("Reset all charts and scripts in this workspace? This will delete generated charts and user scripts for the current workspace, then regenerate defaults.")&&panelApi.postMessage({type:"resetChartsWorkspace"});break;case"reenable-charts":panelApi.postMessage({type:"reenableAllCharts"});break}})})}function postViewExportSnapshotToDashboardIframes(e){const t=e.payload,n=e.meta;document.querySelectorAll(".html-preview iframe").forEach(a=>{const r=a;try{r.contentWindow?.postMessage({type:VIEW_EXPORT_SNAPSHOT,payload:t,meta:n},"*"),r.contentWindow?.postMessage({type:LEGACY_VIEW_EXPORT_SNAPSHOT,payload:t,meta:n},"*")}catch{}})}function initEmbeddedWidgetBridge(){window.addEventListener("message",e=>{const t=e.data;if(!(!t||typeof t!="object")&&t.source==="agentide-wow-widget"){if(t.type==="copySessionId"&&typeof t.sessionId=="string"){const n=t.sessionId.trim();n&&panelApi.postMessage({type:"copySessionId",sessionId:n});return}if(t.type==="requestClipboardText"&&typeof t.requestId=="string"){const n=t.requestId.trim();n&&panelApi.postMessage({type:"requestClipboardText",requestId:n});return}if(t.type==="writeClipboardText"&&typeof t.text=="string"){panelApi.postMessage({type:"writeClipboardText",text:t.text});return}if(t.type==="openArtifact"&&typeof t.path=="string"){const n=t.path.trim();n&&panelApi.postMessage({type:"openArtifact",path:n});return}if(t.type==="openChatWithPrompt"&&typeof t.prompt=="string"){const n=t.prompt.trim();n&&panelApi.postMessage({type:"openChatWithPrompt",prompt:n.slice(0,12e3)});return}if(t.type==="disconnectFleetChannel"&&typeof t.sessionId=="string"){const n=t.sessionId.trim();n&&panelApi.postMessage({type:"disconnectFleetChannel",sessionId:n,channelType:typeof t.channelType=="string"?t.channelType:"",channelTarget:typeof t.channelTarget=="string"?t.channelTarget:""});return}if(t.type==="updateFleetCardTitle"&&typeof t.sessionId=="string"&&typeof t.cardTitle=="string"){const n=t.sessionId.trim(),a=typeof t.sourceId=="string"?t.sourceId.trim():"local";n&&panelApi.postMessage({type:"updateFleetCardTitle",sourceId:a,sessionId:n,cardTitle:t.cardTitle});return}if(t.type==="openSpotlightForSession"&&typeof t.sessionId=="string"){const n=t.sessionId.trim();n&&panelApi.postMessage({type:"openSpotlightForSession",sessionId:n,channelType:typeof t.channelType=="string"?t.channelType:"",channelTarget:typeof t.channelTarget=="string"?t.channelTarget:"",model:typeof t.model=="string"?t.model:"",engine:typeof t.engine=="string"?t.engine:"",agentId:typeof t.agentId=="string"?t.agentId:""});return}if(t.type==="refreshView"){panelApi.postMessage({type:"refreshView"});return}if(t.type==="refreshFleetWidget"){panelApi.postMessage({type:"refreshFleetWidget"});return}if(t.type==="refreshWidget"){const n=typeof t.script=="string"?t.script.trim():"",a=Array.isArray(t.scripts)?t.scripts.filter(r=>typeof r=="string").map(r=>r.trim()).filter(Boolean):[];if(!n&&a.length===0)return;panelApi.postMessage({type:"refreshWidget",script:n||void 0,scripts:a.length>0?a:void 0});return}if(t.type===REQUEST_VIEW_EXPORT_SNAPSHOT||t.type===LEGACY_REQUEST_LIVE_FLEET_SNAPSHOT){panelApi.postMessage({type:REQUEST_VIEW_EXPORT_SNAPSHOT});return}t.type==="openChat"&&panelApi.postMessage({type:"openChat"})}}),window.addEventListener("message",e=>{const t=e.data;if(!t||typeof t!="object"||t.type!=="openSpotlightForSession"||t.source==="agentide-wow-widget"||typeof t.sessionId!="string")return;const n=t.sessionId.trim();n&&panelApi.postMessage({type:"openSpotlightForSession",sessionId:n,channelType:typeof t.channelType=="string"?t.channelType:"",channelTarget:typeof t.channelTarget=="string"?t.channelTarget:"",model:typeof t.model=="string"?t.model:"",engine:typeof t.engine=="string"?t.engine:"",agentId:typeof t.agentId=="string"?t.agentId:""})})}function showGeneratingState(){showGalleryState("generating")}function showFailedState(e){const t=document.getElementById("error-message");t&&(t.textContent=e),showGalleryState("failed")}function showRefreshHint(){const e=document.getElementById("refresh-hint");e&&(e.style.display="flex")}function hideRefreshHint(){const e=document.getElementById("refresh-hint");e&&(e.style.display="none")}function setPerChartRefreshing(e){document.querySelectorAll('.artifact-card[data-type="chart"]').forEach(t=>{t.classList.toggle("chart-refreshing",e);let n=t.querySelector(".artifact-refresh-indicator");e?n||(n=document.createElement("div"),n.className="artifact-refresh-indicator",n.textContent="Refreshing",t.appendChild(n)):n&&n.remove()})}function setRefreshButtonState(e){const t=document.getElementById("refresh-charts-btn");t&&t.classList.toggle("refreshing",e)}panelApi.onMessage(e=>{switch(e.type){case"artifactsUpdated":{const t=getArtifactCatalogSignature(e.artifacts),n=typeof e.activeViewId=="string"?e.activeViewId:state.activeViewId,a=typeof e.fleetRefreshVersion=="number"?Math.max(0,Math.floor(e.fleetRefreshVersion)):state.fleetRefreshVersion,r=Array.isArray(e.galleryIgnorePatterns)?e.galleryIgnorePatterns.filter(c=>typeof c=="string").map(c=>String(c).trim()).filter(Boolean):[],s=n==="fleet",o=activeViewPreservesFleetIframe()&&t!==state.lastArtifactCatalogSignature&&getArtifactCatalogSignatureExcludingExports(e.artifacts)===getArtifactCatalogSignatureExcludingExports(state.artifacts),f=s&&a>state.fleetRefreshVersion&&!activeViewPreservesFleetIframe();if(t===state.lastArtifactCatalogSignature&&!state.isRefreshing&&!f)break;state.lastArtifactCatalogSignature=t,state.artifacts=e.artifacts,state.galleryIgnorePatterns=r;const l=state.activeViewId;if((n===state.activeViewId||!state.views.some(c=>c.id===state.activeViewId))&&(state.activeViewId=n),state.activeViewId!==l&&resetRefreshTrackingForViewChange(),state.fleetRefreshVersion=a,applyFleetAutoRefresh(),o)break;state.isRefreshing&&setPerChartRefreshing(!0),requestGalleryRender({forceFreshHtml:f});break}case"artifactDeleted":{const t=document.querySelector(`[data-path="${e.path}"]`);t&&(t.classList.add("deleting"),setTimeout(()=>t.remove(),300),state.artifacts=state.artifacts.filter(n=>n.localPath!==e.path),state.artifacts.length===0&&showGalleryState("empty"));break}case"summaryCards":state.summaryCards=e.cards,renderSummaryCards(e.cards);break;case"manifestUpdated":state.manifest=e.manifest,state.artifacts.length>0&&requestGalleryRender();break;case VIEW_EXPORT_SNAPSHOT:case LEGACY_VIEW_EXPORT_SNAPSHOT:postViewExportSnapshotToDashboardIframes(e);break;case"artifactContent":if(e.path&&e.format==="html"&&renderHtmlPreview(e.path,e.content,e.error),e.path&&e.format==="md"){const n=Array.from(document.querySelectorAll(".artifact-card")).find(a=>a.dataset.path===e.path)?.querySelector(".markdown-preview");n&&(e.error||!e.content?n.innerHTML="<em>Failed to load preview</em>":n.innerHTML=renderMarkdown(e.content))}break;case"clipboardText":document.querySelectorAll(".html-preview iframe").forEach(t=>{t.contentWindow?.postMessage({source:"agentide-panel",type:"clipboardText",requestId:e.requestId,text:typeof e.text=="string"?e.text:""},"*")});break;case"generatingStarted":setRefreshButtonState(!0),state.isRefreshing=!1,state.refreshingViewId=null,state.needsGalleryRender=!1,state.pendingForceFreshHtml=!1,setPerChartRefreshing(!1),showGeneratingState();break;case"generatingCancelled":setRefreshButtonState(!1),state.isRefreshing=!1,state.refreshingViewId=null,state.needsGalleryRender=!1,state.pendingForceFreshHtml=!1,setPerChartRefreshing(!1),state.artifacts.length>0?renderGallery(state.artifacts):showGalleryState("empty");break;case"generatingFailed":setRefreshButtonState(!1),state.isRefreshing=!1,state.refreshingViewId=null,state.needsGalleryRender=!1,state.pendingForceFreshHtml=!1,setPerChartRefreshing(!1),showFailedState(e.error);break;case"refreshStarted":(!e.viewId||e.viewId===state.activeViewId)&&(setRefreshButtonState(!0),state.isRefreshing=!0,state.refreshingViewId=typeof e.viewId=="string"&&e.viewId?e.viewId:null,setPerChartRefreshing(!0));break;case"refreshFinished":(!e.viewId||e.viewId===state.activeViewId||e.viewId===state.refreshingViewId)&&(setRefreshButtonState(!1),state.isRefreshing=!1,state.refreshingViewId=null,setPerChartRefreshing(!1),flushPendingGalleryRender(),activeViewPreservesFleetIframe()&&document.querySelectorAll(".html-preview iframe").forEach(t=>{const n=t;try{n.contentWindow?.postMessage({type:"fleetRefreshComplete"},"*")}catch{}}));break;case"viewsLoaded":{(e.surfaceMode==="team"||e.surfaceMode==="spotlight")&&applySurfaceMode(e.surfaceMode);const t=state.activeViewId;state.views=Array.isArray(e.views)?e.views:[],state.activeViewId=typeof e.activeViewId=="string"?e.activeViewId:state.activeViewId,state.activeViewId!==t&&resetRefreshTrackingForViewChange(),applyViewOptions(),applyFleetAutoRefresh();break}case"refreshNoData":(!e.viewId||e.viewId===state.activeViewId||e.viewId===state.refreshingViewId)&&(setRefreshButtonState(!1),state.isRefreshing=!1,state.refreshingViewId=null,setPerChartRefreshing(!1),flushPendingGalleryRender());break;case"refreshFailed":(!e.viewId||e.viewId===state.activeViewId||e.viewId===state.refreshingViewId)&&(setRefreshButtonState(!1),state.isRefreshing=!1,state.refreshingViewId=null,setPerChartRefreshing(!1),flushPendingGalleryRender(),state.artifacts.length===0&&showFailedState(e.error));break;case"filtersUpdated":state.scope=e.scope==="workspace"?"workspace":"global",state.projectId=e.projectId||"",state.agentId=e.agentId||"",state.agentIds=Array.isArray(e.agentIds)?e.agentIds:[],applyViewOptions(),applyFleetAutoRefresh(),applyFiltersToControls();break;case"panelStateLoaded":if(e.panelId&&e.panelId!==PANEL_ID)break;(e.surfaceMode==="team"||e.surfaceMode==="spotlight")&&applySurfaceMode(e.surfaceMode),state.panelState=normalizePanelState(e.state),state.panelStateLoaded=!0,applySummarySectionVisibility(),typeof e.fleetAutoRefreshIntervalSeconds=="number"&&(state.fleetAutoRefreshIntervalSeconds=Math.max(0,e.fleetAutoRefreshIntervalSeconds)),applyFleetAutoRefresh(),ensurePanelStateForArtifacts(state.artifacts)&&savePanelState(),state.artifacts.length>0&&renderGallery(state.artifacts);break;case"disabledChartsUpdated":state.disabledCharts=new Set((Array.isArray(e.charts)?e.charts:[]).map(t=>String(t||"").trim().toLowerCase()).filter(Boolean)),requestGalleryRender();break;case"dataStale":showRefreshHint();break;case"dataFresh":hideRefreshHint();break}}),document.addEventListener("DOMContentLoaded",()=>{document.body.classList.contains("spotlight-surface-team")&&applySurfaceMode("team"),ensureShareToolbarButton(),initQuickPrompts(),initStateActions(),initEmbeddedWidgetBridge(),initFilters(),initViews(),initToolbarMenu(),renderSummaryPlaceholders(),panelApi.postMessage({type:"requestViews"}),panelApi.postMessage({type:"requestPanelState",panelId:PANEL_ID}),panelApi.postMessage({type:"requestArtifacts"}),panelApi.postMessage({type:"requestSummary"}),panelApi.postMessage({type:"requestFilters"})});
|