@gooddata/create-pluggable-module 11.43.0-alpha.3 → 11.43.0-alpha.5
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.
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
2
|
|
|
3
|
+
import { version as reactVersion } from "react";
|
|
4
|
+
|
|
3
5
|
import { render, screen } from "@testing-library/react";
|
|
4
6
|
import { IntlProvider } from "react-intl";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
7
|
+
import { describe, expect, it, vi } from "vitest";
|
|
6
8
|
|
|
9
|
+
import {
|
|
10
|
+
type IPluggableAppTelemetryCallbacks,
|
|
11
|
+
LIB_VERSION as sdkVersion,
|
|
12
|
+
} from "@gooddata/sdk-pluggable-application-model";
|
|
7
13
|
import { BackendProvider } from "@gooddata/sdk-ui";
|
|
8
14
|
import { type IClientPlatformContext, PlatformContextProvider } from "@gooddata/sdk-ui-pluggable-application";
|
|
9
15
|
|
|
10
16
|
import { App } from "./App.js";
|
|
17
|
+
import { reportPageView } from "./pluggableApp.js";
|
|
11
18
|
|
|
12
19
|
function createMockCtx(): IClientPlatformContext {
|
|
13
20
|
return {
|
|
@@ -50,4 +57,43 @@ describe("App", () => {
|
|
|
50
57
|
renderWithProviders(<App />);
|
|
51
58
|
expect(screen.getByText(/test@example.com/)).toBeTruthy();
|
|
52
59
|
});
|
|
60
|
+
|
|
61
|
+
it("reports one page view carrying the module React / SDK versions and the workspace id", () => {
|
|
62
|
+
const trackPageView = vi.fn();
|
|
63
|
+
const onTelemetryEvent: IPluggableAppTelemetryCallbacks = {
|
|
64
|
+
trackEvent: vi.fn(),
|
|
65
|
+
trackPageView,
|
|
66
|
+
trackTiming: vi.fn(),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
reportPageView(onTelemetryEvent, "ws-1");
|
|
70
|
+
|
|
71
|
+
expect(trackPageView).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(trackPageView).toHaveBeenCalledWith("gdc-app-template-name", {
|
|
73
|
+
moduleReactVersion: reactVersion,
|
|
74
|
+
moduleSdkVersion: sdkVersion,
|
|
75
|
+
identifiers: { workspaceId: "ws-1" },
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("reports a page view without identifiers for an organization-scoped app", () => {
|
|
80
|
+
const trackPageView = vi.fn();
|
|
81
|
+
const onTelemetryEvent: IPluggableAppTelemetryCallbacks = {
|
|
82
|
+
trackEvent: vi.fn(),
|
|
83
|
+
trackPageView,
|
|
84
|
+
trackTiming: vi.fn(),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
reportPageView(onTelemetryEvent, undefined);
|
|
88
|
+
|
|
89
|
+
expect(trackPageView).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(trackPageView).toHaveBeenCalledWith("gdc-app-template-name", {
|
|
91
|
+
moduleReactVersion: reactVersion,
|
|
92
|
+
moduleSdkVersion: sdkVersion,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("no-ops when the host supplies no telemetry callbacks (standalone run)", () => {
|
|
97
|
+
expect(() => reportPageView(undefined, "ws-1")).not.toThrow();
|
|
98
|
+
});
|
|
53
99
|
});
|
|
@@ -4,7 +4,7 @@ import { FormattedMessage } from "react-intl";
|
|
|
4
4
|
|
|
5
5
|
import { type IPluggableAppEvent } from "@gooddata/sdk-pluggable-application-model";
|
|
6
6
|
import { useWorkspace } from "@gooddata/sdk-ui";
|
|
7
|
-
import { usePlatformContextStrict
|
|
7
|
+
import { usePlatformContextStrict } from "@gooddata/sdk-ui-pluggable-application";
|
|
8
8
|
|
|
9
9
|
interface IAppProps {
|
|
10
10
|
onEvent?: (e: IPluggableAppEvent) => void;
|
|
@@ -13,7 +13,10 @@ interface IAppProps {
|
|
|
13
13
|
export function App({ onEvent: _onEvent }: IAppProps) {
|
|
14
14
|
const ctx = usePlatformContextStrict();
|
|
15
15
|
const workspaceId = useWorkspace();
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
// The mount page view that reports this module's React / SDK versions is fired once per lifecycle
|
|
18
|
+
// in pluggableApp.tsx. To send telemetry from inside the app (e.g. on a user action), pull the
|
|
19
|
+
// host callbacks with `usePluggableAppTelemetry()` and call `trackEvent` / `trackTiming`.
|
|
17
20
|
|
|
18
21
|
return (
|
|
19
22
|
<div style={{ display: "flex", flexDirection: "column", padding: "4rem" }}>
|
|
@@ -13,11 +13,37 @@ import {
|
|
|
13
13
|
type IPluggableApplicationMountOptions,
|
|
14
14
|
LIB_VERSION as moduleSdkVersion,
|
|
15
15
|
} from "@gooddata/sdk-pluggable-application-model";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
PluggableAppTelemetryProvider,
|
|
18
|
+
enrichTelemetryCallbacks,
|
|
19
|
+
} from "@gooddata/sdk-ui-pluggable-application";
|
|
17
20
|
|
|
18
21
|
import { App } from "./App.js";
|
|
19
22
|
import { AppProviders } from "./AppProviders.js";
|
|
20
23
|
|
|
24
|
+
// Page id reported on mount. The scaffolder rewrites the `gdc-app-template-name` token to your
|
|
25
|
+
// module's id when generating the project, so this becomes your app's name automatically — rename
|
|
26
|
+
// it if you want a different page id.
|
|
27
|
+
const TELEMETRY_PAGE = "gdc-app-template-name";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Report one page view stamped with this module's React / SDK versions — the page-scoped custom
|
|
31
|
+
* variables the host records as `moduleReactVersion` / `moduleSdkVersion`, so a single page view per
|
|
32
|
+
* lifecycle is enough to attribute the module's runtime.
|
|
33
|
+
*
|
|
34
|
+
* Fired here from the mount lifecycle rather than from a React effect inside `<App/>`: AppProviders
|
|
35
|
+
* briefly unmounts its children while an async locale bundle loads, so an effect-based page view
|
|
36
|
+
* would re-fire on that remount. The workspace id (when this app is workspace-scoped) rides along as
|
|
37
|
+
* a neutral `identifiers` entry so the host keeps the page view's workspace attribution.
|
|
38
|
+
*/
|
|
39
|
+
export function reportPageView(
|
|
40
|
+
onTelemetryEvent: IPluggableAppTelemetryCallbacks | undefined,
|
|
41
|
+
workspaceId: string | undefined,
|
|
42
|
+
) {
|
|
43
|
+
const telemetry = enrichTelemetryCallbacks(onTelemetryEvent, { moduleReactVersion, moduleSdkVersion });
|
|
44
|
+
telemetry?.trackPageView(TELEMETRY_PAGE, workspaceId ? { identifiers: { workspaceId } } : undefined);
|
|
45
|
+
}
|
|
46
|
+
|
|
21
47
|
function renderApp(
|
|
22
48
|
root: Root,
|
|
23
49
|
ctx: IPlatformContext,
|
|
@@ -53,6 +79,9 @@ export const pluggableApp: IPluggableApp = {
|
|
|
53
79
|
const root = createRoot(container);
|
|
54
80
|
|
|
55
81
|
renderApp(root, ctx, basePath, onEvent, onTelemetryEvent);
|
|
82
|
+
reportPageView(onTelemetryEvent, ctx.currentWorkspaceId);
|
|
83
|
+
|
|
84
|
+
let previousWorkspaceId = ctx.currentWorkspaceId;
|
|
56
85
|
|
|
57
86
|
return {
|
|
58
87
|
unmount() {
|
|
@@ -60,6 +89,12 @@ export const pluggableApp: IPluggableApp = {
|
|
|
60
89
|
},
|
|
61
90
|
updateContext(nextCtx: IPlatformContext) {
|
|
62
91
|
renderApp(root, nextCtx, basePath, onEvent, onTelemetryEvent);
|
|
92
|
+
// Re-report only on a genuine workspace switch — not on every context update (theme,
|
|
93
|
+
// auth, locale, …) — so each workspace visit is counted exactly once.
|
|
94
|
+
if (nextCtx.currentWorkspaceId !== previousWorkspaceId) {
|
|
95
|
+
reportPageView(onTelemetryEvent, nextCtx.currentWorkspaceId);
|
|
96
|
+
previousWorkspaceId = nextCtx.currentWorkspaceId;
|
|
97
|
+
}
|
|
63
98
|
},
|
|
64
99
|
};
|
|
65
100
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/create-pluggable-module",
|
|
3
|
-
"version": "11.43.0-alpha.
|
|
3
|
+
"version": "11.43.0-alpha.5",
|
|
4
4
|
"description": "Scaffolder for GoodData pluggable applications. Invoked via `npm init @gooddata/pluggable-module`.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"typescript": "5.9.3",
|
|
51
51
|
"vite": "8.0.16",
|
|
52
52
|
"vitest": "4.1.8",
|
|
53
|
-
"@gooddata/eslint-config": "11.43.0-alpha.
|
|
54
|
-
"gdc-app-template-name-harness": "11.43.0-alpha.
|
|
55
|
-
"@gooddata/oxlint-config": "11.43.0-alpha.
|
|
56
|
-
"gdc-app-template-name-module": "11.43.0-alpha.
|
|
53
|
+
"@gooddata/eslint-config": "11.43.0-alpha.5",
|
|
54
|
+
"gdc-app-template-name-harness": "11.43.0-alpha.5",
|
|
55
|
+
"@gooddata/oxlint-config": "11.43.0-alpha.5",
|
|
56
|
+
"gdc-app-template-name-module": "11.43.0-alpha.5"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=24.12.0"
|