chrome-devtools-frontend 1.0.1657855 → 1.0.1661063
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/.agents/skills/evaluate-ai-css-completion/SKILL.md +133 -0
- package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +76 -0
- package/.agents/skills/migrate-chromium-test/SKILL.md +15 -70
- package/.agents/skills/ui-eng-vision-orchestrator/SKILL.md +37 -18
- package/.agents/skills/version-control/SKILL.md +8 -1
- package/AUTHORS +1 -0
- package/SECURITY.md +3 -0
- package/docs/get_the_code.md +6 -0
- package/eslint.config.mjs +7 -0
- package/extension-api/ExtensionAPI.d.ts +88 -0
- package/front_end/Tests.js +6 -6
- package/front_end/core/common/Gzip.ts +12 -5
- package/front_end/core/host/AidaClient.ts +35 -9
- package/front_end/core/host/GdpClient.ts +10 -7
- package/front_end/core/host/InspectorFrontendHost.ts +1 -0
- package/front_end/core/host/InspectorFrontendHostStub.ts +2 -0
- package/front_end/core/platform/StringUtilities.ts +55 -4
- package/front_end/core/sdk/AccessibilityModel.snapshot.txt +17 -0
- package/front_end/core/sdk/AccessibilityModel.ts +132 -2
- package/front_end/core/sdk/CPUThrottlingManager.ts +10 -5
- package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +2 -5
- package/front_end/core/sdk/ConsoleModel.ts +5 -5
- package/front_end/core/sdk/DOMDebuggerModel.ts +7 -1
- package/front_end/core/sdk/DOMModel.ts +33 -18
- package/front_end/core/sdk/DebuggerModel.ts +4 -4
- package/front_end/core/sdk/EventBreakpointsModel.ts +2 -0
- package/front_end/core/sdk/FrameManager.ts +1 -0
- package/front_end/core/sdk/IsolateManager.ts +1 -0
- package/front_end/core/sdk/NetworkManager.ts +59 -11
- package/front_end/core/sdk/NetworkRequest.ts +38 -1
- package/front_end/core/sdk/OverlayModel.ts +45 -6
- package/front_end/core/sdk/PageResourceLoader.ts +2 -0
- package/front_end/core/sdk/ResourceTreeModel.ts +6 -7
- package/front_end/core/sdk/ScreenCaptureModel.ts +2 -2
- package/front_end/core/sdk/ServerTiming.ts +17 -13
- package/front_end/core/sdk/ServiceWorkerCacheModel.ts +4 -2
- package/front_end/core/sdk/ServiceWorkerManager.ts +19 -5
- package/front_end/core/sdk/SourceMap.ts +5 -5
- package/front_end/core/sdk/SourceMapManager.ts +3 -2
- package/front_end/core/sdk/TargetManager.ts +14 -1
- package/front_end/core/sdk/TraceObject.ts +4 -2
- package/front_end/core/sdk/sdk-meta.ts +170 -0
- package/front_end/design_system_tokens.css +0 -5
- package/front_end/entrypoints/formatter_worker/FormattedContentBuilder.ts +5 -2
- package/front_end/entrypoints/formatter_worker/HTMLFormatter.ts +26 -4
- package/front_end/entrypoints/formatter_worker/JavaScriptFormatter.ts +8 -3
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +4 -4
- package/front_end/entrypoints/inspector_main/OutermostTargetSelector.ts +2 -2
- package/front_end/entrypoints/inspector_main/RenderingOptions.ts +36 -37
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +15 -33
- package/front_end/entrypoints/js_app/js_app.ts +6 -5
- package/front_end/entrypoints/main/GlobalAiButton.ts +4 -4
- package/front_end/entrypoints/main/MainImpl.ts +20 -22
- package/front_end/entrypoints/main/main-meta.ts +42 -42
- package/front_end/entrypoints/node_app/node_app.ts +3 -2
- package/front_end/entrypoints/worker_app/WorkerMain.ts +1 -1
- package/front_end/foundation/Universe.ts +44 -1
- package/front_end/generated/InspectorBackendCommands.ts +2 -2
- package/front_end/generated/SupportedCSSProperties.js +19 -12
- package/front_end/generated/protocol.ts +3 -1
- package/front_end/models/ai_assistance/AiConversation.ts +19 -17
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +37 -14
- package/front_end/models/ai_assistance/AiUtils.ts +38 -42
- package/front_end/models/ai_assistance/agents/AiAgent.ts +5 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -2
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +7 -5
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +270 -286
- package/front_end/models/ai_assistance/data_formatters/UnitFormatters.ts +20 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +3 -1
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +3 -2
- package/front_end/models/autofill_manager/AutofillManager.ts +3 -1
- package/front_end/models/bindings/CompilerScriptMapping.ts +7 -7
- package/front_end/models/bindings/ContentProviderBasedProject.ts +4 -4
- package/front_end/models/bindings/DebuggerLanguagePlugins.ts +5 -5
- package/front_end/models/bindings/DefaultScriptMapping.ts +3 -3
- package/front_end/models/bindings/NetworkProject.ts +5 -10
- package/front_end/models/bindings/PresentationConsoleMessageHelper.ts +2 -1
- package/front_end/models/bindings/ResourceMapping.ts +3 -4
- package/front_end/models/bindings/ResourceScriptMapping.ts +2 -3
- package/front_end/models/bindings/ResourceUtils.ts +1 -1
- package/front_end/models/bindings/SASSSourceMapping.ts +11 -9
- package/front_end/models/bindings/StylesSourceMapping.ts +3 -3
- package/front_end/models/bindings/TempFile.ts +8 -3
- package/front_end/models/emulation/EmulatedDevices.ts +389 -8
- package/front_end/models/extensions/ExtensionAPI.ts +116 -52
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +13 -12
- package/front_end/models/formatter/ScriptFormatter.ts +8 -11
- package/front_end/models/issues_manager/BounceTrackingIssue.ts +1 -1
- package/front_end/models/issues_manager/ClientHintIssue.ts +1 -1
- package/front_end/models/issues_manager/ConnectionAllowlistIssue.ts +1 -1
- package/front_end/models/issues_manager/ContentSecurityPolicyIssue.ts +7 -7
- package/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +2 -2
- package/front_end/models/issues_manager/CookieIssue.ts +27 -16
- package/front_end/models/issues_manager/CorsIssue.ts +3 -3
- package/front_end/models/issues_manager/CrossOriginEmbedderPolicyIssue.ts +2 -2
- package/front_end/models/issues_manager/DeprecationIssue.ts +3 -3
- package/front_end/models/issues_manager/EmailVerificationRequestIssue.ts +1 -1
- package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +1 -1
- package/front_end/models/issues_manager/FederatedAuthUserInfoRequestIssue.ts +1 -1
- package/front_end/models/issues_manager/GenericIssue.ts +7 -7
- package/front_end/models/issues_manager/HeavyAdIssue.ts +3 -3
- package/front_end/models/issues_manager/Issue.ts +11 -12
- package/front_end/models/issues_manager/IssueAggregator.ts +0 -9
- package/front_end/models/issues_manager/IssueResolver.ts +2 -2
- package/front_end/models/issues_manager/IssuesManager.ts +136 -137
- package/front_end/models/issues_manager/MixedContentIssue.ts +1 -1
- package/front_end/models/issues_manager/PartitioningBlobURLIssue.ts +3 -3
- package/front_end/models/issues_manager/QuirksModeIssue.ts +1 -1
- package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -2
- package/front_end/models/issues_manager/SelectivePermissionsInterventionIssue.ts +2 -2
- package/front_end/models/issues_manager/SharedArrayBufferIssue.ts +2 -2
- package/front_end/models/issues_manager/SharedDictionaryIssue.ts +1 -1
- package/front_end/models/issues_manager/UnencodedDigestIssue.ts +3 -3
- package/front_end/models/issues_manager/issues_manager.ts +0 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
- package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +5 -0
- package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +13 -10
- package/front_end/models/stack_trace/StackTraceModel.ts +3 -3
- package/front_end/models/text_utils/ContentData.ts +27 -0
- package/front_end/models/trace/helpers/SamplesIntegrator.ts +21 -5
- package/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +29 -14
- package/front_end/models/web_mcp/WebMCPModel.ts +24 -6
- package/front_end/models/workspace/IgnoreListManager.ts +6 -6
- package/front_end/models/workspace/UISourceCode.ts +3 -3
- package/front_end/models/workspace/WorkspaceImpl.ts +10 -1
- package/front_end/models/workspace_diff/WorkspaceDiff.ts +10 -4
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +25 -22
- package/front_end/panels/ai_assistance/ExportConversation.ts +3 -4
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -3
- package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +9 -1
- package/front_end/panels/ai_assistance/components/DisabledWidget.ts +2 -2
- package/front_end/panels/animation/AnimationTimeline.ts +17 -19
- package/front_end/panels/animation/AnimationUI.ts +5 -5
- package/front_end/panels/animation/animation-meta.ts +2 -2
- package/front_end/panels/application/ApplicationPanelSidebar.ts +4 -3
- package/front_end/panels/application/DeviceBoundSessionsView.ts +2 -6
- package/front_end/panels/application/FrameDetailsView.ts +1 -1
- package/front_end/panels/application/IndexedDBViews.ts +220 -266
- package/front_end/panels/application/OpenedWindowDetailsView.ts +1 -1
- package/front_end/panels/application/ResourcesPanel.ts +9 -2
- package/front_end/panels/application/ServiceWorkersView.ts +252 -211
- package/front_end/panels/application/StorageView.ts +97 -33
- package/front_end/panels/application/WebMCPView.ts +53 -44
- package/front_end/panels/application/components/AdsView.ts +201 -30
- package/front_end/panels/application/components/adsView.css +25 -0
- package/front_end/panels/application/indexedDBViews.css +38 -9
- package/front_end/panels/application/preloading/components/RuleSetDetailsView.ts +2 -2
- package/front_end/panels/application/preloading/helper/PreloadingForward.ts +2 -1
- package/front_end/panels/application/storageView.css +26 -9
- package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +5 -1
- package/front_end/panels/browser_debugger/browser_debugger-meta.ts +8 -6
- package/front_end/panels/common/DOMLinkifier.ts +1 -1
- package/front_end/panels/common/ExtensionServer.ts +119 -14
- package/front_end/panels/console/ConsoleContextSelector.ts +1 -1
- package/front_end/panels/console/ConsolePinPane.ts +2 -2
- package/front_end/panels/console/ConsolePrompt.ts +2 -2
- package/front_end/panels/console/ConsoleView.ts +3 -2
- package/front_end/panels/console/PromptBuilder.ts +2 -1
- package/front_end/panels/console/SymbolizedErrorWidget.ts +2 -1
- package/front_end/panels/console_counters/WarningErrorCounter.ts +2 -2
- package/front_end/panels/coverage/CoverageListView.ts +28 -28
- package/front_end/panels/coverage/CoverageModel.ts +2 -1
- package/front_end/panels/coverage/CoverageView.ts +22 -22
- package/front_end/panels/coverage/coverage-meta.ts +5 -5
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +36 -36
- package/front_end/panels/css_overview/CSSOverviewProcessingView.ts +1 -1
- package/front_end/panels/css_overview/CSSOverviewSidebarPanel.ts +2 -2
- package/front_end/panels/css_overview/CSSOverviewStartView.ts +6 -6
- package/front_end/panels/css_overview/CSSOverviewUnusedDeclarations.ts +6 -6
- package/front_end/panels/css_overview/css_overview-meta.ts +2 -2
- package/front_end/panels/developer_resources/DeveloperResourcesListView.ts +1 -1
- package/front_end/panels/elements/AccessibilityTreeUtils.ts +8 -102
- package/front_end/panels/elements/AccessibilityTreeView.ts +163 -70
- package/front_end/panels/elements/ElementsPanel.ts +17 -11
- package/front_end/panels/elements/ElementsTreeElement.ts +4 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +4 -4
- package/front_end/panels/elements/LayoutPane.ts +1 -1
- package/front_end/panels/elements/MetricsSidebarPane.ts +100 -34
- package/front_end/panels/elements/StylePropertiesSection.ts +2 -2
- package/front_end/panels/elements/StylePropertyTreeElement.ts +8 -2
- package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
- package/front_end/panels/elements/components/AccessibilityTreeNode.ts +7 -18
- package/front_end/panels/elements/components/ElementsBreadcrumbs.ts +2 -2
- package/front_end/panels/elements/components/QueryContainer.ts +1 -1
- package/front_end/panels/emulation/DeviceModeView.ts +52 -70
- package/front_end/panels/issues/AffectedDirectivesView.ts +1 -1
- package/front_end/panels/issues/AffectedResourcesView.ts +2 -1
- package/front_end/panels/issues/IssueView.ts +0 -2
- package/front_end/panels/issues/IssuesPane.ts +1 -8
- package/front_end/panels/js_timeline/js_timeline-meta.ts +3 -2
- package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +3 -3
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +5 -5
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryHighlightChipList.ts +4 -4
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +2 -2
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryNavigator.ts +6 -6
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +3 -3
- package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +8 -9
- package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplayUtils.ts +2 -2
- package/front_end/panels/linear_memory_inspector/components/ValueInterpreterSettings.ts +1 -1
- package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +2 -2
- package/front_end/panels/network/NetworkDataGridNode.ts +124 -36
- package/front_end/panels/network/NetworkLogView.ts +9 -1
- package/front_end/panels/network/NetworkLogViewColumns.ts +18 -0
- package/front_end/panels/network/NetworkPanel.ts +2 -1
- package/front_end/panels/network/RequestPayloadView.ts +68 -20
- package/front_end/panels/network/RequestPreviewView.ts +7 -1
- package/front_end/panels/network/RequestTimingView.ts +95 -127
- package/front_end/panels/network/components/ResponseHeaderSection.ts +1 -1
- package/front_end/panels/network/forward/UIFilter.ts +1 -0
- package/front_end/panels/network/requestPayloadView.css +10 -0
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +12 -12
- package/front_end/panels/performance_monitor/performance_monitor-meta.ts +7 -7
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +2 -2
- package/front_end/panels/profiler/HeapProfileView.ts +563 -51
- package/front_end/panels/profiler/HeapSnapshotView.ts +14 -9
- package/front_end/panels/profiler/ProfilesPanel.ts +13 -7
- package/front_end/panels/profiler/WritableProfileHeader.ts +152 -0
- package/front_end/panels/profiler/profiler.ts +2 -2
- package/front_end/panels/recorder/{components/ControlButton.ts → ControlButton.ts} +9 -10
- package/front_end/panels/recorder/{components/CreateRecordingView.ts → CreateRecordingView.ts} +59 -58
- package/front_end/panels/recorder/ExtensionView.ts +123 -0
- package/front_end/panels/recorder/RecorderController.ts +102 -92
- package/front_end/panels/recorder/{components/RecordingListView.ts → RecordingListView.ts} +22 -23
- package/front_end/panels/recorder/{components/RecordingView.ts → RecordingView.ts} +99 -96
- package/front_end/panels/recorder/{components/ReplaySection.ts → ReplaySection.ts} +20 -20
- package/front_end/panels/recorder/{components/SelectorPicker.ts → SelectorPicker.ts} +13 -13
- package/front_end/panels/recorder/{components/StepEditor.ts → StepEditor.ts} +367 -336
- package/front_end/panels/recorder/{components/StepView.ts → StepView.ts} +48 -49
- package/front_end/panels/recorder/{components/TimelineSection.ts → TimelineSection.ts} +2 -2
- package/front_end/panels/recorder/models/RecorderSettings.ts +2 -2
- package/front_end/panels/recorder/recorder-meta.ts +7 -7
- package/front_end/panels/recorder/recorder.ts +23 -1
- package/front_end/panels/recorder/{components/recordingView.css → recordingView.css} +1 -1
- package/front_end/panels/recorder/util/util.ts +113 -0
- package/front_end/panels/screencast/ScreencastApp.ts +1 -1
- package/front_end/panels/screencast/ScreencastView.ts +12 -12
- package/front_end/panels/search/SearchResultsPane.ts +4 -4
- package/front_end/panels/search/SearchView.ts +20 -20
- package/front_end/panels/security/SecurityModel.ts +7 -7
- package/front_end/panels/security/SecurityPanel.ts +99 -107
- package/front_end/panels/security/SecurityPanelSidebar.ts +7 -7
- package/front_end/panels/security/security-meta.ts +2 -2
- package/front_end/panels/sensors/LocationsSettingsTab.ts +19 -19
- package/front_end/panels/sensors/SensorsView.ts +27 -27
- package/front_end/panels/sensors/sensors-meta.ts +13 -167
- package/front_end/panels/settings/AISettingsTab.ts +98 -56
- package/front_end/panels/settings/EditFileSystemView.ts +2 -2
- package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +20 -20
- package/front_end/panels/settings/KeybindsSettingsTab.ts +20 -21
- package/front_end/panels/settings/SettingsScreen.ts +11 -11
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +5 -5
- package/front_end/panels/settings/components/SyncSection.ts +12 -12
- package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +13 -13
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +31 -31
- package/front_end/panels/settings/emulation/emulation-meta.ts +1 -1
- package/front_end/panels/settings/settings-meta.ts +14 -14
- package/front_end/panels/sources/InplaceFormatterEditorAction.ts +2 -2
- package/front_end/panels/sources/NavigatorView.ts +7 -6
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +83 -37
- package/front_end/panels/sources/SourcesNavigator.ts +22 -21
- package/front_end/panels/sources/SourcesView.ts +10 -1
- package/front_end/panels/sources/TabbedEditorContainer.ts +1 -1
- package/front_end/panels/sources/scopeChainSidebarPane.css +12 -4
- package/front_end/panels/sources/sources-meta.ts +4 -4
- package/front_end/panels/timeline/CompatibilityTracksAppender.ts +5 -2
- package/front_end/panels/timeline/IsolateSelector.ts +10 -8
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +2 -1
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +2 -1
- package/front_end/panels/timeline/TimelineFlameChartView.ts +1 -1
- package/front_end/panels/timeline/TimelinePanel.ts +20 -8
- package/front_end/panels/timeline/TimelineUIUtils.ts +149 -131
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +4 -2
- package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +4 -2
- package/front_end/panels/timeline/components/insights/ImageRef.ts +2 -1
- package/front_end/panels/timeline/timeline-meta.ts +3 -2
- package/front_end/panels/utils/utils.ts +7 -3
- package/front_end/panels/web_audio/WebAudioView.ts +17 -18
- package/front_end/panels/web_audio/web_audio-meta.ts +3 -3
- package/front_end/panels/whats_new/ReleaseNoteView.ts +1 -1
- package/front_end/panels/whats_new/whats_new-meta.ts +11 -11
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lit/lib/async-directive.d.ts +2 -1
- package/front_end/third_party/lit/lib/async-directive.js +1 -1
- package/front_end/third_party/lit/lib/async-directive.js.map +1 -1
- package/front_end/third_party/lit/lib/decorators.d.ts +2 -1
- package/front_end/third_party/lit/lib/decorators.js.map +1 -1
- package/front_end/third_party/lit/lib/directive.d.ts +2 -1
- package/front_end/third_party/lit/lib/directive.js.map +1 -1
- package/front_end/third_party/lit/lib/directives.d.ts +2 -1
- package/front_end/third_party/lit/lib/directives.js +8 -8
- package/front_end/third_party/lit/lib/directives.js.map +1 -1
- package/front_end/third_party/lit/lib/lit.d.ts +2 -1
- package/front_end/third_party/lit/lib/lit.js +1 -1
- package/front_end/third_party/lit/lib/lit.js.map +1 -1
- package/front_end/third_party/lit/lib/static-html.d.ts +2 -1
- package/front_end/third_party/lit/lib/static-html.js +1 -1
- package/front_end/third_party/lit/lib/static-html.js.map +1 -1
- package/front_end/third_party/lit/package.json +2 -2
- package/front_end/third_party/lit/rebuild.sh +1 -1
- package/front_end/third_party/lit/src/async-directive.ts +5 -0
- package/front_end/ui/components/dialogs/Dialog.ts +1 -1
- package/front_end/ui/components/dialogs/ShortcutDialog.ts +1 -1
- package/front_end/ui/components/diff_view/DiffView.ts +2 -2
- package/front_end/ui/components/issue_counter/IssueCounter.ts +3 -3
- package/front_end/ui/components/issue_counter/IssueLinkIcon.ts +5 -5
- package/front_end/ui/components/lists/List.ts +2 -2
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
- package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +5 -5
- package/front_end/ui/components/settings/SettingCheckbox.ts +1 -1
- package/front_end/ui/components/snackbars/Snackbar.ts +1 -1
- package/front_end/ui/components/survey_link/SurveyLink.ts +3 -3
- package/front_end/ui/components/text_editor/config.ts +2 -2
- package/front_end/ui/components/tree_outline/TreeOutline.ts +34 -1
- package/front_end/ui/legacy/ReportView.ts +5 -0
- package/front_end/ui/legacy/Treeoutline.ts +6 -0
- package/front_end/ui/legacy/View.ts +1 -1
- package/front_end/ui/legacy/Widget.ts +14 -15
- package/front_end/ui/legacy/components/data_grid/DataGrid.ts +2 -0
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +8 -3
- package/front_end/ui/legacy/components/data_grid/data_grid.ts +1 -0
- package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +106 -38
- package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +7 -1
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +2 -1
- package/front_end/ui/legacy/components/utils/ImagePreview.ts +4 -2
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +10 -1
- package/front_end/ui/legacy/inspectorCommon.css +5 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/mcp/mcp.ts +2 -0
- package/package.json +4 -4
- package/front_end/models/issues_manager/AttributionReportingIssue.ts +0 -247
- package/front_end/models/issues_manager/descriptions/arInsecureContext.md +0 -7
- package/front_end/models/issues_manager/descriptions/arInvalidInfoHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arInvalidRegisterSourceHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arInvalidRegisterTriggerHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
- package/front_end/models/issues_manager/descriptions/arNoRegisterOsSourceHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNoRegisterOsTriggerHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNoRegisterSourceHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNoRegisterTriggerHeader.md +0 -5
- package/front_end/models/issues_manager/descriptions/arNoWebOrOsSupport.md +0 -4
- package/front_end/models/issues_manager/descriptions/arOsSourceIgnored.md +0 -18
- package/front_end/models/issues_manager/descriptions/arOsTriggerIgnored.md +0 -19
- package/front_end/models/issues_manager/descriptions/arPermissionPolicyDisabled.md +0 -8
- package/front_end/models/issues_manager/descriptions/arSourceAndTriggerHeaders.md +0 -9
- package/front_end/models/issues_manager/descriptions/arSourceIgnored.md +0 -13
- package/front_end/models/issues_manager/descriptions/arTriggerIgnored.md +0 -12
- package/front_end/models/issues_manager/descriptions/arUntrustworthyReportingOrigin.md +0 -10
- package/front_end/models/issues_manager/descriptions/arWebAndOsHeaders.md +0 -11
- package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +0 -182
- package/front_end/panels/profiler/ProfileView.ts +0 -611
- package/front_end/panels/recorder/components/ExtensionView.ts +0 -132
- package/front_end/panels/recorder/components/components.ts +0 -25
- package/front_end/panels/recorder/components/util.ts +0 -116
- /package/front_end/panels/recorder/{components/controlButton.css → controlButton.css} +0 -0
- /package/front_end/panels/recorder/{components/createRecordingView.css → createRecordingView.css} +0 -0
- /package/front_end/panels/recorder/{components/extensionView.css → extensionView.css} +0 -0
- /package/front_end/panels/recorder/{components/recordingListView.css → recordingListView.css} +0 -0
- /package/front_end/panels/recorder/{components/replaySection.css → replaySection.css} +0 -0
- /package/front_end/panels/recorder/{components/selectorPicker.css → selectorPicker.css} +0 -0
- /package/front_end/panels/recorder/{components/startView.css → startView.css} +0 -0
- /package/front_end/panels/recorder/{components/stepEditor.css → stepEditor.css} +0 -0
- /package/front_end/panels/recorder/{components/stepView.css → stepView.css} +0 -0
- /package/front_end/panels/recorder/{components/timelineSection.css → timelineSection.css} +0 -0
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import * as i18n from '
|
|
6
|
-
import * as Platform from '
|
|
7
|
-
import type * as Puppeteer from '
|
|
8
|
-
import * as Buttons from '
|
|
9
|
-
import * as SuggestionInput from '
|
|
10
|
-
import * as UI from '
|
|
11
|
-
import * as Lit from '
|
|
12
|
-
import * as VisualLogging from '
|
|
13
|
-
import * as Models from '../models/models.js';
|
|
14
|
-
import * as Util from '../util/util.js';
|
|
5
|
+
import * as i18n from '../../core/i18n/i18n.js';
|
|
6
|
+
import * as Platform from '../../core/platform/platform.js';
|
|
7
|
+
import type * as Puppeteer from '../../third_party/puppeteer/puppeteer.js';
|
|
8
|
+
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
9
|
+
import * as SuggestionInput from '../../ui/components/suggestion_input/suggestion_input.js';
|
|
10
|
+
import * as UI from '../../ui/legacy/legacy.js';
|
|
11
|
+
import * as Lit from '../../ui/lit/lit.js';
|
|
12
|
+
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
15
13
|
|
|
14
|
+
import * as Models from './models/models.js';
|
|
16
15
|
import {RequestSelectorAttributeEvent, SelectorPicker} from './SelectorPicker.js';
|
|
17
16
|
import stepEditorStyles from './stepEditor.css.js';
|
|
18
17
|
import {
|
|
@@ -27,10 +26,10 @@ import {
|
|
|
27
26
|
type Keys,
|
|
28
27
|
type OptionalKeys,
|
|
29
28
|
type RequiredKeys,
|
|
30
|
-
|
|
29
|
+
SharedObject,
|
|
30
|
+
} from './util/util.js';
|
|
31
31
|
|
|
32
|
-
const {html,
|
|
33
|
-
const {customElement, property, state} = Decorators;
|
|
32
|
+
const {html, render, Directives} = Lit;
|
|
34
33
|
const {live} = Directives;
|
|
35
34
|
const {widget} = UI.Widget;
|
|
36
35
|
|
|
@@ -226,7 +225,7 @@ const attributesByType = deepFreeze<{
|
|
|
226
225
|
|
|
227
226
|
const UIStrings = {
|
|
228
227
|
/**
|
|
229
|
-
* @description The text that is
|
|
228
|
+
* @description The text that is displayed when the steps were not saved due to an error. The error message itself is always in English and not translated.
|
|
230
229
|
* @example {Saving failed} error
|
|
231
230
|
*/
|
|
232
231
|
notSaved: 'Not saved: {error}',
|
|
@@ -240,7 +239,7 @@ const UIStrings = {
|
|
|
240
239
|
*/
|
|
241
240
|
deleteRow: 'Delete row',
|
|
242
241
|
/**
|
|
243
|
-
* @description The title of a button that adds a new input field for the entry of the frame index. Frame index is the number of the frame within the page
|
|
242
|
+
* @description The title of a button that adds a new input field for the entry of the frame index. Frame index is the number of the frame within the page’s frame tree.
|
|
244
243
|
*/
|
|
245
244
|
addFrameIndex: 'Add frame index within the frame tree',
|
|
246
245
|
/**
|
|
@@ -264,19 +263,13 @@ const UIStrings = {
|
|
|
264
263
|
*/
|
|
265
264
|
removeSelector: 'Remove a selector',
|
|
266
265
|
/**
|
|
267
|
-
* @description The error message
|
|
266
|
+
* @description The error message displayed when a user enters a type in the input that is not associated with any existing types.
|
|
268
267
|
*/
|
|
269
|
-
unknownActionType: '
|
|
268
|
+
unknownActionType: 'Enter a valid action type',
|
|
270
269
|
} as const;
|
|
271
|
-
const str_ = i18n.i18n.registerUIStrings('panels/recorder/
|
|
270
|
+
const str_ = i18n.i18n.registerUIStrings('panels/recorder/StepEditor.ts', UIStrings);
|
|
272
271
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
273
272
|
|
|
274
|
-
declare global {
|
|
275
|
-
interface HTMLElementTagNameMap {
|
|
276
|
-
'devtools-recorder-step-editor': StepEditor;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
273
|
export class StepEditedEvent extends Event {
|
|
281
274
|
static readonly eventName = 'stepedited';
|
|
282
275
|
data: Models.Schema.Step;
|
|
@@ -335,9 +328,9 @@ interface Puppeteer {
|
|
|
335
328
|
}
|
|
336
329
|
|
|
337
330
|
export class EditorState {
|
|
338
|
-
static #puppeteer:
|
|
339
|
-
() => Models.RecordingPlayer.RecordingPlayer.connectPuppeteer(),
|
|
340
|
-
|
|
331
|
+
static #puppeteer: SharedObject.SharedObject<Puppeteer> =
|
|
332
|
+
new SharedObject.SharedObject(() => Models.RecordingPlayer.RecordingPlayer.connectPuppeteer(),
|
|
333
|
+
({browser}) => Models.RecordingPlayer.RecordingPlayer.disconnectPuppeteer(browser));
|
|
341
334
|
|
|
342
335
|
static async default(type: Models.Schema.StepType): Promise<DeepImmutable<EditorState>> {
|
|
343
336
|
const state = {type};
|
|
@@ -358,9 +351,9 @@ export class EditorState {
|
|
|
358
351
|
static async defaultByAttribute<Attribute extends keyof typeof defaultValuesByAttribute>(
|
|
359
352
|
state: DeepImmutable<EditorState>,
|
|
360
353
|
attribute: Attribute): Promise<DeepImmutable<typeof defaultValuesByAttribute[Attribute]>>;
|
|
361
|
-
static async defaultByAttribute(_state: DeepImmutable<EditorState>,
|
|
362
|
-
|
|
363
|
-
return await this.#puppeteer.run(puppeteer => {
|
|
354
|
+
static async defaultByAttribute(_state: DeepImmutable<EditorState>,
|
|
355
|
+
attribute: keyof typeof defaultValuesByAttribute): Promise<unknown> {
|
|
356
|
+
return await this.#puppeteer.run<unknown>(puppeteer => {
|
|
364
357
|
switch (attribute) {
|
|
365
358
|
case 'assertedEvents': {
|
|
366
359
|
return immutableDeepAssign(defaultValuesByAttribute.assertedEvents, new ArrayAssignments({
|
|
@@ -373,14 +366,12 @@ export class EditorState {
|
|
|
373
366
|
return puppeteer.page.url() || defaultValuesByAttribute.url;
|
|
374
367
|
}
|
|
375
368
|
case 'height': {
|
|
376
|
-
return (
|
|
377
|
-
|
|
378
|
-
defaultValuesByAttribute.height);
|
|
369
|
+
return puppeteer.page.evaluate(() => (visualViewport as VisualViewport).height)
|
|
370
|
+
.then(h => h || defaultValuesByAttribute.height);
|
|
379
371
|
}
|
|
380
372
|
case 'width': {
|
|
381
|
-
return (
|
|
382
|
-
|
|
383
|
-
defaultValuesByAttribute.width);
|
|
373
|
+
return puppeteer.page.evaluate(() => (visualViewport as VisualViewport).width)
|
|
374
|
+
.then(w => w || defaultValuesByAttribute.width);
|
|
384
375
|
}
|
|
385
376
|
default: {
|
|
386
377
|
return defaultValuesByAttribute[attribute];
|
|
@@ -389,11 +380,10 @@ export class EditorState {
|
|
|
389
380
|
});
|
|
390
381
|
}
|
|
391
382
|
|
|
392
|
-
static fromStep(step:
|
|
383
|
+
static fromStep(step: Models.Schema.Step): DeepImmutable<EditorState> {
|
|
393
384
|
const state = structuredClone(step) as EditorState;
|
|
394
385
|
for (const key of ['parameters', 'properties'] as Array<'properties'>) {
|
|
395
386
|
if (key in step && step[key] !== undefined) {
|
|
396
|
-
// @ts-expect-error Potential infinite type instantiation.
|
|
397
387
|
state[key] = JSON.stringify(step[key]);
|
|
398
388
|
}
|
|
399
389
|
}
|
|
@@ -458,212 +448,98 @@ export class EditorState {
|
|
|
458
448
|
* @fires RequestSelectorAttributeEvent#requestselectorattribute
|
|
459
449
|
* @fires StepEditedEvent#stepedited
|
|
460
450
|
*/
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
451
|
+
export interface ViewInput {
|
|
452
|
+
state: DeepImmutable<EditorState>;
|
|
453
|
+
disabled: boolean;
|
|
454
|
+
error: string|undefined;
|
|
455
|
+
isTypeEditable: boolean;
|
|
456
|
+
handleInputBlur: <A extends Attribute>(opts: {
|
|
457
|
+
attribute: A,
|
|
458
|
+
from(value: DataType<A>): DeepImmutable<DeepPartial<Assignments<EditorState>>>|undefined,
|
|
459
|
+
}) => (event: Event) => void;
|
|
460
|
+
handleTypeInputBlur: (event: Event) => Promise<void>;
|
|
461
|
+
handleAddRowClickEvent: (event: MouseEvent) => Promise<void>;
|
|
462
|
+
handleDeleteRowClick: (attribute: Attribute) => (event: MouseEvent) => void;
|
|
463
|
+
handleSelectorPicked: (data: Models.Schema.StepWithSelectors&
|
|
464
|
+
Pick<Models.Schema.ClickAttributes, 'offsetX'|'offsetY'>) => void;
|
|
465
|
+
handleAttributeRequested: (send: (attribute?: string) => void) => void;
|
|
466
|
+
handleAddOrRemoveClick: (assignments: DeepImmutable<DeepPartial<Assignments<EditorState>>>,
|
|
467
|
+
query: string) => (event: Event) => void;
|
|
468
|
+
handleKeyDownEvent: (event: Event) => void;
|
|
469
|
+
}
|
|
475
470
|
|
|
476
|
-
|
|
477
|
-
|
|
471
|
+
function renderInlineButton(
|
|
472
|
+
input: ViewInput, opts: {class: string, title: string, iconName: string, onClick: (event: MouseEvent) => void}):
|
|
473
|
+
Lit.TemplateResult|undefined {
|
|
474
|
+
if (input.disabled) {
|
|
475
|
+
return;
|
|
478
476
|
}
|
|
477
|
+
return html`
|
|
478
|
+
<devtools-button
|
|
479
|
+
title=${opts.title}
|
|
480
|
+
.accessibleLabel=${opts.title}
|
|
481
|
+
.size=${Buttons.Button.Size.SMALL}
|
|
482
|
+
.iconName=${opts.iconName}
|
|
483
|
+
.variant=${Buttons.Button.Variant.ICON}
|
|
484
|
+
jslog=${VisualLogging.action(opts.class).track({
|
|
485
|
+
click: true,
|
|
486
|
+
})}
|
|
487
|
+
class="inline-button ${opts.class}"
|
|
488
|
+
@click=${opts.onClick}
|
|
489
|
+
></devtools-button>
|
|
490
|
+
`;
|
|
491
|
+
}
|
|
479
492
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
return root;
|
|
493
|
+
function renderDeleteButton(input: ViewInput, attribute: Attribute): Lit.TemplateResult|undefined {
|
|
494
|
+
if (input.disabled) {
|
|
495
|
+
return;
|
|
484
496
|
}
|
|
485
497
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
498
|
+
const attributes = attributesByType[input.state.type];
|
|
499
|
+
const optional = [...attributes.optional].includes(attribute as typeof attributes.optional[number]);
|
|
500
|
+
if (!optional || input.disabled) {
|
|
501
|
+
return;
|
|
489
502
|
}
|
|
490
503
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
#handleSelectorPicked =
|
|
506
|
-
(data: Models.Schema.StepWithSelectors&Pick<Models.Schema.ClickAttributes, 'offsetX'|'offsetY'>): void => {
|
|
507
|
-
this.#commit(immutableDeepAssign(this.state, {
|
|
508
|
-
target: data.target,
|
|
509
|
-
frame: data.frame,
|
|
510
|
-
selectors: data.selectors.map(selector => typeof selector === 'string' ? [selector] : selector),
|
|
511
|
-
offsetX: data.offsetX,
|
|
512
|
-
offsetY: data.offsetY,
|
|
513
|
-
}));
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
#handleAttributeRequested = (send: (attribute?: string) => void): void => {
|
|
517
|
-
this.dispatchEvent(new RequestSelectorAttributeEvent(send));
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
#handleAddOrRemoveClick = (assignments: DeepImmutable<DeepPartial<Assignments<EditorState>>>, query: string):
|
|
521
|
-
((event: Event) => void) => event => {
|
|
522
|
-
event.preventDefault();
|
|
523
|
-
event.stopPropagation();
|
|
524
|
-
|
|
525
|
-
this.#commit(immutableDeepAssign(this.state, assignments));
|
|
526
|
-
|
|
527
|
-
this.#ensureFocus(query);
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
#handleKeyDownEvent = (event: Event): void => {
|
|
531
|
-
assert(event instanceof KeyboardEvent);
|
|
532
|
-
if (event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput && event.key === 'Enter') {
|
|
533
|
-
event.preventDefault();
|
|
534
|
-
event.stopPropagation();
|
|
535
|
-
const elements = this.renderRoot.querySelectorAll('devtools-suggestion-input');
|
|
536
|
-
const element = [...elements].findIndex(value => value === event.target);
|
|
537
|
-
if (element >= 0 && element + 1 < elements.length) {
|
|
538
|
-
elements[element + 1].focus();
|
|
539
|
-
} else {
|
|
540
|
-
event.target.blur();
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
#handleInputBlur = <A extends Attribute>(opts: {
|
|
546
|
-
attribute: A,
|
|
547
|
-
// If there are not assignments, then we should ignore the event.
|
|
548
|
-
from(this: StepEditor, value: DataType<A>): DeepImmutable<DeepPartial<Assignments<EditorState>>>|undefined,
|
|
549
|
-
}): ((event: Event) => void) => event => {
|
|
550
|
-
assert(event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput);
|
|
551
|
-
if (event.target.disabled) {
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
const dataType = dataTypeByAttribute[opts.attribute];
|
|
556
|
-
const value = typeConverters[dataType](event.target.value) as DataType<A>;
|
|
557
|
-
const assignments = opts.from.bind(this)(value);
|
|
558
|
-
if (!assignments) {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
this.#commit(immutableDeepAssign(this.state, assignments));
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
#handleTypeInputBlur = async(event: Event): Promise<void> => {
|
|
565
|
-
assert(event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput);
|
|
566
|
-
if (event.target.disabled) {
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const value = event.target.value as Models.Schema.StepType;
|
|
571
|
-
if (value === this.state.type) {
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
if (!Object.values(Models.Schema.StepType).includes(value)) {
|
|
575
|
-
this.error = i18nString(UIStrings.unknownActionType);
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
this.#commit(await EditorState.default(value));
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
#handleAddRowClickEvent = async(event: MouseEvent): Promise<void> => {
|
|
582
|
-
event.preventDefault();
|
|
583
|
-
event.stopPropagation();
|
|
584
|
-
|
|
585
|
-
const attribute = (event.target as HTMLElement).dataset.attribute as Attribute;
|
|
586
|
-
|
|
587
|
-
this.#commit(immutableDeepAssign(this.state, {
|
|
588
|
-
[attribute]: await EditorState.defaultByAttribute(this.state, attribute),
|
|
589
|
-
}));
|
|
590
|
-
|
|
591
|
-
this.#ensureFocus(`[data-attribute=${attribute}].attribute devtools-suggestion-input`);
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
#renderInlineButton(opts: {class: string, title: string, iconName: string, onClick: (event: MouseEvent) => void}):
|
|
595
|
-
Lit.TemplateResult|undefined {
|
|
596
|
-
if (this.disabled) {
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
return html`
|
|
600
|
-
<devtools-button
|
|
601
|
-
title=${opts.title}
|
|
602
|
-
.accessibleLabel=${opts.title}
|
|
603
|
-
.size=${Buttons.Button.Size.SMALL}
|
|
604
|
-
.iconName=${opts.iconName}
|
|
605
|
-
.variant=${Buttons.Button.Variant.ICON}
|
|
606
|
-
jslog=${VisualLogging.action(opts.class).track({
|
|
607
|
-
click: true,
|
|
608
|
-
})}
|
|
609
|
-
class="inline-button ${opts.class}"
|
|
610
|
-
@click=${opts.onClick}
|
|
611
|
-
></devtools-button>
|
|
612
|
-
`;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
#renderDeleteButton(attribute: Attribute): Lit.TemplateResult|undefined {
|
|
616
|
-
if (this.disabled) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const attributes = attributesByType[this.state.type];
|
|
621
|
-
const optional = [...attributes.optional].includes(attribute as typeof attributes.optional[number]);
|
|
622
|
-
if (!optional || this.disabled) {
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
504
|
+
// clang-format off
|
|
505
|
+
return html`<devtools-button
|
|
506
|
+
.size=${Buttons.Button.Size.SMALL}
|
|
507
|
+
.iconName=${'bin'}
|
|
508
|
+
.variant=${Buttons.Button.Variant.ICON}
|
|
509
|
+
.title=${i18nString(UIStrings.deleteRow)}
|
|
510
|
+
class="inline-button delete-row"
|
|
511
|
+
data-attribute=${attribute}
|
|
512
|
+
jslog=${VisualLogging.action('delete').track({click: true})}
|
|
513
|
+
@click=${input.handleDeleteRowClick(attribute)}
|
|
514
|
+
></devtools-button>`;
|
|
515
|
+
// clang-format on
|
|
516
|
+
}
|
|
625
517
|
|
|
626
|
-
|
|
627
|
-
return html`<devtools-button
|
|
628
|
-
.size=${Buttons.Button.Size.SMALL}
|
|
629
|
-
.iconName=${'bin'}
|
|
630
|
-
.variant=${Buttons.Button.Variant.ICON}
|
|
631
|
-
.title=${i18nString(UIStrings.deleteRow)}
|
|
632
|
-
class="inline-button delete-row"
|
|
633
|
-
data-attribute=${attribute}
|
|
634
|
-
jslog=${VisualLogging.action('delete').track({click: true})}
|
|
635
|
-
@click=${(event: MouseEvent) => {
|
|
636
|
-
event.preventDefault();
|
|
637
|
-
event.stopPropagation();
|
|
518
|
+
type View = (input: ViewInput, _output: undefined, target: HTMLElement) => void;
|
|
638
519
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
);
|
|
642
|
-
}}
|
|
643
|
-
></devtools-button>`;
|
|
644
|
-
// clang-format on
|
|
645
|
-
}
|
|
520
|
+
const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
521
|
+
const renderedAttributes = new Set<Attribute>();
|
|
646
522
|
|
|
647
|
-
|
|
648
|
-
|
|
523
|
+
function renderTypeRow(editable: boolean): Lit.TemplateResult {
|
|
524
|
+
renderedAttributes.add('type');
|
|
649
525
|
// clang-format off
|
|
650
526
|
return html`<div class="row attribute" data-attribute="type" jslog=${VisualLogging.treeItem('type').track({resize: true})}>
|
|
651
527
|
<div id="type">type<span class="separator">:</span></div>
|
|
652
528
|
<devtools-suggestion-input
|
|
653
529
|
aria-labelledby="type"
|
|
654
|
-
.disabled=${!editable ||
|
|
530
|
+
.disabled=${!editable || input.disabled}
|
|
655
531
|
.options=${Object.values(Models.Schema.StepType)}
|
|
656
532
|
.placeholder=${defaultValuesByAttribute.type}
|
|
657
|
-
.value=${live(
|
|
658
|
-
@blur=${
|
|
533
|
+
.value=${live(input.state.type)}
|
|
534
|
+
@blur=${input.handleTypeInputBlur}
|
|
659
535
|
></devtools-suggestion-input>
|
|
660
536
|
</div>`;
|
|
661
537
|
// clang-format on
|
|
662
538
|
}
|
|
663
539
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const attributeValue =
|
|
540
|
+
function renderRow(attribute: Attribute): Lit.TemplateResult|undefined {
|
|
541
|
+
renderedAttributes.add(attribute);
|
|
542
|
+
const attributeValue = input.state[attribute]?.toString();
|
|
667
543
|
if (attributeValue === undefined) {
|
|
668
544
|
return;
|
|
669
545
|
}
|
|
@@ -671,7 +547,7 @@ export class StepEditor extends LitElement {
|
|
|
671
547
|
return html`<div class="row attribute" data-attribute=${attribute} jslog=${VisualLogging.treeItem(Platform.StringUtilities.toKebabCase(attribute)).track({resize: true})}>
|
|
672
548
|
<div id=${attribute}>${attribute}<span class="separator">:</span></div>
|
|
673
549
|
<devtools-suggestion-input
|
|
674
|
-
.disabled=${
|
|
550
|
+
.disabled=${input.disabled}
|
|
675
551
|
aria-labelledby=${attribute}
|
|
676
552
|
.placeholder=${defaultValuesByAttribute[attribute].toString()}
|
|
677
553
|
.value=${live(attributeValue)}
|
|
@@ -685,24 +561,24 @@ export class StepEditor extends LitElement {
|
|
|
685
561
|
return '';
|
|
686
562
|
}
|
|
687
563
|
})()}
|
|
688
|
-
@blur=${
|
|
564
|
+
@blur=${input.handleInputBlur({
|
|
689
565
|
attribute,
|
|
690
566
|
from(value) {
|
|
691
|
-
if (
|
|
567
|
+
if (input.state[attribute] === undefined || input.state[attribute] === value) {
|
|
692
568
|
return;
|
|
693
569
|
}
|
|
694
570
|
return {[attribute]: value};
|
|
695
571
|
},
|
|
696
572
|
})}
|
|
697
573
|
></devtools-suggestion-input>
|
|
698
|
-
${
|
|
574
|
+
${renderDeleteButton(input, attribute)}
|
|
699
575
|
</div>`;
|
|
700
576
|
// clang-format on
|
|
701
577
|
}
|
|
702
578
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
if (
|
|
579
|
+
function renderFrameRow(): Lit.TemplateResult|undefined {
|
|
580
|
+
renderedAttributes.add('frame');
|
|
581
|
+
if (input.state.frame === undefined) {
|
|
706
582
|
return;
|
|
707
583
|
}
|
|
708
584
|
// clang-format off
|
|
@@ -710,21 +586,21 @@ export class StepEditor extends LitElement {
|
|
|
710
586
|
<div class="attribute" data-attribute="frame" jslog=${VisualLogging.treeItem('frame').track({resize: true})}>
|
|
711
587
|
<div class="row">
|
|
712
588
|
<div id="frame">frame<span class="separator">:</span></div>
|
|
713
|
-
${
|
|
589
|
+
${renderDeleteButton(input, 'frame')}
|
|
714
590
|
</div>
|
|
715
|
-
${
|
|
591
|
+
${input.state.frame.map((frame, index, frames) => {
|
|
716
592
|
return html`
|
|
717
593
|
<div class="padded row">
|
|
718
594
|
<devtools-suggestion-input
|
|
719
595
|
aria-labelledby="frame"
|
|
720
|
-
.disabled=${
|
|
596
|
+
.disabled=${input.disabled}
|
|
721
597
|
.placeholder=${defaultValuesByAttribute.frame[0].toString()}
|
|
722
598
|
.value=${live(frame.toString())}
|
|
723
599
|
data-path=${`frame.${index}`}
|
|
724
|
-
@blur=${
|
|
600
|
+
@blur=${input.handleInputBlur({
|
|
725
601
|
attribute: 'frame',
|
|
726
602
|
from(value) {
|
|
727
|
-
if (
|
|
603
|
+
if (input.state.frame?.[index] === undefined || input.state.frame[index] === value) {
|
|
728
604
|
return;
|
|
729
605
|
}
|
|
730
606
|
return {
|
|
@@ -733,11 +609,11 @@ export class StepEditor extends LitElement {
|
|
|
733
609
|
},
|
|
734
610
|
})}
|
|
735
611
|
></devtools-suggestion-input>
|
|
736
|
-
${
|
|
612
|
+
${renderInlineButton(input, {
|
|
737
613
|
class: 'add-frame',
|
|
738
614
|
title: i18nString(UIStrings.addFrameIndex),
|
|
739
615
|
iconName: 'plus',
|
|
740
|
-
onClick:
|
|
616
|
+
onClick: input.handleAddOrRemoveClick(
|
|
741
617
|
{
|
|
742
618
|
frame: new ArrayAssignments({
|
|
743
619
|
[index + 1]: new InsertAssignment(
|
|
@@ -748,11 +624,11 @@ export class StepEditor extends LitElement {
|
|
|
748
624
|
`devtools-suggestion-input[data-path="frame.${index + 1}"]`,
|
|
749
625
|
),
|
|
750
626
|
})}
|
|
751
|
-
${
|
|
627
|
+
${renderInlineButton(input, {
|
|
752
628
|
class: 'remove-frame',
|
|
753
629
|
title: i18nString(UIStrings.removeFrameIndex),
|
|
754
630
|
iconName: 'minus',
|
|
755
|
-
onClick:
|
|
631
|
+
onClick: input.handleAddOrRemoveClick(
|
|
756
632
|
{
|
|
757
633
|
frame: new ArrayAssignments({ [index]: undefined }),
|
|
758
634
|
},
|
|
@@ -770,9 +646,9 @@ export class StepEditor extends LitElement {
|
|
|
770
646
|
// clang-format on
|
|
771
647
|
}
|
|
772
648
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
if (
|
|
649
|
+
function renderSelectorsRow(): Lit.TemplateResult|undefined {
|
|
650
|
+
renderedAttributes.add('selectors');
|
|
651
|
+
if (input.state.selectors === undefined) {
|
|
776
652
|
return;
|
|
777
653
|
}
|
|
778
654
|
// clang-format off
|
|
@@ -780,20 +656,20 @@ export class StepEditor extends LitElement {
|
|
|
780
656
|
<div class="row">
|
|
781
657
|
<div>selectors<span class="separator">:</span></div>
|
|
782
658
|
${widget(SelectorPicker, {
|
|
783
|
-
disabled:
|
|
784
|
-
onSelectorPicked:
|
|
785
|
-
onAttributeRequested:
|
|
659
|
+
disabled: input.disabled,
|
|
660
|
+
onSelectorPicked: input.handleSelectorPicked,
|
|
661
|
+
onAttributeRequested: input.handleAttributeRequested,
|
|
786
662
|
})}
|
|
787
|
-
${
|
|
663
|
+
${renderDeleteButton(input, 'selectors')}
|
|
788
664
|
</div>
|
|
789
|
-
${
|
|
665
|
+
${input.state.selectors.map((selector, index, selectors) => {
|
|
790
666
|
return html`<div class="padded row" data-selector-path=${index}>
|
|
791
667
|
<div id="selector-${index}">selector #${index + 1}<span class="separator">:</span></div>
|
|
792
|
-
${
|
|
668
|
+
${renderInlineButton(input, {
|
|
793
669
|
class: 'add-selector',
|
|
794
670
|
title: i18nString(UIStrings.addSelector),
|
|
795
671
|
iconName: 'plus',
|
|
796
|
-
onClick:
|
|
672
|
+
onClick: input.handleAddOrRemoveClick(
|
|
797
673
|
{
|
|
798
674
|
selectors: new ArrayAssignments({
|
|
799
675
|
[index + 1]: new InsertAssignment(
|
|
@@ -804,11 +680,11 @@ export class StepEditor extends LitElement {
|
|
|
804
680
|
`devtools-suggestion-input[data-path="selectors.${index + 1}.0"]`,
|
|
805
681
|
),
|
|
806
682
|
})}
|
|
807
|
-
${
|
|
683
|
+
${renderInlineButton(input, {
|
|
808
684
|
class: 'remove-selector',
|
|
809
685
|
title: i18nString(UIStrings.removeSelector),
|
|
810
686
|
iconName: 'minus',
|
|
811
|
-
onClick:
|
|
687
|
+
onClick: input.handleAddOrRemoveClick(
|
|
812
688
|
{ selectors: new ArrayAssignments({ [index]: undefined }) },
|
|
813
689
|
`devtools-suggestion-input[data-path="selectors.${Math.min(
|
|
814
690
|
index,
|
|
@@ -824,15 +700,15 @@ export class StepEditor extends LitElement {
|
|
|
824
700
|
>
|
|
825
701
|
<devtools-suggestion-input
|
|
826
702
|
aria-labelledby="selector-${index}"
|
|
827
|
-
.disabled=${
|
|
703
|
+
.disabled=${input.disabled}
|
|
828
704
|
.placeholder=${defaultValuesByAttribute.selectors[0][0]}
|
|
829
705
|
.value=${live(part)}
|
|
830
706
|
data-path=${`selectors.${index}.${partIndex}`}
|
|
831
|
-
@blur=${
|
|
707
|
+
@blur=${input.handleInputBlur({
|
|
832
708
|
attribute: 'selectors',
|
|
833
709
|
from(value) {
|
|
834
710
|
if (
|
|
835
|
-
|
|
711
|
+
input.state.selectors?.[index]?.[partIndex] === undefined || input.state.selectors[index][partIndex] === value
|
|
836
712
|
) {
|
|
837
713
|
return;
|
|
838
714
|
}
|
|
@@ -846,11 +722,11 @@ export class StepEditor extends LitElement {
|
|
|
846
722
|
},
|
|
847
723
|
})}
|
|
848
724
|
></devtools-suggestion-input>
|
|
849
|
-
${
|
|
725
|
+
${renderInlineButton(input, {
|
|
850
726
|
class: 'add-selector-part',
|
|
851
727
|
title: i18nString(UIStrings.addSelectorPart),
|
|
852
728
|
iconName: 'plus',
|
|
853
|
-
onClick:
|
|
729
|
+
onClick: input.handleAddOrRemoveClick(
|
|
854
730
|
{
|
|
855
731
|
selectors: new ArrayAssignments({
|
|
856
732
|
[index]: new ArrayAssignments({
|
|
@@ -865,11 +741,11 @@ export class StepEditor extends LitElement {
|
|
|
865
741
|
}"]`,
|
|
866
742
|
),
|
|
867
743
|
})}
|
|
868
|
-
${
|
|
744
|
+
${renderInlineButton(input, {
|
|
869
745
|
class: 'remove-selector-part',
|
|
870
746
|
title: i18nString(UIStrings.removeSelectorPart),
|
|
871
747
|
iconName: 'minus',
|
|
872
|
-
onClick:
|
|
748
|
+
onClick: input.handleAddOrRemoveClick(
|
|
873
749
|
{
|
|
874
750
|
selectors: new ArrayAssignments({
|
|
875
751
|
[index]: new ArrayAssignments({
|
|
@@ -890,18 +766,18 @@ export class StepEditor extends LitElement {
|
|
|
890
766
|
// clang-format on
|
|
891
767
|
}
|
|
892
768
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
if (
|
|
769
|
+
function renderAssertedEvents(): Lit.TemplateResult|undefined {
|
|
770
|
+
renderedAttributes.add('assertedEvents');
|
|
771
|
+
if (input.state.assertedEvents === undefined) {
|
|
896
772
|
return;
|
|
897
773
|
}
|
|
898
774
|
// clang-format off
|
|
899
775
|
return html`<div class="attribute" data-attribute="assertedEvents" jslog=${VisualLogging.treeItem('asserted-events')}>
|
|
900
776
|
<div class="row">
|
|
901
777
|
<div>asserted events<span class="separator">:</span></div>
|
|
902
|
-
${
|
|
778
|
+
${renderDeleteButton(input, 'assertedEvents')}
|
|
903
779
|
</div>
|
|
904
|
-
${
|
|
780
|
+
${input.state.assertedEvents.map((event, index) => {
|
|
905
781
|
return html` <div class="padded row" jslog=${VisualLogging.treeItem('event-type')}>
|
|
906
782
|
<div id="event-type">type<span class="separator">:</span></div>
|
|
907
783
|
<div aria-labelledby="event-type">${event.type}</div>
|
|
@@ -910,13 +786,13 @@ export class StepEditor extends LitElement {
|
|
|
910
786
|
<div id="event-title">title<span class="separator">:</span></div>
|
|
911
787
|
<devtools-suggestion-input
|
|
912
788
|
aria-labelledby="event-title"
|
|
913
|
-
.disabled=${
|
|
789
|
+
.disabled=${input.disabled}
|
|
914
790
|
.placeholder=${defaultValuesByAttribute.assertedEvents[0].title}
|
|
915
791
|
.value=${live(event.title ?? '')}
|
|
916
|
-
@blur=${
|
|
792
|
+
@blur=${input.handleInputBlur({
|
|
917
793
|
attribute: 'assertedEvents',
|
|
918
794
|
from(value) {
|
|
919
|
-
if (
|
|
795
|
+
if (input.state.assertedEvents?.[index]?.title === undefined || input.state.assertedEvents[index].title === value) {
|
|
920
796
|
return;
|
|
921
797
|
}
|
|
922
798
|
return {
|
|
@@ -932,13 +808,13 @@ export class StepEditor extends LitElement {
|
|
|
932
808
|
<div>url<span class="separator">:</span></div>
|
|
933
809
|
<devtools-suggestion-input
|
|
934
810
|
aria-labelledby="event-url"
|
|
935
|
-
.disabled=${
|
|
811
|
+
.disabled=${input.disabled}
|
|
936
812
|
.placeholder=${defaultValuesByAttribute.assertedEvents[0].url}
|
|
937
813
|
.value=${live(event.url ?? '')}
|
|
938
|
-
@blur=${
|
|
814
|
+
@blur=${input.handleInputBlur({
|
|
939
815
|
attribute: 'url',
|
|
940
816
|
from(value) {
|
|
941
|
-
if (
|
|
817
|
+
if (input.state.assertedEvents?.[index]?.url === undefined || input.state.assertedEvents[index].url === value) {
|
|
942
818
|
return;
|
|
943
819
|
}
|
|
944
820
|
return {
|
|
@@ -955,29 +831,29 @@ export class StepEditor extends LitElement {
|
|
|
955
831
|
// clang-format on
|
|
956
832
|
}
|
|
957
833
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
if (
|
|
834
|
+
function renderAttributesRow(): Lit.TemplateResult|undefined {
|
|
835
|
+
renderedAttributes.add('attributes');
|
|
836
|
+
if (input.state.attributes === undefined) {
|
|
961
837
|
return;
|
|
962
838
|
}
|
|
963
839
|
// clang-format off
|
|
964
840
|
return html`<div class="attribute" data-attribute="attributes" jslog=${VisualLogging.treeItem('attributes')}>
|
|
965
841
|
<div class="row">
|
|
966
842
|
<div>attributes<span class="separator">:</span></div>
|
|
967
|
-
${
|
|
843
|
+
${renderDeleteButton(input, 'attributes')}
|
|
968
844
|
</div>
|
|
969
|
-
${
|
|
845
|
+
${input.state.attributes.map(({ name, value }, index, attributes) => {
|
|
970
846
|
return html`<div class="padded row" jslog=${VisualLogging.treeItem('attribute')}>
|
|
971
847
|
<devtools-suggestion-input
|
|
972
|
-
.disabled=${
|
|
848
|
+
.disabled=${input.disabled}
|
|
973
849
|
.placeholder=${defaultValuesByAttribute.attributes[0].name}
|
|
974
850
|
.value=${live(name)}
|
|
975
851
|
data-path=${`attributes.${index}.name`}
|
|
976
852
|
jslog=${VisualLogging.key().track({change: true})}
|
|
977
|
-
@blur=${
|
|
853
|
+
@blur=${input.handleInputBlur({
|
|
978
854
|
attribute: 'attributes',
|
|
979
855
|
from(name) {
|
|
980
|
-
if (
|
|
856
|
+
if (input.state.attributes?.[index]?.name === undefined || input.state.attributes[index].name === name) {
|
|
981
857
|
return;
|
|
982
858
|
}
|
|
983
859
|
return {
|
|
@@ -988,14 +864,14 @@ export class StepEditor extends LitElement {
|
|
|
988
864
|
></devtools-suggestion-input>
|
|
989
865
|
<span class="separator">:</span>
|
|
990
866
|
<devtools-suggestion-input
|
|
991
|
-
.disabled=${
|
|
867
|
+
.disabled=${input.disabled}
|
|
992
868
|
.placeholder=${defaultValuesByAttribute.attributes[0].value}
|
|
993
869
|
.value=${live(value)}
|
|
994
870
|
data-path=${`attributes.${index}.value`}
|
|
995
|
-
@blur=${
|
|
871
|
+
@blur=${input.handleInputBlur({
|
|
996
872
|
attribute: 'attributes',
|
|
997
873
|
from(value) {
|
|
998
|
-
if (
|
|
874
|
+
if (input.state.attributes?.[index]?.value === undefined || input.state.attributes[index].value === value) {
|
|
999
875
|
return;
|
|
1000
876
|
}
|
|
1001
877
|
return {
|
|
@@ -1004,11 +880,11 @@ export class StepEditor extends LitElement {
|
|
|
1004
880
|
},
|
|
1005
881
|
})}
|
|
1006
882
|
></devtools-suggestion-input>
|
|
1007
|
-
${
|
|
883
|
+
${renderInlineButton(input, {
|
|
1008
884
|
class: 'add-attribute-assertion',
|
|
1009
885
|
title: i18nString(UIStrings.addSelectorPart),
|
|
1010
886
|
iconName: 'plus',
|
|
1011
|
-
onClick:
|
|
887
|
+
onClick: input.handleAddOrRemoveClick(
|
|
1012
888
|
{
|
|
1013
889
|
attributes: new ArrayAssignments({
|
|
1014
890
|
[index + 1]: new InsertAssignment(
|
|
@@ -1036,11 +912,11 @@ export class StepEditor extends LitElement {
|
|
|
1036
912
|
}.name"]`,
|
|
1037
913
|
),
|
|
1038
914
|
})}
|
|
1039
|
-
${
|
|
915
|
+
${renderInlineButton(input, {
|
|
1040
916
|
class: 'remove-attribute-assertion',
|
|
1041
917
|
title: i18nString(UIStrings.removeSelectorPart),
|
|
1042
918
|
iconName: 'minus',
|
|
1043
|
-
onClick:
|
|
919
|
+
onClick: input.handleAddOrRemoveClick(
|
|
1044
920
|
{ attributes: new ArrayAssignments({ [index]: undefined }) },
|
|
1045
921
|
`devtools-suggestion-input[data-path="attributes.${Math.min(
|
|
1046
922
|
index,
|
|
@@ -1054,16 +930,16 @@ export class StepEditor extends LitElement {
|
|
|
1054
930
|
// clang-format on
|
|
1055
931
|
}
|
|
1056
932
|
|
|
1057
|
-
|
|
1058
|
-
const attributes = attributesByType[
|
|
1059
|
-
return [...attributes.optional].filter(attr =>
|
|
933
|
+
function renderAddRowButtons(): Array<Lit.TemplateResult|undefined> {
|
|
934
|
+
const attributes = attributesByType[input.state.type];
|
|
935
|
+
return [...attributes.optional].filter(attr => input.state[attr] === undefined).map(attr => {
|
|
1060
936
|
// clang-format off
|
|
1061
937
|
return html`<devtools-button
|
|
1062
938
|
.variant=${Buttons.Button.Variant.OUTLINED}
|
|
1063
939
|
class="add-row"
|
|
1064
940
|
data-attribute=${attr}
|
|
1065
941
|
jslog=${VisualLogging.action(`add-${Platform.StringUtilities.toKebabCase(attr)}`)}
|
|
1066
|
-
@click=${
|
|
942
|
+
@click=${input.handleAddRowClickEvent}
|
|
1067
943
|
>
|
|
1068
944
|
${i18nString(UIStrings.addAttribute, {
|
|
1069
945
|
attributeName: attr,
|
|
@@ -1073,63 +949,218 @@ export class StepEditor extends LitElement {
|
|
|
1073
949
|
});
|
|
1074
950
|
}
|
|
1075
951
|
|
|
952
|
+
// clang-format off
|
|
953
|
+
const result = html`
|
|
954
|
+
<style>${stepEditorStyles}</style>
|
|
955
|
+
<div class="wrapper" jslog=${VisualLogging.tree('step-editor')} >
|
|
956
|
+
${renderTypeRow(input.isTypeEditable)} ${renderRow('target')}
|
|
957
|
+
${renderFrameRow()} ${renderSelectorsRow()}
|
|
958
|
+
${renderRow('deviceType')} ${renderRow('button')}
|
|
959
|
+
${renderRow('url')} ${renderRow('x')}
|
|
960
|
+
${renderRow('y')} ${renderRow('offsetX')}
|
|
961
|
+
${renderRow('offsetY')} ${renderRow('value')}
|
|
962
|
+
${renderRow('key')} ${renderRow('operator')}
|
|
963
|
+
${renderRow('count')} ${renderRow('expression')}
|
|
964
|
+
${renderRow('duration')} ${renderAssertedEvents()}
|
|
965
|
+
${renderRow('timeout')} ${renderRow('width')}
|
|
966
|
+
${renderRow('height')} ${renderRow('deviceScaleFactor')}
|
|
967
|
+
${renderRow('isMobile')} ${renderRow('hasTouch')}
|
|
968
|
+
${renderRow('isLandscape')} ${renderRow('download')}
|
|
969
|
+
${renderRow('upload')} ${renderRow('latency')}
|
|
970
|
+
${renderRow('name')} ${renderRow('parameters')}
|
|
971
|
+
${renderRow('visible')} ${renderRow('properties')}
|
|
972
|
+
${renderAttributesRow()}
|
|
973
|
+
${input.error
|
|
974
|
+
? html`
|
|
975
|
+
<div class="error">
|
|
976
|
+
${i18nString(UIStrings.notSaved, {
|
|
977
|
+
error: input.error,
|
|
978
|
+
})}
|
|
979
|
+
</div>
|
|
980
|
+
`
|
|
981
|
+
: undefined}
|
|
982
|
+
${!input.disabled
|
|
983
|
+
? html`<div
|
|
984
|
+
class="row-buttons wrapped gap row regular-font no-margin"
|
|
985
|
+
>
|
|
986
|
+
${renderAddRowButtons()}
|
|
987
|
+
</div>`
|
|
988
|
+
: undefined}
|
|
989
|
+
</div>
|
|
990
|
+
`;
|
|
991
|
+
|
|
992
|
+
// clang-format on
|
|
993
|
+
for (const key of Object.keys(dataTypeByAttribute)) {
|
|
994
|
+
if (!renderedAttributes.has(key as Attribute)) {
|
|
995
|
+
throw new Error(`The editable attribute ${key} does not have UI`);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
render(result, target, {container: {listeners: {keydown: input.handleKeyDownEvent}}});
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
export class StepEditor extends UI.Widget.Widget {
|
|
1003
|
+
#state: DeepImmutable<EditorState>;
|
|
1004
|
+
#error: string|undefined;
|
|
1005
|
+
#isTypeEditable = true;
|
|
1006
|
+
#disabled = false;
|
|
1007
|
+
#view: View;
|
|
1008
|
+
|
|
1009
|
+
constructor(element?: HTMLElement, view = DEFAULT_VIEW) {
|
|
1010
|
+
super(element, {useShadowDom: true});
|
|
1011
|
+
this.#state = {type: Models.Schema.StepType.WaitForElement};
|
|
1012
|
+
this.#view = view;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
set isTypeEditable(value: boolean) {
|
|
1016
|
+
this.#isTypeEditable = value;
|
|
1017
|
+
this.requestUpdate();
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
set disabled(value: boolean) {
|
|
1021
|
+
this.#disabled = value;
|
|
1022
|
+
this.requestUpdate();
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
set step(step: Models.Schema.Step) {
|
|
1026
|
+
this.#state = deepFreeze(EditorState.fromStep(step));
|
|
1027
|
+
this.#error = undefined;
|
|
1028
|
+
this.requestUpdate();
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
override performUpdate(): void {
|
|
1032
|
+
const input: ViewInput = {
|
|
1033
|
+
state: this.#state,
|
|
1034
|
+
disabled: this.#disabled,
|
|
1035
|
+
error: this.#error,
|
|
1036
|
+
isTypeEditable: this.#isTypeEditable,
|
|
1037
|
+
handleInputBlur: this.#handleInputBlur,
|
|
1038
|
+
handleTypeInputBlur: this.#handleTypeInputBlur,
|
|
1039
|
+
handleAddRowClickEvent: this.#handleAddRowClickEvent,
|
|
1040
|
+
handleDeleteRowClick: this.#handleDeleteRowClick,
|
|
1041
|
+
handleSelectorPicked: this.#handleSelectorPicked,
|
|
1042
|
+
handleAttributeRequested: this.#handleAttributeRequested,
|
|
1043
|
+
handleAddOrRemoveClick: this.#handleAddOrRemoveClick,
|
|
1044
|
+
handleKeyDownEvent: this.#handleKeyDownEvent,
|
|
1045
|
+
};
|
|
1046
|
+
this.#view(input, undefined, this.contentElement);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
#commit(updatedState: DeepImmutable<EditorState>): void {
|
|
1050
|
+
try {
|
|
1051
|
+
this.element.dispatchEvent(new StepEditedEvent(EditorState.toStep(updatedState)));
|
|
1052
|
+
// Note we don't need to update this variable since it will come from up
|
|
1053
|
+
// the tree, but processing up the tree is asynchronous implying we cannot
|
|
1054
|
+
// reliably know when the state will come back down. Since we need to
|
|
1055
|
+
// focus the DOM elements that may be created as a result of this new
|
|
1056
|
+
// state, we set it here for waiting on the updateComplete promise later.
|
|
1057
|
+
this.#state = updatedState;
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
this.#error = error.message;
|
|
1060
|
+
}
|
|
1061
|
+
this.requestUpdate();
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
#handleSelectorPicked =
|
|
1065
|
+
(data: Models.Schema.StepWithSelectors&Pick<Models.Schema.ClickAttributes, 'offsetX'|'offsetY'>): void => {
|
|
1066
|
+
this.#commit(immutableDeepAssign(this.#state, {
|
|
1067
|
+
target: data.target,
|
|
1068
|
+
frame: data.frame,
|
|
1069
|
+
selectors: data.selectors.map(selector => typeof selector === 'string' ? [selector] : selector),
|
|
1070
|
+
offsetX: data.offsetX,
|
|
1071
|
+
offsetY: data.offsetY,
|
|
1072
|
+
}));
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
#handleAttributeRequested = (send: (attribute?: string) => void): void => {
|
|
1076
|
+
this.element.dispatchEvent(new RequestSelectorAttributeEvent(send));
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
#handleAddOrRemoveClick = (assignments: DeepImmutable<DeepPartial<Assignments<EditorState>>>,
|
|
1080
|
+
query: string): ((event: Event) => void) => event => {
|
|
1081
|
+
event.preventDefault();
|
|
1082
|
+
event.stopPropagation();
|
|
1083
|
+
|
|
1084
|
+
this.#commit(immutableDeepAssign(this.#state, assignments));
|
|
1085
|
+
|
|
1086
|
+
this.#ensureFocus(query);
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
#handleDeleteRowClick = (attribute: Attribute) => (event: Event): void => {
|
|
1090
|
+
event.preventDefault();
|
|
1091
|
+
event.stopPropagation();
|
|
1092
|
+
this.#commit(immutableDeepAssign(this.#state, {[attribute]: undefined}));
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1076
1095
|
#ensureFocus = (query: string): void => {
|
|
1077
1096
|
void this.updateComplete.then(() => {
|
|
1078
|
-
const node = this.
|
|
1097
|
+
const node = this.contentElement.querySelector<HTMLElement>(query);
|
|
1079
1098
|
node?.focus();
|
|
1080
1099
|
});
|
|
1081
1100
|
};
|
|
1082
1101
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1102
|
+
#handleKeyDownEvent = (event: Event): void => {
|
|
1103
|
+
assert(event instanceof KeyboardEvent);
|
|
1104
|
+
if (event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput && event.key === 'Enter') {
|
|
1105
|
+
event.preventDefault();
|
|
1106
|
+
event.stopPropagation();
|
|
1107
|
+
const elements = this.contentElement.querySelectorAll('devtools-suggestion-input');
|
|
1108
|
+
const element = [...elements].findIndex(value => value === event.target);
|
|
1109
|
+
if (element >= 0 && element + 1 < elements.length) {
|
|
1110
|
+
elements[element + 1].focus();
|
|
1111
|
+
} else {
|
|
1112
|
+
event.target.blur();
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1085
1116
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
${this.#renderRow('offsetY')} ${this.#renderRow('value')}
|
|
1096
|
-
${this.#renderRow('key')} ${this.#renderRow('operator')}
|
|
1097
|
-
${this.#renderRow('count')} ${this.#renderRow('expression')}
|
|
1098
|
-
${this.#renderRow('duration')} ${this.#renderAssertedEvents()}
|
|
1099
|
-
${this.#renderRow('timeout')} ${this.#renderRow('width')}
|
|
1100
|
-
${this.#renderRow('height')} ${this.#renderRow('deviceScaleFactor')}
|
|
1101
|
-
${this.#renderRow('isMobile')} ${this.#renderRow('hasTouch')}
|
|
1102
|
-
${this.#renderRow('isLandscape')} ${this.#renderRow('download')}
|
|
1103
|
-
${this.#renderRow('upload')} ${this.#renderRow('latency')}
|
|
1104
|
-
${this.#renderRow('name')} ${this.#renderRow('parameters')}
|
|
1105
|
-
${this.#renderRow('visible')} ${this.#renderRow('properties')}
|
|
1106
|
-
${this.#renderAttributesRow()}
|
|
1107
|
-
${this.error
|
|
1108
|
-
? html`
|
|
1109
|
-
<div class="error">
|
|
1110
|
-
${i18nString(UIStrings.notSaved, {
|
|
1111
|
-
error: this.error,
|
|
1112
|
-
})}
|
|
1113
|
-
</div>
|
|
1114
|
-
`
|
|
1115
|
-
: undefined}
|
|
1116
|
-
${!this.disabled
|
|
1117
|
-
? html`<div
|
|
1118
|
-
class="row-buttons wrapped gap row regular-font no-margin"
|
|
1119
|
-
>
|
|
1120
|
-
${this.#renderAddRowButtons()}
|
|
1121
|
-
</div>`
|
|
1122
|
-
: undefined}
|
|
1123
|
-
</div>
|
|
1124
|
-
`;
|
|
1117
|
+
#handleInputBlur = <A extends Attribute>(opts: {
|
|
1118
|
+
attribute: A,
|
|
1119
|
+
// If there are not assignments, then we should ignore the event.
|
|
1120
|
+
from(this: StepEditor, value: DataType<A>): DeepImmutable<DeepPartial<Assignments<EditorState>>>|undefined,
|
|
1121
|
+
}): ((event: Event) => void) => event => {
|
|
1122
|
+
assert(event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput);
|
|
1123
|
+
if (event.target.disabled) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1125
1126
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1127
|
+
const dataType = dataTypeByAttribute[opts.attribute];
|
|
1128
|
+
const value = typeConverters[dataType](event.target.value) as DataType<A>;
|
|
1129
|
+
const assignments = opts.from.bind(this)(value);
|
|
1130
|
+
if (!assignments) {
|
|
1131
|
+
return;
|
|
1131
1132
|
}
|
|
1133
|
+
this.#commit(immutableDeepAssign(this.#state, assignments));
|
|
1134
|
+
};
|
|
1132
1135
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1136
|
+
#handleTypeInputBlur = async(event: Event): Promise<void> => {
|
|
1137
|
+
assert(event.target instanceof SuggestionInput.SuggestionInput.SuggestionInput);
|
|
1138
|
+
if (event.target.disabled) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const value = event.target.value as Models.Schema.StepType;
|
|
1143
|
+
if (value === this.#state.type) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
if (!Object.values(Models.Schema.StepType).includes(value)) {
|
|
1147
|
+
this.#error = i18nString(UIStrings.unknownActionType);
|
|
1148
|
+
this.requestUpdate();
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
this.#commit(await EditorState.default(value));
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
#handleAddRowClickEvent = async(event: MouseEvent): Promise<void> => {
|
|
1155
|
+
event.preventDefault();
|
|
1156
|
+
event.stopPropagation();
|
|
1157
|
+
|
|
1158
|
+
const attribute = (event.target as HTMLElement).dataset.attribute as Attribute;
|
|
1159
|
+
|
|
1160
|
+
this.#commit(immutableDeepAssign(this.#state, {
|
|
1161
|
+
[attribute]: await EditorState.defaultByAttribute(this.#state, attribute),
|
|
1162
|
+
}));
|
|
1163
|
+
|
|
1164
|
+
this.#ensureFocus(`[data-attribute=${attribute}].attribute devtools-suggestion-input`);
|
|
1165
|
+
};
|
|
1135
1166
|
}
|