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
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ parameters:

orbs:
macos: circleci/macos@2.5.4
# android: circleci/android@3.1.0
codecov: codecov/codecov@5.4.3
codecov: codecov/codecov@6.0.0

executors:
base:
Expand Down
29 changes: 28 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ let excluded = ["ViewInspector", "UITests", "Tests", "BUILD"]

let playerUIDependency: Target.Dependency = .product(name: "PlayerUI", package: "playerui-swift-package")
let playerUILoggerDependency: Target.Dependency = .product(name: "PlayerUILogger", package: "playerui-swift-package")
let playerUISwiftUIDependency: Target.Dependency = .product(name: "PlayerUISwiftUI", package: "playerui-swift-package")
let swiftFlipperDependency: Target.Dependency = .product(name: "SwiftFlipper", package: "SwiftFlipper")

let utils: Target = .target(
Expand Down Expand Up @@ -105,6 +106,30 @@ let basicPlugin: Target = .target(
exclude: excluded
)

let baseProfilerDevtoolsPlugin: Target = .target(
name: "PlayerUIDevtoolsBaseProfilerDevtoolsPlugin",
dependencies: [
playerUIDependency,
playerUILoggerDependency,
"PlayerUIDevtoolsPlugin",
"PlayerUIDevtoolsUtilsSwiftUI"
],
path: "devtools/plugins/profiler/ios",
exclude: excluded,
resources: [.process("Resources")]
)

let profilerPlugin: Target = .target(
name: "PlayerUIDevtoolsProfilerPlugin",
dependencies: [
swiftFlipperDependency,
"PlayerUIDevtoolsSwiftUIPlugin",
"PlayerUIDevtoolsBaseProfilerDevtoolsPlugin"
],
path: "devtools/plugins/profiler/swiftui",
exclude: excluded
)

// --- END DECLARATIONS ---

let allTargets: [Target] = [
Expand All @@ -115,7 +140,9 @@ let allTargets: [Target] = [
plugin,
swiftUIPlugin,
baseBasicDevtoolsPlugin,
basicPlugin
basicPlugin,
baseProfilerDevtoolsPlugin,
profilerPlugin
]

// This is the Package.swift for our SPM release.
Expand Down
3 changes: 3 additions & 0 deletions devtools/plugin/core/src/helpers/getNowTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const getNowTime = globalThis.performance
? () => globalThis.performance.now()
: () => Date.now();
Comment on lines +1 to +3

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

performance isn't available on the ios and kotlin integrations, so it's preferred for accuracy but Date.now still works.

1 change: 1 addition & 0 deletions devtools/plugin/core/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { generateUUID } from "./uuid";
export { genDataChangeTransaction } from "./genDataChangeTransaction";
export { getNowTime } from "./getNowTime";
9 changes: 4 additions & 5 deletions devtools/plugin/core/src/helpers/uuid.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { getNowTime } from "./getNowTime";

// TODO: Either polyfill crypto or use this (pulled from SO)
export function generateUUID(): string {
// Public Domain/MIT
let d = new Date().getTime(); //Timestamp
let d2 =
(typeof performance !== "undefined" &&
performance.now &&
performance.now() * 1000) ||
0; //Time in microseconds since page-load or 0 if unsupported
let d2 = getNowTime() * 1000;
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
let r = Math.random() * 16; //random number between 0 and 16
if (d > 0) {
Expand Down
34 changes: 34 additions & 0 deletions devtools/plugins/profiler/android/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Android lib that consumes jvm similar to how react consumes core
load("@rules_jvm_external//:defs.bzl", "artifact")
load("//helpers:android.bzl", "kt_android")

main_exports = [
"//devtools/plugin/android:plugin-android",
]

main_deps = main_exports + [
"//devtools/plugins/profiler/jvm:profiler-plugin",
]

main_resources = []

test_deps = [
"//helpers:kotlin_serialization",
artifact("com.intuit.playerui:testutils"),
artifact("com.intuit.playerui:j2v8-all"),
]

kt_android(
name = "profiler-android",
group = "com.intuit.playerui.plugins.devtools.profiler",
main_deps = main_deps,
main_exports = main_exports,
main_resources = main_resources,
unit_test_deps = test_deps,
unit_test_package = "com.intuit.playerui.plugins.devtools.profiler",
)

alias(
name = "android",
actual = "profiler-android",
)
14 changes: 14 additions & 0 deletions devtools/plugins/profiler/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<manifest package="com.intuit.playerui.plugins.devtools.profiler"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-sdk android:minSdkVersion="24" />

<!-- Resolve a conflict issue while building with Bazel. -->
<application>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.intuit.playerui.plugins.devtools.profiler

import androidx.annotation.StyleRes
import com.intuit.playerui.android.AndroidPlayer
import com.intuit.playerui.core.bridge.runtime.Runtime
import com.intuit.playerui.devtools.AndroidDevtoolsPlugin
import com.intuit.playerui.plugins.devtools.profiler.ProfilerDevtoolsPlugin.Module.ProfilerDevtoolsPlugin

public class ProfilerAndroidDevtoolsPlugin(
private val id: String,
@StyleRes private val overlayStyle: Int? = R.style.ProfilerAndroidDevtoolsPlugin,
) : AndroidDevtoolsPlugin<ProfilerDevtoolsPlugin>() {
override fun Runtime<*>.buildCorePlugin(): ProfilerDevtoolsPlugin =
ProfilerDevtoolsPlugin(
ProfilerDevtoolsPlugin.Options(id, this@ProfilerAndroidDevtoolsPlugin),
)

override fun apply(androidPlayer: AndroidPlayer) {
if (!checkIfDevtoolsIsActive()) return

super.apply(androidPlayer)

overlayStyle?.let(::listOf)?.let {
androidPlayer.hooks.context.tap(this::class.simpleName!!) { _, context ->
androidPlayer.getCachedStyledContext(context, it)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="ProfilerAndroidDevtoolsPlugin">
<item name="android:background">#330000FF</item>
</style>
</resources>
47 changes: 47 additions & 0 deletions devtools/plugins/profiler/content/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@rules_player//javascript:defs.bzl", "js_pipeline")
load("@rules_player//player:defs.bzl", "dsl_compile", create_base_dsl_config = "create_base_config")
load("//helpers:defs.bzl", "tsup_config", "vitest_config")

npm_link_all_packages(name = "node_modules")

tsup_config(name = "tsup_config")

vitest_config(name = "vitest_config")

create_base_dsl_config(
name = "dsl_config",
presets = [],
)

entrypoint = ["src/flow.tsx"]

dsl_compile(
name = "compiled_flow",
srcs = entrypoint,
config = ":dsl_config",
data = glob(
["src/**"],
entrypoint,
) + [
"//:node_modules/@devtools-ui/plugin",
"//:node_modules/@player-tools/dsl",
"//:node_modules/@player-ui/common-types-plugin",
"//:node_modules/react",
],
input_dir = "src",
output_dir = "_generated",
skip_test = True,
)

js_pipeline(
package_name = "@player-devtools/profiler-plugin-content",
srcs = [
"src/constants.ts",
"src/index.ts",
":compiled_flow",
],
deps = [
":node_modules/@player-devtools/types",
],
)
8 changes: 8 additions & 0 deletions devtools/plugins/profiler/content/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@player-devtools/profiler-plugin-content",
"version": "0.0.0-PLACEHOLDER",
"main": "src/index.ts",
"dependencies": {
"@player-devtools/types": "workspace:*"
}
}
30 changes: 30 additions & 0 deletions devtools/plugins/profiler/content/src/common/ProfilerFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import { Collection, Action, Text } from "@devtools-ui/plugin";
import { expression as e } from "@player-tools/dsl";
import type { Expression } from "@player-tools/dsl";
import { INTERACTIONS } from "../constants";
import { bindings } from "../schema";

const toggleProfiling = e`conditional(${bindings.profiling} === true, publish('${INTERACTIONS.STOP_PROFILING}'), publish('${INTERACTIONS.START_PROFILING}'))`;

const toggleLabel = e`conditional(${bindings.profiling} === true, 'Stop', 'Start')`;

const reset = e`publish('${INTERACTIONS.RESET_PROFILING}')`;

/** Shared footer with a Start/Stop toggle and a Reset action. */
export const ProfilerFooter = (
<Collection>
<Collection.Values>
<Action exp={toggleProfiling as Expression}>
<Action.Label>
<Text>{toggleLabel}</Text>
</Action.Label>
</Action>
<Action exp={reset as Expression}>
<Action.Label>
<Text>Reset</Text>
</Action.Label>
</Action>
</Collection.Values>
</Collection>
);
41 changes: 41 additions & 0 deletions devtools/plugins/profiler/content/src/common/Screen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from "react";
import { Navigation, Action, Text, StackedView } from "@devtools-ui/plugin";
import { VIEWS_IDS } from "../constants";

/** Display labels for the navigation actions, keyed by view id. */
const NAV_LABELS: Record<string, string> = {
[VIEWS_IDS.PROFILE]: "Flame Graph",
[VIEWS_IDS.RAW]: "Raw",
};

const Nav = () => (
<Navigation>
<Navigation.Values>
{Object.values(VIEWS_IDS).map((viewId) => (
<Action key={viewId} value={viewId}>
<Action.Label>
<Text>{NAV_LABELS[viewId] ?? viewId}</Text>
</Action.Label>
</Action>
))}
</Navigation.Values>
</Navigation>
);

export const Screen = ({
main,
footer,
id,
}: {
id: string;
main: React.ReactNode;
footer?: React.ReactNode;
}) => (
<StackedView id={id}>
<StackedView.Header>
<Nav />
</StackedView.Header>
<StackedView.Main>{main}</StackedView.Main>
{footer && <StackedView.Footer>{footer}</StackedView.Footer>}
</StackedView>
);
2 changes: 2 additions & 0 deletions devtools/plugins/profiler/content/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./Screen";
export * from "./ProfilerFooter";
12 changes: 12 additions & 0 deletions devtools/plugins/profiler/content/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const PLUGIN_ID = "player-ui-profiler-plugin";

export const VIEWS_IDS = {
PROFILE: "Profile",
RAW: "Raw",
};

export const INTERACTIONS = {
START_PROFILING: "start-profiling",
STOP_PROFILING: "stop-profiling",
RESET_PROFILING: "reset-profiling",
};
19 changes: 19 additions & 0 deletions devtools/plugins/profiler/content/src/flow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { PLUGIN_ID } from "./constants";
import { navigation } from "./navigation";
import { schema } from "./schema";
import { views } from "./views";

export default {
id: PLUGIN_ID,
views,
navigation,
schema,
data: {
profiling: false,
displayFlameGraph: false,
rootNode: {
value: 0,
},
rawNodes: [],
},
};
22 changes: 22 additions & 0 deletions devtools/plugins/profiler/content/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { PluginData } from "@player-devtools/types";
import { PLUGIN_ID } from "./constants";

// Generated via dsl_compile target
import flow from "../_generated/flow.json";

declare global {
const __VERSION__: string;
}

const PLUGIN_VERSION =
typeof __VERSION__ !== "undefined" ? __VERSION__ : "unstamped";

export const ProfilerPluginData: PluginData = {
id: PLUGIN_ID,
name: "Player UI Profiler",
description: "Standard Player UI Profiler",
version: PLUGIN_VERSION,
flow,
};

export * from "./constants";
27 changes: 27 additions & 0 deletions devtools/plugins/profiler/content/src/navigation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { VIEWS_IDS } from "../constants";

const transitions = Object.entries(VIEWS_IDS).reduce(
(acc, [key, value]) => ({
...acc,
[value]: key,
}),
{} as Record<string, string>,
);

export const navigation = {
BEGIN: "Plugin",
Plugin: {
startState: Object.keys(VIEWS_IDS)[0],
...Object.entries(VIEWS_IDS).reduce(
(acc, [key, value]) => ({
...acc,
[key]: {
state_type: "VIEW",
ref: value,
transitions,
},
}),
{} as Record<string, unknown>,
),
},
};
Loading