Skip to content

Commit eb3cd52

Browse files
authored
Merge pull request #49 from contentstack/development
Development --> Stag
2 parents 19700ee + f527467 commit eb3cd52

File tree

22 files changed

+24988
-170
lines changed

22 files changed

+24988
-170
lines changed

ui/package-lock.json

Lines changed: 24228 additions & 102 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
{
22
"name": "marketplace-json-editor-app-ui",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"private": true,
55
"dependencies": {
6-
"@contentstack/app-sdk": "^1.2.0",
7-
"@types/node": "^12.20.37",
6+
"@contentstack/app-sdk": "^1.5.0",
7+
"@datadog/browser-rum": "^4.25.0",
8+
"@playwright/test": "1.25.0",
89
"@types/react": "^17.0.35",
910
"@types/react-dom": "^17.0.11",
1011
"ajv": "^8.8.2",
12+
"axios": "^1.4.0",
1113
"brace": "^0.11.1",
14+
"jotai": "^2.2.1",
1215
"jsoneditor": "^9.5.8",
1316
"jsoneditor-react": "^3.1.2",
1417
"prop-types": "^15.8.1",
@@ -18,18 +21,23 @@
1821
"react-scripts": "4.0.3",
1922
"sass": "^1.43.4",
2023
"tippy.js": "^6.3.7",
21-
"trackjs": "^3.10.1",
2224
"typescript": "^4.5.2",
2325
"web-vitals": "^1.1.2"
2426
},
2527
"scripts": {
26-
"start": "export PORT=4000 && react-scripts start",
28+
"start": "export PORT=3000 && react-scripts start",
2729
"build": "GENERATE_SOURCEMAP=false react-scripts build",
2830
"test": "jest",
2931
"eject": "react-scripts eject",
3032
"prettify": "prettier --write .",
3133
"lint:fix": "eslint --fix --ext .js,.jsx,.ts,.tsx . --ignore-pattern './node_modules/' --ignore-pattern './buid/'",
32-
"precommit": "npm run prettify && npm run lint:fix"
34+
"precommit": "npm run prettify && npm run lint:fix",
35+
"test:chrome": "npx playwright test --config=playwright.config.ts --project=Chromium",
36+
"test:firefox": "npx playwright test --config=playwright.config.ts --project=firefox",
37+
"test:safari": "npx playwright test --config=playwright.config.ts --project=safari",
38+
"test:chrome-headed": "npx playwright test --headed --config=playwright.config.ts --project=Chromium",
39+
"test:firefox-headed": "npx playwright test --headed --config=playwright.config.ts --project=firefox",
40+
"test:safari-headed": "npx playwright test --headed --config=playwright.config.ts --project=safari"
3341
},
3442
"eslintConfig": {
3543
"extends": [
@@ -58,6 +66,7 @@
5866
"@testing-library/jest-dom": "^5.16.0",
5967
"@testing-library/react": "^12.1.2",
6068
"@types/jest": "^26.0.14",
69+
"@types/node": "^20.3.2",
6170
"@typescript-eslint/eslint-plugin": "^5.4.0",
6271
"@typescript-eslint/parser": "^5.4.0",
6372
"babel-jest": "^26.6.0",

ui/playwright-report/index.html

Lines changed: 62 additions & 0 deletions
Large diffs are not rendered by default.

ui/playwright.config.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type { PlaywrightTestConfig } from "@playwright/test";
2+
import { devices } from "@playwright/test";
3+
/**
4+
* Read environment variables from file.
5+
*/
6+
require("dotenv").config();
7+
8+
/**
9+
* See https://playwright.dev/docs/test-configuration.
10+
*/
11+
const config: PlaywrightTestConfig = {
12+
testMatch: /.*.ts/,
13+
/**
14+
* globalSetup & teardown of test data
15+
* globalTeardown: require.resolve("./tests/global-teardown"),
16+
*/
17+
globalSetup: require.resolve("../ui/tests/global-setup"),
18+
19+
20+
testDir: "../ui/tests/e2e",
21+
/* Maximum time one test can run for. */
22+
timeout: 10 * 10000,
23+
expect: {
24+
/**
25+
* Maximum time expect() should wait for the condition to be met.
26+
* For example in `await expect(locator).toHaveText();`
27+
*/
28+
timeout: 10 * 10000,
29+
},
30+
/* Fail the build on CI if you accidentally left test.only in the source code. */
31+
forbidOnly: !!process.env.CI,
32+
/* Retry on CI only */
33+
retries: 2,
34+
/* Opt out of parallel tests on CI. */
35+
workers: process.env.CI ? 1 : undefined,
36+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
37+
reporter: [["html", { open: "never" }]],
38+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
39+
use: {
40+
storageState: "storageState.json",
41+
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
42+
actionTimeout: 0,
43+
screenshot: "off",
44+
video: "off",
45+
viewport: { width: 1000, height: 720 },
46+
trace: "on-first-retry",
47+
baseURL: process.env.APP_HOST_URL,
48+
launchOptions: {
49+
logger: {
50+
isEnabled: () => {
51+
return false;
52+
},
53+
log: (name, severity, message, args) => console.log(`${name}: ${message}`),
54+
},
55+
},
56+
},
57+
/* Configure projects for major browsers */
58+
projects: [
59+
{
60+
name: "Chromium",
61+
use: {
62+
browserName: "chromium",
63+
},
64+
},
65+
{
66+
name: 'safari',
67+
use: { ...devices['Desktop Safari'] },
68+
},
69+
{
70+
name: "firefox",
71+
use: {
72+
browserName: "firefox",
73+
},
74+
},
75+
],
76+
};
77+
78+
export default config;

ui/src/common/constants/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
export default {
22
appSdkError: "appSdk initialization error",
33
};
4+
5+
export const eventNames = Object.freeze({
6+
APP_INITIALIZE_SUCCESS: "App Loaded Successfully",
7+
APP_INITIALIZE_FAILURE: "App Load Failure",
8+
});

ui/src/components/ErrorBoundary/index.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
11
/* eslint-disable react/prop-types */
22
/* eslint-disable react/destructuring-assignment */
33
import React from "react";
4-
import TrackJS from "../../trackjs";
4+
import { datadogRum } from '@datadog/browser-rum';
55

6-
interface MyProps {}
6+
interface MyProps {
7+
children: React.ReactElement;
8+
}
79

810
interface MyState {
911
hasError: boolean;
1012
}
1113

14+
// datadog-rum Installation
15+
datadogRum.init({
16+
applicationId: `${process.env.REACT_APP_DATADOG_RUM_APPLICATION_ID}`,
17+
clientToken: `${process.env.REACT_APP_DATADOG_RUM_CLIENT_TOKEN}`,
18+
site: `${process.env.REACT_APP_DATADOG_RUM_SITE}`,
19+
service: `${process.env.REACT_APP_DATADOG_RUM_SERVICE}`,
20+
sampleRate: 100,
21+
sessionReplaySampleRate: 20,
22+
trackInteractions: true,
23+
trackResources: true,
24+
trackLongTasks: true,
25+
defaultPrivacyLevel: 'mask-user-input',
26+
useCrossSiteSessionCookie: true,
27+
});
28+
29+
// sending MetaData to Datadog RUM
30+
datadogRum.setGlobalContextProperty('Application Type', 'Marketplace');
31+
datadogRum.setGlobalContextProperty('Application Name', 'JSON Editor App');
32+
1233
class ErrorBoundary extends React.Component<MyProps, MyState> {
1334
constructor(props: any) {
1435
super(props);
1536
this.state = { hasError: false };
1637
}
1738

1839
static getDerivedStateFromError(error: any) {
19-
// error tracker for error reporting service
20-
TrackJS.trackError(error);
2140
// Update state so the next render will show the fallback UI.
2241
console.warn(error); // Remove this line if not required.
2342
return { hasError: true };
2443
}
2544

2645
componentDidCatch(error: any, errorInfo: any) {
27-
// error tracker for error reporting service
28-
TrackJS.trackError(error);
2946
// You can also log the error to an error reporting service
3047
// logErrorToMyService(error, errorInfo);
3148
console.error("errorInfo ", errorInfo);
@@ -34,8 +51,6 @@ class ErrorBoundary extends React.Component<MyProps, MyState> {
3451

3552
render() {
3653
if (this?.state?.hasError) {
37-
// error tracker for error reporting service
38-
TrackJS.trackError(this?.state?.hasError);
3954
// You can render any custom fallback UI
4055
return <h1>Something went wrong.</h1>;
4156
}

ui/src/containers/App/index.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from "react";
22
import { HashRouter, Route, Routes, Navigate } from "react-router-dom";
3-
import TrackJS from "../../trackjs";
43
import ErrorBoundary from "../../components/ErrorBoundary";
54
import ConfigScreen from "../ConfigScreen";
65
import CustomField from "../CustomField";
@@ -17,8 +16,6 @@ const HomeRedirectHandler = function () {
1716
return null;
1817
};
1918

20-
// Track.js installation
21-
TrackJS.installation();
2219

2320
/* App - The main app component that should be rendered */
2421
const App: React.FC = function () {

ui/src/containers/ConfigScreen/index.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,25 @@ import tippy from "tippy.js";
1111
import localeTexts from "../../common/locale/en-us";
1212
import constants from "../../common/constants";
1313
import { mergeObjects } from "../../common/utils";
14-
import TrackJS from "../../trackjs";
1514
import { TypeAppSdkConfigState } from "../../common/types";
1615

1716
/* Import node module CSS */
1817
import "tippy.js/dist/tippy.css";
1918
/* Import our CSS */
2019
import "./styles.scss";
2120

21+
import useJsErrorTracker from "../../hooks/useJsErrorTracker";
22+
import { useAppSdk } from "../../hooks/useAppSdk";
23+
import useAnalytics from "../../hooks/useAnalytics";
24+
2225
const ConfigScreen: React.FC = function () {
26+
27+
// error tracking hooks
28+
const { addMetadata, trackError } = useJsErrorTracker();
29+
const { trackEvent } = useAnalytics();
30+
const [appSdk] = useAppSdk();
31+
32+
2333
const [state, setState] = useState<TypeAppSdkConfigState>({
2434
installationData: {
2535
configuration: {
@@ -35,14 +45,11 @@ const ConfigScreen: React.FC = function () {
3545
},
3646
appSdkInitialized: false,
3747
});
38-
const [isStringified, setIsStringified] = useState(false);
48+
const [isStringified,setIsStringified]=useState(false);
3949

4050
useEffect(() => {
4151
ContentstackAppSdk.init()
4252
.then(async (appSdk) => {
43-
//Adding Track.js metadata
44-
TrackJS.addMetadata(appSdk);
45-
4653
const sdkConfigData = appSdk?.location?.AppConfigWidget?.installation;
4754
if (sdkConfigData) {
4855
const installationDataFromSDK =
@@ -63,6 +70,7 @@ const ConfigScreen: React.FC = function () {
6370
}
6471
})
6572
.catch((error) => {
73+
trackError(error);
6674
console.error(constants.appSdkError, error);
6775
});
6876
}, []);
@@ -77,10 +85,8 @@ const ConfigScreen: React.FC = function () {
7785
if (typeof fieldValue === "string") fieldValue = fieldValue?.trim();
7886
const updatedConfig = state?.installationData?.configuration || {};
7987
const updatedServerConfig = state?.installationData?.serverConfiguration;
80-
8188
if (fieldName === "auth_token") updatedServerConfig[fieldName] = fieldValue;
8289
else updatedConfig[fieldName] = fieldValue;
83-
8490
if (typeof state?.setInstallationData !== "undefined") {
8591
await state?.setInstallationData({
8692
...state?.installationData,
@@ -94,6 +100,7 @@ const ConfigScreen: React.FC = function () {
94100

95101
const updateCustomJSON = (e: any) => {
96102
const val = e?.target?.id !== "jsonObject";
103+
trackEvent("Clicked", { property: `Update Json` });
97104
setIsStringified(val);
98105
updateConfig({ target: { name: "isStringified", value: val } });
99106
};

ui/src/containers/CustomField/index.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, { useEffect, useState } from "react";
22
import ContentstackAppSdk from "@contentstack/app-sdk";
3-
import constants from "../../common/constants";
3+
import constants, { eventNames } from "../../common/constants";
44
import { isEmpty } from "../../common/utils";
5-
import TrackJS from "../../trackjs";
65
import { TypeSDKData } from "../../common/types";
76
import "./styles.scss";
7+
import useAnalytics from "../../hooks/useAnalytics";
88
import JSONEditor from "../../components/jsoneditor";
99

1010
const CustomField: React.FC = function () {
@@ -14,7 +14,10 @@ const CustomField: React.FC = function () {
1414
appSdkInitialized: false,
1515
});
1616
const [jsonData, setJsonData] = useState<Array<any>>([{}]);
17-
const [saceJsonData, setSaveJsonData] = useState<Array<any>>([{}]);
17+
const { trackEvent } = useAnalytics();
18+
const [saveJsonData, setSaveJsonData] = useState<Array<any>>([{}]);
19+
const { APP_INITIALIZE_SUCCESS, APP_INITIALIZE_FAILURE } = eventNames;
20+
1821
let isStringified: any;
1922

2023
const toStringify = (localConfig: any, globalConfig: any) => {
@@ -30,9 +33,6 @@ const CustomField: React.FC = function () {
3033
useEffect(() => {
3134
ContentstackAppSdk.init()
3235
.then(async (appSdk) => {
33-
// Adding Track.js metadata
34-
TrackJS.addMetadata(appSdk);
35-
3636
const config = await appSdk?.getConfig();
3737
setState({
3838
config,
@@ -66,9 +66,11 @@ const CustomField: React.FC = function () {
6666
[JSON.stringify(jsonVal[0])]
6767
: jsonVal
6868
);
69+
trackEvent(APP_INITIALIZE_SUCCESS)
6970
})
7071
.catch((error) => {
7172
console.error(constants.appSdkError, error);
73+
trackEvent(APP_INITIALIZE_FAILURE)
7274
});
7375
}, []);
7476

@@ -81,8 +83,8 @@ const CustomField: React.FC = function () {
8183
};
8284

8385
useEffect(() => {
84-
state?.location?.CustomField?.field?.setData(saceJsonData);
85-
}, [saceJsonData]);
86+
state?.location?.CustomField?.field?.setData(saveJsonData);
87+
}, [saveJsonData]);
8688

8789
return (
8890
<div className="layout-container">

ui/src/hooks/useAnalytics.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { useCallback } from "react";
2+
import { useAppSdk } from "./useAppSdk";
3+
4+
const ENV: string = process.env.NODE_ENV || "";
5+
6+
/**
7+
* useAnalytics hook to track user actions and events in application
8+
*/
9+
const useAnalytics = () => {
10+
const [appSDK] = useAppSdk();
11+
const trackEvent = useCallback(
12+
(event: string, eventData: any = {}) => {
13+
if (ENV === "production") {
14+
appSDK?.pulse(event, eventData);
15+
}
16+
},
17+
[appSDK]
18+
);
19+
20+
return { trackEvent };
21+
};
22+
23+
export default useAnalytics;

0 commit comments

Comments
 (0)