Ahmad Kholid hace 2 años
padre
commit
e0bfc5f798

+ 6 - 6
package.json

@@ -1,6 +1,6 @@
 {
   "name": "automa",
-  "version": "1.21.1",
+  "version": "1.21.2",
   "description": "An extension for automating your browser by connecting blocks",
   "repository": {
     "type": "git",
@@ -31,7 +31,7 @@
     "@braks/vue-flow": "^0.4.40",
     "@codemirror/autocomplete": "^6.1.0",
     "@codemirror/lang-css": "^6.0.0",
-    "@codemirror/lang-html": "^6.1.0",
+    "@codemirror/lang-html": "^6.1.2",
     "@codemirror/lang-javascript": "^6.0.2",
     "@codemirror/lang-json": "^6.0.0",
     "@codemirror/language": "^6.2.1",
@@ -43,11 +43,11 @@
     "@tiptap/extension-placeholder": "^2.0.0-beta.53",
     "@tiptap/starter-kit": "^2.0.0-beta.197",
     "@tiptap/vue-3": "^2.0.0-beta.96",
-    "@viselect/vanilla": "^3.1.0",
+    "@viselect/vanilla": "^3.1.1",
     "@vueuse/rxjs": "^9.1.1",
     "@vuex-orm/core": "^0.36.4",
     "codemirror": "^6.0.1",
-    "compare-versions": "^4.1.2",
+    "compare-versions": "^5.0.1",
     "cron-parser": "^4.6.0",
     "cronstrue": "^2.11.0",
     "crypto-js": "^4.1.1",
@@ -106,7 +106,7 @@
     "eslint-plugin-vue": "^9.4.0",
     "file-loader": "^6.2.0",
     "fs-extra": "^10.1.0",
-    "html-loader": "^4.1.0",
+    "html-loader": "^4.2.0",
     "html-webpack-plugin": "^5.5.0",
     "lint-staged": "^13.0.2",
     "mini-css-extract-plugin": "^2.3.0",
@@ -121,6 +121,6 @@
     "web-worker": "^1.2.0",
     "webpack": "^5.73.0",
     "webpack-cli": "^4.10.0",
-    "webpack-dev-server": "^4.11.0"
+    "webpack-dev-server": "^4.11.1"
   }
 }

+ 2 - 1
src/background/workflowEngine/blocksHandler/handlerLoopData.js

@@ -49,6 +49,7 @@ async function loopData({ data, id }, { refData }) {
               findBy,
               max: maxLoop,
               multiple: true,
+              reverseLoop: data.reverseLoop,
               selector: data.elementSelector,
               waitForSelector: data.waitForSelector ?? false,
               waitSelectorTimeout: data.waitSelectorTimeout ?? 5000,
@@ -81,7 +82,7 @@ async function loopData({ data, id }, { refData }) {
           index = data.startIndex;
         }
 
-        if (data.reverseLoop) {
+        if (data.reverseLoop && data.loopThrough !== 'elements') {
           currLoopData.reverse();
         }
       }

+ 1 - 1
src/components/newtab/workflow/edit/EditElementExists.vue

@@ -20,8 +20,8 @@
       <ui-input
         :model-value="data.selector"
         :label="t('workflow.blocks.element-exists.selector')"
+        :placeholder="data.findBy === 'xpath' ? '//element' : '.element'"
         autocomplete="off"
-        placeholder=".element"
         class="w-full"
         @change="updateData({ selector: $event })"
       />

+ 7 - 0
src/components/newtab/workflow/edit/EditLoopElements.vue

@@ -21,6 +21,13 @@
       class="w-full mt-3"
       @change="updateData({ maxLoop: $event })"
     />
+    <ui-checkbox
+      :model-value="data.reverseLoop"
+      class="mt-2"
+      @change="updateData({ reverseLoop: $event })"
+    >
+      {{ t('workflow.blocks.loop-data.reverse') }}
+    </ui-checkbox>
     <div class="mt-4 border-t pt-4 mb-8">
       <p class="text-sm text-gray-600 dark:text-gray-200">
         {{ t('workflow.blocks.loop-elements.loadMore') }}

+ 6 - 3
src/content/commandPalette/App.vue

@@ -248,9 +248,10 @@ function onKeydown(event) {
     return;
   }
 
-  if (state.shortcutKeys.length < 1) return;
+  const shortcuts = window._automaShortcuts;
+  if (shortcuts.length < 1) return;
 
-  const automaShortcut = state.shortcutKeys.every((shortcutKey) => {
+  const automaShortcut = shortcuts.every((shortcutKey) => {
     if (shortcutKey === 'mod') return ctrlKey || metaKey;
     if (shortcutKey === 'shift') return shiftKey;
     if (shortcutKey === 'option') return altKey;
@@ -260,6 +261,7 @@ function onKeydown(event) {
   if (automaShortcut) {
     event.preventDefault();
     state.active = true;
+    state.shortcutKeys = shortcuts;
   }
 }
 function onInputKeydown(event) {
@@ -385,10 +387,11 @@ onMounted(() => {
   browser.storage.local.get('automaShortcut').then(({ automaShortcut }) => {
     if (Array.isArray(automaShortcut) && automaShortcut.length < 1) return;
 
-    let keys = ['mod', 'shift', 'a'];
+    let keys = ['mod', 'shift', 'e'];
     if (automaShortcut) keys = automaShortcut.split('+');
 
     state.shortcutKeys = keys;
+    window._automaShortcuts = keys;
   });
 
   window.addEventListener('keydown', onKeydown);

+ 32 - 30
src/content/index.js

@@ -42,8 +42,7 @@ function messageToFrame(frameElement, blockData) {
 }
 async function executeBlock(data) {
   const removeExecutedBlock = showExecutedBlock(data, data.executedBlockOnWeb);
-
-  if (data.data?.selector?.includes('|>') && isMainFrame) {
+  if (data.data?.selector?.includes('|>')) {
     const [frameSelector, selector] = data.data.selector.split(/\|>(.+)/);
     const frameElement = document.querySelector(frameSelector);
     const frameError = (message) => {
@@ -136,18 +135,41 @@ function messageListener({ data, source }) {
 
   initCommandPalette();
 
+  let contextElement = null;
+  let $ctxLink = '';
+  let $ctxMediaUrl = '';
+  let $ctxTextSelection = '';
+
   window.isAutomaInjected = true;
   window.addEventListener('message', messageListener);
+  window.addEventListener(
+    'contextmenu',
+    ({ target }) => {
+      contextElement = target;
+      $ctxTextSelection = window.getSelection().toString();
 
-  let contextElement = null;
-  let $ctxTextSelection = '';
+      const tag = target.tagName;
+      if (tag === 'A') {
+        $ctxLink = target.href;
+      }
+
+      const mediaTags = ['AUDIO', 'VIDEO', 'IMG'];
+      if (mediaTags.includes(tag)) {
+        let mediaSrc = target.src || '';
+
+        if (!mediaSrc.src) {
+          const sourceEl = target.querySelector('source');
+          if (sourceEl) mediaSrc = sourceEl.src;
+        }
+
+        $ctxMediaUrl = mediaSrc;
+      }
+    },
+    true
+  );
 
   if (isMainFrame) {
     shortcutListener();
-    window.addEventListener('contextmenu', ({ target }) => {
-      contextElement = target;
-      $ctxTextSelection = window.getSelection().toString();
-    });
     // window.addEventListener('load', elementObserver);
   }
 
@@ -198,30 +220,10 @@ function messageListener({ data, source }) {
             break;
           }
           case 'context-element': {
-            let $ctxLink = '';
-            let $ctxMediaUrl = '';
             let $ctxElSelector = '';
 
             if (contextElement) {
               $ctxElSelector = findSelector(contextElement);
-
-              const tag = contextElement.tagName;
-              if (tag === 'A') {
-                $ctxLink = contextElement.href;
-              }
-
-              const mediaTags = ['AUDIO', 'VIDEO', 'IMG'];
-              if (mediaTags.includes(tag)) {
-                let mediaSrc = contextElement.src || '';
-
-                if (!mediaSrc.src) {
-                  const sourceEl = contextElement.querySelector('source');
-                  if (sourceEl) mediaSrc = sourceEl.src;
-                }
-
-                $ctxMediaUrl = mediaSrc;
-              }
-
               contextElement = null;
             }
             if (!$ctxTextSelection) {
@@ -229,10 +231,10 @@ function messageListener({ data, source }) {
             }
 
             resolve({
-              $ctxElSelector,
-              $ctxTextSelection,
               $ctxLink,
               $ctxMediaUrl,
+              $ctxElSelector,
+              $ctxTextSelection,
             });
             break;
           }

+ 42 - 14
src/content/services/shortcutListener.js

@@ -63,20 +63,28 @@ function workflowShortcutsListener(findWorkflow, shortcutsObj) {
     return true;
   });
 }
+async function getWorkflows() {
+  const { workflows, workflowHosts } = await browser.storage.local.get([
+    'workflows',
+    'workflowHosts',
+  ]);
+  const localWorkflows = Array.isArray(workflows)
+    ? workflows
+    : Object.values(workflows);
+
+  return {
+    local: localWorkflows,
+    hosted: Object.values(workflowHosts || {}),
+  };
+}
 
 export default async function () {
   try {
-    const { shortcuts, workflows, workflowHosts } =
-      await browser.storage.local.get([
-        'shortcuts',
-        'workflows',
-        'workflowHosts',
-      ]);
-    const workflowsArr = Array.isArray(workflows)
-      ? workflows
-      : Object.values(workflows);
+    const storage = await browser.storage.local.get('shortcuts');
+    let workflows = await getWorkflows();
+
     const findWorkflow = (id, publicId = false) => {
-      let workflow = workflowsArr.find((item) => {
+      let workflow = workflows.local.find((item) => {
         if (publicId) {
           return item.settings.publicId === id;
         }
@@ -85,9 +93,7 @@ export default async function () {
       });
 
       if (!workflow) {
-        workflow = Object.values(workflowHosts || {}).find(
-          ({ hostId }) => hostId === id
-        );
+        workflow = workflows.hosted.find(({ hostId }) => hostId === id);
 
         if (workflow) workflow.id = workflow.hostId;
       }
@@ -95,8 +101,30 @@ export default async function () {
       return workflow;
     };
 
+    browser.storage.onChanged.addListener(({ automaShortcut, shortcuts }) => {
+      if (automaShortcut) {
+        if (
+          Array.isArray(automaShortcut.newValue) &&
+          automaShortcut.newValue.length < 1
+        ) {
+          window._automaShortcuts = [];
+        } else {
+          const automaShortcutArr = automaShortcut.newValue.split('+');
+
+          window._automaShortcuts = automaShortcutArr;
+        }
+      }
+      if (shortcuts) {
+        Mousetrap.reset();
+        getWorkflows().then((updatedWorkflows) => {
+          workflows = updatedWorkflows;
+          workflowShortcutsListener(findWorkflow, shortcuts.newValue || {});
+        });
+      }
+    });
+
     automaCustomEventListener(findWorkflow);
-    workflowShortcutsListener(findWorkflow, shortcuts || {});
+    workflowShortcutsListener(findWorkflow, storage.shortcuts || {});
   } catch (error) {
     console.error(error);
   }

+ 7 - 2
src/content/utils.js

@@ -13,11 +13,16 @@ export function simulateClickElement(element) {
 
 export function generateLoopSelectors(
   elements,
-  { max, attrId, frameSelector, startIndex = 0 }
+  { max, attrId, frameSelector, reverseLoop, startIndex = 0 }
 ) {
   const selectors = [];
+  let elementsList = elements;
 
-  elements.forEach((el, index) => {
+  if (reverseLoop) {
+    elementsList = Array.from(elements).reverse();
+  }
+
+  elementsList.forEach((el, index) => {
     if (max > 0 && selectors.length - 1 > max) return;
 
     const attrName = 'automa-loop';

+ 1 - 1
src/newtab/pages/settings/SettingsShortcuts.vue

@@ -108,7 +108,7 @@ const { t } = useI18n();
 const toast = useToast();
 
 const shortcuts = ref(mapShortcuts);
-const automaShortcut = ref(getReadableShortcut('mod+shift+a'));
+const automaShortcut = ref(getReadableShortcut('mod+shift+e'));
 const recording = reactive({
   id: '',
   keys: [],

+ 4 - 3
src/utils/shared.js

@@ -742,11 +742,12 @@ export const tasks = {
     data: {
       disableBlock: false,
       loopId: '',
+      selector: '',
       maxLoop: '0',
       description: '',
-      selector: '',
-      findBy: 'cssSelector',
+      reverseLoop: false,
       actionElSelector: '',
+      findBy: 'cssSelector',
       actionElMaxWaitTime: 5,
       actionPageMaxWaitTime: 10,
       loadMoreAction: 'none',
@@ -1241,7 +1242,7 @@ export const tasks = {
     outputs: 1,
     allowedInputs: true,
     maxConnection: 1,
-    refDataKeys: ['html', 'css'],
+    refDataKeys: ['html', 'css', 'selector'],
     data: {
       disableBlock: false,
       description: '',

+ 31 - 9
src/utils/workflowTrigger.js

@@ -3,7 +3,7 @@ import dayjs from 'dayjs';
 import cronParser from 'cron-parser';
 import { isObject } from './helper';
 
-export function registerContextMenu(workflowId, data) {
+export function registerContextMenu(triggerId, data) {
   return new Promise((resolve, reject) => {
     const documentUrlPatterns = ['https://*/*', 'http://*/*'];
     const contextTypes =
@@ -19,6 +19,10 @@ export function registerContextMenu(workflowId, data) {
       return;
     }
 
+    const workflowId = triggerId.includes(':')
+      ? triggerId.split(':')[1]
+      : triggerId;
+
     browserContext.create(
       {
         id: workflowId,
@@ -29,7 +33,6 @@ export function registerContextMenu(workflowId, data) {
       },
       () => {
         const error = browser.runtime.lastError;
-
         if (error) {
           if (error.message.includes('automaContextMenu')) {
             browserContext.create(
@@ -45,6 +48,13 @@ export function registerContextMenu(workflowId, data) {
                   .catch(reject);
               }
             );
+            resolve();
+            return;
+          }
+          if (error.message.includes('Duplicate id')) {
+            browserContext.remove(triggerId).then(() => {
+              registerContextMenu(workflowId, data).then(resolve).catch(reject);
+            });
             return;
           }
 
@@ -71,7 +81,7 @@ async function removeFromWorkflowQueue(workflowId) {
   await browser.storage.local.set({ workflowQueue });
 }
 
-export async function cleanWorkflowTriggers(workflowId) {
+export async function cleanWorkflowTriggers(workflowId, triggers) {
   try {
     const alarms = await browser.alarms.getAll();
     for (const alarm of alarms) {
@@ -109,17 +119,29 @@ export async function cleanWorkflowTriggers(workflowId) {
       visitWebTriggers: filteredVisitWebTriggers,
     });
 
+    const browserContextMenu =
+      BROWSER_TYPE === 'firefox' ? browser.menus : browser.contextMenus;
     const removeFromContextMenu = async () => {
       try {
-        await (BROWSER_TYPE === 'firefox'
-          ? browser.menus
-          : browser.contextMenus
-        )?.remove(workflowId);
+        let promises = [];
+
+        if (triggers) {
+          promises = triggers.map(async (trigger) => {
+            if (trigger.type !== 'context-menu') return;
+
+            const triggerId = `trigger:${workflowId}:${trigger.id}`;
+            await browserContextMenu.remove(triggerId);
+          });
+        }
+
+        promises.push(browserContextMenu.remove(workflowId));
+
+        await Promise.allSettled(promises);
       } catch (error) {
         // Do nothing
       }
     };
-    await removeFromContextMenu();
+    if (browserContextMenu) await removeFromContextMenu();
   } catch (error) {
     console.error(error);
   }
@@ -259,7 +281,7 @@ export const workflowTriggersMap = {
 
 export async function registerWorkflowTrigger(workflowId, { data }) {
   try {
-    await cleanWorkflowTriggers(workflowId);
+    await cleanWorkflowTriggers(workflowId, data.triggers);
 
     if (data.triggers) {
       for (const trigger of data.triggers) {

+ 60 - 25
yarn.lock

@@ -952,10 +952,10 @@
     "@codemirror/state" "^6.0.0"
     "@lezer/css" "^1.0.0"
 
-"@codemirror/lang-html@^6.1.0":
-  version "6.1.1"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-6.1.1.tgz#1bbe5ac2b5af113594bf99ee8c85399bfcf42349"
-  integrity sha512-+hV1kVZySmr7GxCgSVM+BodaVlsgD98laEJbj/GALhgIrfnHTSiRuTz2EPTjNCKeq5uEQXeOKFY711/CxJbYrg==
+"@codemirror/lang-html@^6.1.2":
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-6.1.2.tgz#64979e583c6120c70d3123e6ce3f8595b20abc52"
+  integrity sha512-e8JAUWyOo7N26tmek+WK0+Zg+pZRe+dQi8TZq0OOVVygpLV+mNAT2n5b5JhknY+TVZIVGLjuhdsoizw1SDFfPg==
   dependencies:
     "@codemirror/autocomplete" "^6.0.0"
     "@codemirror/lang-css" "^6.0.0"
@@ -1674,10 +1674,10 @@
   dependencies:
     "@types/node" "*"
 
-"@viselect/vanilla@^3.1.0":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@viselect/vanilla/-/vanilla-3.1.0.tgz#66ef6eaa383a053c24bd2f6d8db1691f5b32e6bb"
-  integrity sha512-B0cvgsHandCXXsqp3O09HKR6buJa6kGpzu/Y9gQOiKcE26mbfRlZIGKBcYEdOELmRa+QrzG6ydegjNET/htsGg==
+"@viselect/vanilla@^3.1.1":
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/@viselect/vanilla/-/vanilla-3.1.1.tgz#e63ef3529f819cc83e8c1aea6b3ab9936d550f76"
+  integrity sha512-aS1UF6WkV3TvO5vqg2uQk8WRI36b2SAtfozVrxtfVI1WTuaOG0uYxvdXTmIYwfki6fFF4qQpkiQcg8+NqpJA8Q==
 
 "@vue/compiler-core@3.2.39":
   version "3.2.39"
@@ -2486,6 +2486,13 @@ chrome-trace-event@^1.0.2:
   resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
   integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
 
+clean-css@5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.0.tgz#44e4a04e8873ff0041df97acecf23a4a6519844e"
+  integrity sha512-2639sWGa43EMmG7fn8mdVuBSs6HuWaSor+ZPoFWzenBc6oN+td8YhTfghWXZ25G1NiiSvz8bOFBS7PdSbTiqEA==
+  dependencies:
+    source-map "~0.6.0"
+
 clean-css@^5.2.2:
   version "5.3.1"
   resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.1.tgz#d0610b0b90d125196a2894d35366f734e5d7aa32"
@@ -2604,15 +2611,20 @@ commander@^9.3.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
   integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
 
+commander@^9.4.0:
+  version "9.4.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd"
+  integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==
+
 commondir@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
   integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
 
-compare-versions@^4.1.2:
-  version "4.1.4"
-  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-4.1.4.tgz#3571f4d610924d4414846a4183d386c8f3d51112"
-  integrity sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==
+compare-versions@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.1.tgz#14c6008436d994c3787aba38d4087fabe858555e"
+  integrity sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ==
 
 compress-commons@^4.1.0:
   version "4.1.1"
@@ -3166,7 +3178,7 @@ entities@^2.0.0:
   resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
   integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
 
-entities@^4.4.0:
+entities@^4.3.1, entities@^4.4.0:
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
   integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
@@ -3996,15 +4008,15 @@ html-entities@^2.3.2:
   resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46"
   integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==
 
-html-loader@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-4.1.0.tgz#a2f935802675fef0703165491316b200600996be"
-  integrity sha512-QDDNmLgn96NWtTPx/VXRerFXH0hn7cm4bruqsZ333GCb+rqiqGurcxtP/M52wcui1/iLiu0l5ms/McE7/Ik6aQ==
+html-loader@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-4.2.0.tgz#20f69f9ec69244860c250ae6ee0046c8c5c4d348"
+  integrity sha512-OxCHD3yt+qwqng2vvcaPApCEvbx+nXWu+v69TYHx1FO8bffHn/JjHtE3TTQZmHjwvnJe4xxzuecetDVBrQR1Zg==
   dependencies:
-    html-minifier-terser "^6.1.0"
+    html-minifier-terser "^7.0.0"
     parse5 "^7.0.0"
 
-html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0:
+html-minifier-terser@^6.0.2:
   version "6.1.0"
   resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab"
   integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==
@@ -4017,6 +4029,19 @@ html-minifier-terser@^6.0.2, html-minifier-terser@^6.1.0:
     relateurl "^0.2.7"
     terser "^5.10.0"
 
+html-minifier-terser@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-7.0.0.tgz#e0ce8f10befeff89f29f19490f87213b85adaa4c"
+  integrity sha512-Adqk0b/pWKIQiGvEAuzPKpBKNHiwblr3QSGS7TTr6v+xXKV9AI2k4vWW+6Oytt6Z5SeBnfvYypKOnz8r75pz3Q==
+  dependencies:
+    camel-case "^4.1.2"
+    clean-css "5.2.0"
+    commander "^9.4.0"
+    entities "^4.3.1"
+    param-case "^3.0.4"
+    relateurl "^0.2.7"
+    terser "^5.14.2"
+
 html-webpack-plugin@^5.5.0:
   version "5.5.0"
   resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50"
@@ -5831,7 +5856,7 @@ select-hose@^2.0.0:
   resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
   integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==
 
-selfsigned@^2.0.1:
+selfsigned@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61"
   integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==
@@ -6281,6 +6306,16 @@ terser@^5.10.0, terser@^5.14.1:
     commander "^2.20.0"
     source-map-support "~0.5.20"
 
+terser@^5.14.2:
+  version "5.15.1"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c"
+  integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==
+  dependencies:
+    "@jridgewell/source-map" "^0.3.2"
+    acorn "^8.5.0"
+    commander "^2.20.0"
+    source-map-support "~0.5.20"
+
 text-segmentation@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
@@ -6625,10 +6660,10 @@ webpack-dev-middleware@^5.3.1:
     range-parser "^1.2.1"
     schema-utils "^4.0.0"
 
-webpack-dev-server@^4.11.0:
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz#290ee594765cd8260adfe83b2d18115ea04484e7"
-  integrity sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==
+webpack-dev-server@^4.11.1:
+  version "4.11.1"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz#ae07f0d71ca0438cf88446f09029b92ce81380b5"
+  integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==
   dependencies:
     "@types/bonjour" "^3.5.9"
     "@types/connect-history-api-fallback" "^1.3.5"
@@ -6653,7 +6688,7 @@ webpack-dev-server@^4.11.0:
     p-retry "^4.5.0"
     rimraf "^3.0.2"
     schema-utils "^4.0.0"
-    selfsigned "^2.0.1"
+    selfsigned "^2.1.1"
     serve-index "^1.9.1"
     sockjs "^0.3.24"
     spdy "^4.0.2"