From 250b198f0bbce047996fe2d2da80bc79a0d6435e Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Mon, 2 Sep 2024 17:17:44 +0530 Subject: [PATCH 1/4] initial --- apps/acf-extension/project.json | 8 ++ apps/acf-extension/src/devtools/devtools.html | 106 ++++++++++++++++++ apps/acf-extension/src/devtools/index.ts | 3 + .../src/devtools/recorder/index.ts | 14 +++ .../src/devtools/recorder/recorder.html | 48 ++++++++ apps/acf-extension/src/manifest.json | 1 + apps/acf-extension/webpack.config.js | 2 + 7 files changed, 182 insertions(+) create mode 100644 apps/acf-extension/src/devtools/devtools.html create mode 100644 apps/acf-extension/src/devtools/index.ts create mode 100644 apps/acf-extension/src/devtools/recorder/index.ts create mode 100644 apps/acf-extension/src/devtools/recorder/recorder.html diff --git a/apps/acf-extension/project.json b/apps/acf-extension/project.json index a6d251d6..e87a2455 100644 --- a/apps/acf-extension/project.json +++ b/apps/acf-extension/project.json @@ -82,6 +82,14 @@ { "entryName": "wizard-popup", "entryPath": "apps/acf-extension/src/wizard/popup/wizard-popup.ts" + }, + { + "entryName": "devtools", + "entryPath": "apps/acf-extension/src/devtools/index.ts" + }, + { + "entryName": "recorder", + "entryPath": "apps/acf-extension/src/devtools/recorder/index.ts" } ], "styles": ["apps/acf-extension/src/wizard/popup/wizard-popup.scss", "libs/shared/status-bar/src/lib/status-bar.scss"], diff --git a/apps/acf-extension/src/devtools/devtools.html b/apps/acf-extension/src/devtools/devtools.html new file mode 100644 index 00000000..291c522f --- /dev/null +++ b/apps/acf-extension/src/devtools/devtools.html @@ -0,0 +1,106 @@ + + + + + + \ No newline at end of file diff --git a/apps/acf-extension/src/devtools/index.ts b/apps/acf-extension/src/devtools/index.ts new file mode 100644 index 00000000..712cfc0c --- /dev/null +++ b/apps/acf-extension/src/devtools/index.ts @@ -0,0 +1,3 @@ +chrome.devtools.panels.create('demo panel', 'icon.png', 'recorder.html', () => { + console.log('user switched to this panel'); +}); diff --git a/apps/acf-extension/src/devtools/recorder/index.ts b/apps/acf-extension/src/devtools/recorder/index.ts new file mode 100644 index 00000000..d14e6ac1 --- /dev/null +++ b/apps/acf-extension/src/devtools/recorder/index.ts @@ -0,0 +1,14 @@ +const types = {}; +chrome.devtools.inspectedWindow.getResources((resources) => { + console.log(resources); + const result = `Resources on this page: + ${Object.entries(types) + .map((entry) => { + const [type, count] = entry; + return `${type}: ${count}`; + }) + .join('\n')}`; + const div = document.createElement('div'); + div.innerText = result; + document.body.appendChild(div); +}); diff --git a/apps/acf-extension/src/devtools/recorder/recorder.html b/apps/acf-extension/src/devtools/recorder/recorder.html new file mode 100644 index 00000000..49149efd --- /dev/null +++ b/apps/acf-extension/src/devtools/recorder/recorder.html @@ -0,0 +1,48 @@ + + + + + + + + + +

Recorder

+ + + \ No newline at end of file diff --git a/apps/acf-extension/src/manifest.json b/apps/acf-extension/src/manifest.json index 469c1a2c..a89d439c 100644 --- a/apps/acf-extension/src/manifest.json +++ b/apps/acf-extension/src/manifest.json @@ -54,6 +54,7 @@ "sandbox": { "pages": ["html/sandbox.html"] }, + "devtools_page": "devtools.html", "web_accessible_resources": [ { "resources": ["assets/*", "css/*", "html/*", "*.js.map"], diff --git a/apps/acf-extension/webpack.config.js b/apps/acf-extension/webpack.config.js index f34056a0..0e8b3abc 100644 --- a/apps/acf-extension/webpack.config.js +++ b/apps/acf-extension/webpack.config.js @@ -41,6 +41,8 @@ module.exports = composePlugins(withNx(), (config, ctx) => { { from: `**/messages.json`, to: './_locales', context: `${ctx.options.root}/apps/acf-i18n/src/locales` }, { from: path.join(__dirname, 'assets', config.watch ? 'DEV' : process.env.NX_PUBLIC_VARIANT), to: './assets' }, { from: `./*.html`, to: './html', context: 'src/wizard/popup' }, + { from: `./*.html`, to: './', context: 'src/devtools' }, + { from: `./*.html`, to: './', context: 'src/devtools/recorder' }, { from: `./*.html`, to: './html', context: '../../libs/shared/sandbox/src/lib' }, { from: path.join(ctx.options.root, './node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js'), to: './webcomponents' }, { From 3e70ad199b39670d35d7025a413f63b3f18ebf2d Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Mon, 9 Sep 2024 09:14:42 +0530 Subject: [PATCH 2/4] Removed i18n from build --- .github/workflows/deploy.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 69f8a260..997e76b0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -55,7 +55,7 @@ jobs: echo "HEAD: ${{ env.NX_HEAD }}" - run: npm ci - name: Build Projects and Library - run: npx nx run-many -t=build --parallel=3 --prod --exclude=acf-configs --base-href ${{vars.PUBLIC_URL}} --verbose + run: npx nx run-many -t build -p acf-options-page acf-extension --prod --base-href ${{vars.PUBLIC_URL}} --verbose env: NX_PUBLIC_NAME: ${{vars.NX_PUBLIC_NAME}} NX_PUBLIC_VARIANT: ${{vars.NX_PUBLIC_VARIANT}} @@ -84,10 +84,7 @@ jobs: - name: Bundle Projects run: | mkdir bundle - cd dist/apps/acf-i18n - zip -r ../../../bundle/acf-i18n-${{vars.NX_PUBLIC_VARIANT}}.zip . - cd .. - cd acf-options-page + cd dist/apps/acf-options-page zip -r ../../../bundle/acf-options-page-${{vars.NX_PUBLIC_VARIANT}}.zip . cd .. cd acf-extension @@ -103,8 +100,7 @@ jobs: generate_release_notes: true discussion_category_name: 'Release' fail_on_unmatched_files: true - files: | - bundle/* + files: bundle/* - uses: actions/upload-artifact@v4 id: artifact-upload-step with: From ea528548c6e225ec93984b58758be41573c7031c Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Tue, 10 Sep 2024 00:41:03 +0530 Subject: [PATCH 3/4] Added devtools --- apps/acf-extension/project.json | 8 +- .../src/devtools/chrome-devtools.d.ts | 7 ++ apps/acf-extension/src/devtools/converter.ts | 97 ++++++++++++++++ apps/acf-extension/src/devtools/devtools.html | 107 +----------------- apps/acf-extension/src/devtools/index.ts | 17 ++- .../acf-extension/src/devtools/index.types.ts | 46 ++++++++ .../src/devtools/recorder/index.ts | 14 --- .../src/devtools/recorder/recorder.html | 48 -------- apps/acf-extension/webpack.config.js | 1 - .../src/store/config/config.slice.ts | 2 +- libs/acf/common/src/lib/model/action-model.ts | 1 + libs/acf/common/src/lib/model/config-model.ts | 1 + package.json | 2 +- 13 files changed, 173 insertions(+), 178 deletions(-) create mode 100644 apps/acf-extension/src/devtools/chrome-devtools.d.ts create mode 100644 apps/acf-extension/src/devtools/converter.ts create mode 100644 apps/acf-extension/src/devtools/index.types.ts delete mode 100644 apps/acf-extension/src/devtools/recorder/index.ts delete mode 100644 apps/acf-extension/src/devtools/recorder/recorder.html diff --git a/apps/acf-extension/project.json b/apps/acf-extension/project.json index e87a2455..17fb0d37 100644 --- a/apps/acf-extension/project.json +++ b/apps/acf-extension/project.json @@ -31,6 +31,10 @@ { "entryName": "wizard-popup", "entryPath": "apps/acf-extension/src/wizard/popup/wizard-popup.ts" + }, + { + "entryName": "devtools", + "entryPath": "apps/acf-extension/src/devtools/index.ts" } ], "styles": ["apps/acf-extension/src/wizard/popup/wizard-popup.scss", "libs/shared/status-bar/src/lib/status-bar.scss"], @@ -86,10 +90,6 @@ { "entryName": "devtools", "entryPath": "apps/acf-extension/src/devtools/index.ts" - }, - { - "entryName": "recorder", - "entryPath": "apps/acf-extension/src/devtools/recorder/index.ts" } ], "styles": ["apps/acf-extension/src/wizard/popup/wizard-popup.scss", "libs/shared/status-bar/src/lib/status-bar.scss"], diff --git a/apps/acf-extension/src/devtools/chrome-devtools.d.ts b/apps/acf-extension/src/devtools/chrome-devtools.d.ts new file mode 100644 index 00000000..4221dca0 --- /dev/null +++ b/apps/acf-extension/src/devtools/chrome-devtools.d.ts @@ -0,0 +1,7 @@ +declare namespace chrome { + namespace devtools { + namespace recorder { + function registerRecorderExtensionPlugin(plugin: any, name: string, mediaType: string): void; + } + } +} diff --git a/apps/acf-extension/src/devtools/converter.ts b/apps/acf-extension/src/devtools/converter.ts new file mode 100644 index 00000000..ff40aac7 --- /dev/null +++ b/apps/acf-extension/src/devtools/converter.ts @@ -0,0 +1,97 @@ +import { Action, CONFIG_SOURCE, Configuration, getDefaultAction, getDefaultConfig } from '@dhruv-techapps/acf-common'; + +import { Recording, Step } from './index.types'; + +const getProps = (selectors: Array>) => { + let elementFinder = ''; + let name = ''; + selectors.flat().every((selector) => { + if (selector.startsWith('xpath/')) { + elementFinder = selector.replace('xpath/', ''); + return false; + } else if (selector.startsWith('text/')) { + elementFinder = `//*[contains(text(),"${selector.replace('text/', '')}")`; + return false; + } else if (selector.startsWith('aria/')) { + name = selector.replace('aria/', ''); + } + return true; + }); + return { elementFinder, name }; +}; + +export const ConvertStep = (step: Step) => { + const action: Action = getDefaultAction(); + switch (step.type) { + case 'change': + { + console.assert(step.selectors, 'Selectors are required for change step'); + console.assert(step.value, 'Value is required for change step'); + const { elementFinder, name } = getProps(step.selectors); + action.elementFinder = elementFinder; + action.name = name; + action.selectors = step.selectors; + action.value = step.value; + } + break; // Add an expression here if needed + case 'click': + case 'doubleClick': + { + console.assert(step.selectors, 'Selectors are required for click step'); + const { elementFinder, name } = getProps(step.selectors); + action.elementFinder = elementFinder; + action.name = name; + action.selectors = step.selectors; + } + + break; + case 'keyDown': + case 'keyUp': + case 'navigate': + case 'setViewport': + break; + default: + console.assert(false, `Unknown step type: ${step}`); + } + if (step.timeout) { + action.settings = { retry: step.timeout / 1000, retryInterval: 1 }; + } + delete action.error; + return action; +}; + +const getConfig = (url: string) => { + const config: Configuration = getDefaultConfig(CONFIG_SOURCE.RECORDER); + config.actions = []; + config.url = url; + delete config.updated; + return config; +}; + +export const ConvertRecording = (recording: Recording) => { + const configs: Array = []; + const [, navigate, ...steps] = recording.steps; + let config: Configuration; + if (navigate.type === 'navigate') { + console.assert(navigate.url, 'URL is required for navigate step'); + config = getConfig(navigate.url); + configs.push(config); + } + + console.assert(steps.length === 0, 'No steps found in recording'); + steps.forEach((step) => { + const action = ConvertStep(step); + if (action && action.elementFinder) { + config.actions.push(action); + } + if (step.assertedEvents) { + step.assertedEvents.forEach((assertedEvent) => { + if (assertedEvent.type === 'navigation' && assertedEvent.url !== config.url) { + configs.push(config); + config = getConfig(assertedEvent.url); + } + }); + } + }); + return configs; +}; diff --git a/apps/acf-extension/src/devtools/devtools.html b/apps/acf-extension/src/devtools/devtools.html index 291c522f..e38e51d1 100644 --- a/apps/acf-extension/src/devtools/devtools.html +++ b/apps/acf-extension/src/devtools/devtools.html @@ -1,106 +1 @@ - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/apps/acf-extension/src/devtools/index.ts b/apps/acf-extension/src/devtools/index.ts index 712cfc0c..ffdfbd93 100644 --- a/apps/acf-extension/src/devtools/index.ts +++ b/apps/acf-extension/src/devtools/index.ts @@ -1,3 +1,14 @@ -chrome.devtools.panels.create('demo panel', 'icon.png', 'recorder.html', () => { - console.log('user switched to this panel'); -}); +import { ConvertRecording, ConvertStep } from './converter'; +import { Recording, Step } from './index.types'; + +export class RecorderPlugin { + stringify(recording: Recording) { + return Promise.resolve(JSON.stringify(ConvertRecording(recording))); + } + stringifyStep(step: Step) { + return Promise.resolve(JSON.stringify(ConvertStep(step))); + } +} + +/* eslint-disable no-undef */ +chrome.devtools.recorder.registerRecorderExtensionPlugin(new RecorderPlugin(), 'Auto Clicker Auto Fill', 'application/json'); diff --git a/apps/acf-extension/src/devtools/index.types.ts b/apps/acf-extension/src/devtools/index.types.ts new file mode 100644 index 00000000..bfc13160 --- /dev/null +++ b/apps/acf-extension/src/devtools/index.types.ts @@ -0,0 +1,46 @@ +type NavigationStep = { + type: 'navigate'; + url: string; +}; + +type SetViewportStep = { + type: 'setViewport'; + width: number; + height: number; + deviceScaleFactor: number; + isMobile: boolean; + hasTouch: boolean; + isLandscape: boolean; +}; +type ChangeStep = { + target: string; + type: 'change'; + selectors: Array>; + value: string; +}; + +type ClickStep = { + target: string; + type: 'click' | 'doubleClick'; + selectors: Array>; + offsetY: number; + offsetX: number; +}; + +type KeyStep = { + target: string; + type: 'keyDown' | 'keyUp'; + key: string; +}; + +type AssertedEvents = { + type: string; + url: string; + title: string; +}; + +export type Step = (NavigationStep | SetViewportStep | ChangeStep | ClickStep | KeyStep) & { assertedEvents?: Array; timeout: number }; +export type Recording = { + title: string; + steps: Array; +}; diff --git a/apps/acf-extension/src/devtools/recorder/index.ts b/apps/acf-extension/src/devtools/recorder/index.ts deleted file mode 100644 index d14e6ac1..00000000 --- a/apps/acf-extension/src/devtools/recorder/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -const types = {}; -chrome.devtools.inspectedWindow.getResources((resources) => { - console.log(resources); - const result = `Resources on this page: - ${Object.entries(types) - .map((entry) => { - const [type, count] = entry; - return `${type}: ${count}`; - }) - .join('\n')}`; - const div = document.createElement('div'); - div.innerText = result; - document.body.appendChild(div); -}); diff --git a/apps/acf-extension/src/devtools/recorder/recorder.html b/apps/acf-extension/src/devtools/recorder/recorder.html deleted file mode 100644 index 49149efd..00000000 --- a/apps/acf-extension/src/devtools/recorder/recorder.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - -

Recorder

- - - \ No newline at end of file diff --git a/apps/acf-extension/webpack.config.js b/apps/acf-extension/webpack.config.js index 0e8b3abc..568dff8e 100644 --- a/apps/acf-extension/webpack.config.js +++ b/apps/acf-extension/webpack.config.js @@ -42,7 +42,6 @@ module.exports = composePlugins(withNx(), (config, ctx) => { { from: path.join(__dirname, 'assets', config.watch ? 'DEV' : process.env.NX_PUBLIC_VARIANT), to: './assets' }, { from: `./*.html`, to: './html', context: 'src/wizard/popup' }, { from: `./*.html`, to: './', context: 'src/devtools' }, - { from: `./*.html`, to: './', context: 'src/devtools/recorder' }, { from: `./*.html`, to: './html', context: '../../libs/shared/sandbox/src/lib' }, { from: path.join(ctx.options.root, './node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js'), to: './webcomponents' }, { diff --git a/apps/acf-options-page/src/store/config/config.slice.ts b/apps/acf-options-page/src/store/config/config.slice.ts index 9a76ec43..6dc7ed73 100644 --- a/apps/acf-options-page/src/store/config/config.slice.ts +++ b/apps/acf-options-page/src/store/config/config.slice.ts @@ -108,7 +108,7 @@ const slice = createSlice({ state.selectedConfigId = state.configs[0].id; }, importAll: (state, action: PayloadAction>) => { - state.configs = { ...state.configs, ...updateConfigIds(action.payload) }; + state.configs.push(...updateConfigIds(action.payload)); state.selectedConfigId = state.configs[0].id; }, importConfig: (state, action: PayloadAction) => { diff --git a/libs/acf/common/src/lib/model/action-model.ts b/libs/acf/common/src/lib/model/action-model.ts index 44a098e5..6d88a872 100644 --- a/libs/acf/common/src/lib/model/action-model.ts +++ b/libs/acf/common/src/lib/model/action-model.ts @@ -74,6 +74,7 @@ export type Action = { status?: string; error?: string[]; valueFieldType?: 'text' | 'textarea'; + selectors?: Array>; }; export const getDefaultAction = (): Action => ({ diff --git a/libs/acf/common/src/lib/model/config-model.ts b/libs/acf/common/src/lib/model/config-model.ts index 076b713c..784db0bd 100644 --- a/libs/acf/common/src/lib/model/config-model.ts +++ b/libs/acf/common/src/lib/model/config-model.ts @@ -16,6 +16,7 @@ export const defaultHotkey = 'Ctrl + Shift + A'; export enum CONFIG_SOURCE { WIZARD = 'wizard', + RECORDER = 'recorder', WEB = 'web', } diff --git a/package.json b/package.json index 584f8899..06a6740c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "3.4.37", "license": "MIT", "scripts": { - "start": "nx run-many -t serve", + "start": "nx run-many -t serve -p acf-extension acf-options-page acf-i18n", "release:publish": "nx release publish", "build": "nx run-many -t build", "lint": "nx run-many -t lint" From c26ea05997ba33c4d0f00d05e0cdc8c614589d2d Mon Sep 17 00:00:00 2001 From: Dharmesh Patel Date: Tue, 10 Sep 2024 00:50:08 +0530 Subject: [PATCH 4/4] Formatted code --- apps/acf-extension/src/devtools/devtools.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/acf-extension/src/devtools/devtools.html b/apps/acf-extension/src/devtools/devtools.html index e38e51d1..05bbc4e9 100644 --- a/apps/acf-extension/src/devtools/devtools.html +++ b/apps/acf-extension/src/devtools/devtools.html @@ -1 +1 @@ - \ No newline at end of file +