Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devtools #413

Merged
merged 4 commits into from
Sep 10, 2024
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
10 changes: 3 additions & 7 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions apps/acf-extension/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down Expand Up @@ -82,6 +86,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"],
Expand Down
7 changes: 7 additions & 0 deletions apps/acf-extension/src/devtools/chrome-devtools.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare namespace chrome {
namespace devtools {
namespace recorder {
function registerRecorderExtensionPlugin(plugin: any, name: string, mediaType: string): void;
}
}
}
97 changes: 97 additions & 0 deletions apps/acf-extension/src/devtools/converter.ts
Original file line number Diff line number Diff line change
@@ -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<Array<string>>) => {
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<Configuration> = [];
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;
};
1 change: 1 addition & 0 deletions apps/acf-extension/src/devtools/devtools.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="module" src="./devtools.js"></script>
14 changes: 14 additions & 0 deletions apps/acf-extension/src/devtools/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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');
46 changes: 46 additions & 0 deletions apps/acf-extension/src/devtools/index.types.ts
Original file line number Diff line number Diff line change
@@ -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<Array<string>>;
value: string;
};

type ClickStep = {
target: string;
type: 'click' | 'doubleClick';
selectors: Array<Array<string>>;
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<AssertedEvents>; timeout: number };
export type Recording = {
title: string;
steps: Array<Step>;
};
1 change: 1 addition & 0 deletions apps/acf-extension/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"sandbox": {
"pages": ["html/sandbox.html"]
},
"devtools_page": "devtools.html",
"web_accessible_resources": [
{
"resources": ["assets/*", "css/*", "html/*", "*.js.map"],
Expand Down
1 change: 1 addition & 0 deletions apps/acf-extension/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ 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: './html', context: '../../libs/shared/sandbox/src/lib' },
{ from: path.join(ctx.options.root, './node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js'), to: './webcomponents' },
{
Expand Down
2 changes: 1 addition & 1 deletion apps/acf-options-page/src/store/config/config.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const slice = createSlice({
state.selectedConfigId = state.configs[0].id;
},
importAll: (state, action: PayloadAction<Array<Configuration>>) => {
state.configs = { ...state.configs, ...updateConfigIds(action.payload) };
state.configs.push(...updateConfigIds(action.payload));
state.selectedConfigId = state.configs[0].id;
},
importConfig: (state, action: PayloadAction<Configuration>) => {
Expand Down
1 change: 1 addition & 0 deletions libs/acf/common/src/lib/model/action-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export type Action = {
status?: string;
error?: string[];
valueFieldType?: 'text' | 'textarea';
selectors?: Array<Array<string>>;
};

export const getDefaultAction = (): Action => ({
Expand Down
1 change: 1 addition & 0 deletions libs/acf/common/src/lib/model/config-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const defaultHotkey = 'Ctrl + Shift + A';

export enum CONFIG_SOURCE {
WIZARD = 'wizard',
RECORDER = 'recorder',
WEB = 'web',
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down