Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/gni/devtools_grd_files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,6 @@ grd_files_release_sources = [
"front_end/panels/recorder/recorder-meta.js",
"front_end/panels/recorder/recorder.js",
"front_end/panels/recorder/util/util.js",
"front_end/panels/rn_welcome/ReactNativeApplicationModel.js",
"front_end/panels/rn_welcome/rn_welcome-legacy-meta.js",
"front_end/panels/rn_welcome/rn_welcome-meta.js",
"front_end/panels/rn_welcome/rn_welcome.js",
Expand Down Expand Up @@ -787,6 +786,7 @@ grd_files_debug_sources = [
"front_end/core/sdk/PerformanceMetricsModel.js",
"front_end/core/sdk/PreloadingModel.js",
"front_end/core/sdk/ProfileTreeModel.js",
"front_end/core/sdk/ReactNativeApplicationModel.js",
"front_end/core/sdk/RemoteObject.js",
"front_end/core/sdk/Resource.js",
"front_end/core/sdk/ResourceTreeModel.js",
Expand Down
1 change: 1 addition & 0 deletions front_end/core/sdk/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ devtools_module("sdk") {
"PreloadingModel.ts",
"ProfileTreeModel.ts",
"RemoteObject.ts",
"ReactNativeApplicationModel.ts",
"Resource.ts",
"ResourceTreeModel.ts",
"RuntimeModel.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as SDK from '../../core/sdk/sdk.js';

import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
import type * as Protocol from '../../generated/protocol.js';

export class ReactNativeApplicationModel extends SDK.SDKModel.SDKModel<EventTypes> implements ProtocolProxyApi.ReactNativeApplicationDispatcher {
private enabled: boolean;
private readonly agent: ProtocolProxyApi.ReactNativeApplicationApi;
import {Capability, type Target} from './Target.js';
import {SDKModel} from './SDKModel.js';

export class ReactNativeApplicationModel extends SDKModel<EventTypes> implements ProtocolProxyApi.ReactNativeApplicationDispatcher {
#enabled: boolean;
readonly #agent: ProtocolProxyApi.ReactNativeApplicationApi;

metadataCached: Protocol.ReactNativeApplication.MetadataUpdatedEvent | null = null;

constructor(target: SDK.Target.Target) {
constructor(target: Target) {
super(target);

this.enabled = false;
this.agent = target.reactNativeApplicationAgent();
this.#enabled = false;
this.#agent = target.reactNativeApplicationAgent();
target.registerReactNativeApplicationDispatcher(this);
}

ensureEnabled(): void {
if (this.enabled) {
if (this.#enabled) {
return;
}

void this.agent.invoke_enable();
this.enabled = true;
void this.#agent.invoke_enable();
this.#enabled = true;
}

metadataUpdated(metadata: Protocol.ReactNativeApplication.MetadataUpdatedEvent): void {
this.metadataCached = metadata;
this.dispatchEventToListeners(Events.MetadataUpdated, metadata);
}
}
Expand All @@ -42,10 +46,10 @@ export type EventTypes = {
[Events.MetadataUpdated]: Protocol.ReactNativeApplication.MetadataUpdatedEvent,
};

SDK.SDKModel.SDKModel.register(
SDKModel.register(
ReactNativeApplicationModel,
{
capabilities: SDK.Target.Capability.None,
capabilities: Capability.None,
autostart: true,
},
);
2 changes: 2 additions & 0 deletions front_end/core/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import * as PaintProfiler from './PaintProfiler.js';
import * as PerformanceMetricsModel from './PerformanceMetricsModel.js';
import * as PreloadingModel from './PreloadingModel.js';
import * as ProfileTreeModel from './ProfileTreeModel.js';
import * as ReactNativeApplicationModel from './ReactNativeApplicationModel.js';
import * as RemoteObject from './RemoteObject.js';
import * as Resource from './Resource.js';
import * as ResourceTreeModel from './ResourceTreeModel.js';
Expand Down Expand Up @@ -136,6 +137,7 @@ export {
PerformanceMetricsModel,
PreloadingModel,
ProfileTreeModel,
ReactNativeApplicationModel,
RemoteObject,
Resource,
ResourceTreeModel,
Expand Down
31 changes: 31 additions & 0 deletions front_end/entrypoints/rn_fusebox/rn_fusebox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import * as SDK from '../../core/sdk/sdk.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as Main from '../main/main.js';

import type * as Common from '../../core/common/common.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as Protocol from '../../generated/protocol.js';
import type * as Sources from '../../panels/sources/sources.js';
import * as RNExperiments from '../../core/rn_experiments/rn_experiments.js';

Expand Down Expand Up @@ -222,4 +224,33 @@ UI.Toolbar.registerToolbarItem({
},
});

class FuseboxReactNativeApplicationObserver implements
SDK.TargetManager.SDKModelObserver<SDK.ReactNativeApplicationModel.ReactNativeApplicationModel> {
constructor(targetManager: SDK.TargetManager.TargetManager) {
targetManager.observeModels(SDK.ReactNativeApplicationModel.ReactNativeApplicationModel, this);
}

modelAdded(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.ensureEnabled();
model.addEventListener(SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
}

modelRemoved(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.removeEventListener(
SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
}

#handleMetadataUpdated(
event: Common.EventTarget.EventTargetEvent<Protocol.ReactNativeApplication.MetadataUpdatedEvent>): void {
const {appDisplayName, deviceName} = event.data;

// Update window title
if (appDisplayName != null && deviceName != null) {
document.title = `${appDisplayName} (${deviceName}) - React Native DevTools`;
}
}
}

new FuseboxReactNativeApplicationObserver(SDK.TargetManager.TargetManager.instance());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior art for this pattern under front_end/entrypoints/: ExecutionContextSelector.


Host.rnPerfMetrics.entryPointLoadingFinished('rn_fusebox');
1 change: 0 additions & 1 deletion front_end/panels/rn_welcome/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ generate_css("css_files") {
devtools_module("rn_welcome") {
sources = [
"RNWelcome.ts",
"ReactNativeApplicationModel.ts",
]

deps = [
Expand Down
51 changes: 24 additions & 27 deletions front_end/panels/rn_welcome/RNWelcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import rnWelcomeStyles from './rnWelcome.css.js';
import * as LitHtml from '../../ui/lit-html/lit-html.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as Protocol from '../../generated/protocol.js';
import {Events as ModelEvents, ReactNativeApplicationModel} from './ReactNativeApplicationModel.js';

const UIStrings = {
/** @description Beta label */
Expand Down Expand Up @@ -53,10 +52,11 @@ type RNWelcomeOptions = {
showDocs?: boolean
};

export class RNWelcomeImpl extends UI.Widget.VBox implements SDK.TargetManager.SDKModelObserver<ReactNativeApplicationModel> {
export class RNWelcomeImpl extends UI.Widget.VBox implements
SDK.TargetManager.SDKModelObserver<SDK.ReactNativeApplicationModel.ReactNativeApplicationModel> {
private readonly options: RNWelcomeOptions;

private reactNativeVersion: string | undefined;
#reactNativeVersion: string|undefined;

static instance(options: RNWelcomeOptions): RNWelcomeImpl {
if (!rnWelcomeImplInstance) {
Expand All @@ -70,7 +70,8 @@ export class RNWelcomeImpl extends UI.Widget.VBox implements SDK.TargetManager.S

this.options = options;

SDK.TargetManager.TargetManager.instance().observeModels(ReactNativeApplicationModel, this);
SDK.TargetManager.TargetManager.instance().observeModels(
SDK.ReactNativeApplicationModel.ReactNativeApplicationModel, this);
}

override wasShown(): void {
Expand All @@ -80,35 +81,31 @@ export class RNWelcomeImpl extends UI.Widget.VBox implements SDK.TargetManager.S
UI.InspectorView.InspectorView.instance().showDrawer({focus: true, hasTargetDrawer: false});
}

modelAdded(model: ReactNativeApplicationModel): void {
if (this.isShowing()) {
model.ensureEnabled();
model.addEventListener(ModelEvents.MetadataUpdated, this._updateReactNativeVersion, this);
}
}

modelRemoved(model: ReactNativeApplicationModel): void {
model.removeEventListener(ModelEvents.MetadataUpdated, this._updateReactNativeVersion, this);
modelAdded(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.ensureEnabled();
model.addEventListener(
SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
this.#reactNativeVersion = model.metadataCached?.reactNativeVersion;
}

private _handleLinkPress(url: string): void {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(
url as Platform.DevToolsPath.UrlString,
);
modelRemoved(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.removeEventListener(
SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
}

private _updateReactNativeVersion(event: Common.EventTarget.EventTargetEvent<Protocol.ReactNativeApplication.MetadataUpdatedEvent>): void {
const {appDisplayName, deviceName, reactNativeVersion} = event.data;
#handleMetadataUpdated(
event: Common.EventTarget.EventTargetEvent<Protocol.ReactNativeApplication.MetadataUpdatedEvent>): void {
this.#reactNativeVersion = event.data.reactNativeVersion;

if (reactNativeVersion != null) {
this.reactNativeVersion = reactNativeVersion;
if (this.isShowing()) {
this.render();
}
}

// Side-effect: Update window title
if (appDisplayName != null && deviceName != null) {
document.title = `${appDisplayName} (${deviceName}) - React Native DevTools`;
}
private _handleLinkPress(url: string): void {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(
url as Platform.DevToolsPath.UrlString,
);
}

render(): void {
Expand Down Expand Up @@ -153,8 +150,8 @@ export class RNWelcomeImpl extends UI.Widget.VBox implements SDK.TargetManager.S
${i18nString(UIStrings.whatsNewLabel)}
</x-link>
</div>
${this.reactNativeVersion != null ? html`
<p class="rn-welcome-version">React Native: <code>${this.reactNativeVersion}</code></p>
${this.#reactNativeVersion != null ? html`
<p class="rn-welcome-version">React Native: <code>${this.#reactNativeVersion}</code></p>
` : null}
</header>
${showDocs ? html`
Expand Down