Ahmad Kholid 3 年之前
父节点
当前提交
c532ff130d
共有 29 个文件被更改,包括 718 次插入183 次删除
  1. 2 2
      package.json
  2. 31 0
      src/background/index.js
  3. 132 0
      src/background/workflow-engine/blocks-handler/handler-browser-event.js
  4. 4 1
      src/background/workflow-engine/blocks-handler/handler-interaction-block.js
  5. 1 1
      src/background/workflow-engine/blocks-handler/handler-new-tab.js
  6. 5 3
      src/background/workflow-engine/blocks-handler/handler-switch-to.js
  7. 1 1
      src/background/workflow-engine/blocks-handler/handler-trigger.js
  8. 1 4
      src/background/workflow-engine/engine.js
  9. 1 5
      src/background/workflow-engine/execute-content-script.js
  10. 1 1
      src/components/block/BlockBase.vue
  11. 1 1
      src/components/block/BlockConditions.vue
  12. 11 1
      src/components/block/BlockGroup.vue
  13. 1 1
      src/components/newtab/workflow/WorkflowDetailsCard.vue
  14. 1 1
      src/components/newtab/workflow/WorkflowEditBlock.vue
  15. 25 19
      src/components/newtab/workflow/WorkflowSettings.vue
  16. 116 0
      src/components/newtab/workflow/edit/EditBrowserEvent.vue
  17. 58 0
      src/components/newtab/workflow/edit/EditUploadFile.vue
  18. 1 1
      src/components/ui/UiPagination.vue
  19. 5 1
      src/content/blocks-handler/handler-event-click.js
  20. 42 0
      src/content/blocks-handler/handler-upload-file.js
  21. 4 0
      src/lib/v-remixicon.js
  22. 16 1
      src/locales/en/blocks.json
  23. 2 1
      src/locales/en/common.json
  24. 4 3
      src/locales/en/newtab.json
  25. 1 0
      src/models/workflow.js
  26. 12 0
      src/newtab/pages/Workflows.vue
  27. 1 1
      src/newtab/pages/workflows/[id].vue
  28. 41 0
      src/utils/shared.js
  29. 197 134
      yarn.lock

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "automa",
-  "version": "0.15.4",
+  "version": "0.16.0",
   "description": "An extension for automating your browser by connecting blocks",
   "license": "MIT",
   "repository": {
@@ -35,7 +35,7 @@
     "idb": "^7.0.0",
     "mitt": "^3.0.0",
     "mousetrap": "^1.6.5",
-    "nanoid": "3.1.28",
+    "nanoid": "^3.2.0",
     "object-path-immutable": "^4.1.2",
     "papaparse": "^5.3.1",
     "tippy.js": "^6.3.1",

+ 31 - 0
src/background/index.js

@@ -168,6 +168,37 @@ message.on('open:dashboard', async (url) => {
 message.on('get:sender', (_, sender) => {
   return sender;
 });
+message.on('get:file', (path) => {
+  return new Promise((resolve, reject) => {
+    const isFile = /\.(.*)/.test(path);
+
+    if (!isFile) {
+      reject(new Error(`"${path}" is invalid file path.`));
+      return;
+    }
+
+    const fileUrl = path.startsWith('file://') ? path : `file://${path}`;
+
+    const xhr = new XMLHttpRequest();
+    xhr.responseType = 'blob';
+    xhr.onreadystatechange = () => {
+      if (xhr.readyState === XMLHttpRequest.DONE) {
+        if (xhr.status === 0 || xhr.status === 200) {
+          const objUrl = URL.createObjectURL(xhr.response);
+
+          resolve({ path, objUrl, type: xhr.response.type });
+        } else {
+          reject(new Error(xhr.statusText));
+        }
+      }
+    };
+    xhr.onerror = function () {
+      reject(new Error(xhr.statusText));
+    };
+    xhr.open('GET', fileUrl);
+    xhr.send();
+  });
+});
 
 message.on('collection:execute', (collection) => {
   const engine = new CollectionEngine(collection, {

+ 132 - 0
src/background/workflow-engine/blocks-handler/handler-browser-event.js

@@ -0,0 +1,132 @@
+import browser from 'webextension-polyfill';
+import { getBlockConnection } from '../helper';
+import { isWhitespace } from '@/utils/helper';
+
+function handleEventListener(target, validate) {
+  return (data, activeTab) => {
+    return new Promise((resolve) => {
+      let resolved = false;
+      const eventListener = (event) => {
+        if (resolved) return;
+        if (validate && !validate(event, { data, activeTab })) return;
+
+        target.removeListener(eventListener);
+        resolve(event);
+      };
+
+      setTimeout(() => {
+        resolved = true;
+        target.removeListener(eventListener);
+        resolve('');
+      }, data.timeout || 10000);
+
+      target.addListener(eventListener);
+    });
+  };
+}
+
+function onTabLoaded({ tabLoadedUrl, activeTabLoaded, timeout }, { id }) {
+  return new Promise((resolve, reject) => {
+    let resolved = false;
+
+    const checkActiveTabStatus = () => {
+      if (resolved) return;
+      if (!id) {
+        reject(new Error('no-tab'));
+        return;
+      }
+
+      browser.tabs
+        .get(id)
+        .then((tab) => {
+          if (tab.status === 'complete') {
+            resolve();
+            return;
+          }
+
+          setTimeout(checkActiveTabStatus, 1000);
+        })
+        .catch(reject);
+    };
+
+    const url = isWhitespace(tabLoadedUrl)
+      ? '<all_urls>'
+      : tabLoadedUrl.replace(/\s/g, '').split(',');
+    const checkTabsStatus = () => {
+      browser.tabs
+        .query({
+          url,
+          status: 'loading',
+        })
+        .then((tabs) => {
+          if (resolved) return;
+          if (tabs.length === 0) {
+            resolve();
+            return;
+          }
+
+          setTimeout(checkTabsStatus, 1000);
+        })
+        .catch(reject);
+    };
+
+    if (activeTabLoaded) checkActiveTabStatus();
+    else checkTabsStatus();
+
+    setTimeout(() => {
+      resolved = true;
+      resolve('');
+    }, timeout || 10000);
+  });
+}
+
+const validateCreatedTab = ({ url }, { data }) => {
+  if (!isWhitespace(data.tabUrl)) {
+    const regex = new RegExp(data.tabUrl, 'gi');
+
+    if (!regex.test(url)) return false;
+  }
+
+  return true;
+};
+const events = {
+  'tab:loaded': onTabLoaded,
+  'tab:close': handleEventListener(browser.tabs.onRemoved),
+  'tab:create': handleEventListener(
+    browser.webNavigation.onCreatedNavigationTarget,
+    validateCreatedTab
+  ),
+  'window:create': handleEventListener(
+    browser.webNavigation.onCreatedNavigationTarget,
+    validateCreatedTab
+  ),
+  'window:close': handleEventListener(browser.windows.onRemoved),
+};
+
+export default async function ({ data, outputs }) {
+  const nextBlockId = getBlockConnection({ outputs });
+
+  try {
+    const currentEvent = events[data.eventName];
+
+    if (!currentEvent) {
+      throw new Error(`Can't find ${data.eventName} event`);
+    }
+
+    const result = await currentEvent(data, this.activeTab);
+
+    if (data.eventName === 'tab:create' && data.setAsActiveTab) {
+      this.activeTab.id = result.tabId;
+      this.activeTab.url = result.url;
+    }
+
+    return {
+      nextBlockId,
+      data: result || '',
+    };
+  } catch (error) {
+    error.nextBlockId = nextBlockId;
+
+    throw error;
+  }
+}

+ 4 - 1
src/background/workflow-engine/blocks-handler/handler-interaction-block.js

@@ -2,12 +2,15 @@ import { objectHasKey } from '@/utils/helper';
 import { getBlockConnection } from '../helper';
 
 async function interactionHandler(block, { refData }) {
+  const { executedBlockOnWeb, debugMode } = this.workflow.settings;
+
   const nextBlockId = getBlockConnection(block);
   const messagePayload = {
     ...block,
     refData,
+    debugMode,
+    executedBlockOnWeb,
     frameSelector: this.frameSelector,
-    executedBlockOnWeb: this.workflow.settings?.executedBlockOnWeb,
   };
 
   try {

+ 1 - 1
src/background/workflow-engine/blocks-handler/handler-new-tab.js

@@ -48,7 +48,7 @@ async function newTab(block) {
     }
 
     this.activeTab.frameId = 0;
-    this.activeTab.frames = await executeContentScript(this.activeTab.id);
+    await executeContentScript(this.activeTab.id);
 
     return {
       data: url,

+ 5 - 3
src/background/workflow-engine/blocks-handler/handler-switch-to.js

@@ -1,6 +1,6 @@
 import { objectHasKey } from '@/utils/helper';
 import { getBlockConnection } from '../helper';
-import executeContentScript from '../execute-content-script';
+import executeContentScript, { getFrames } from '../execute-content-script';
 
 async function switchTo(block) {
   const nextBlockId = getBlockConnection(block);
@@ -30,8 +30,10 @@ async function switchTo(block) {
       };
     }
 
-    if (objectHasKey(this.activeTab.frames, url)) {
-      this.activeTab.frameId = this.activeTab.frames[url];
+    const frames = await getFrames(this.activeTab.id);
+
+    if (objectHasKey(frames, url)) {
+      this.activeTab.frameId = frames[url];
 
       await executeContentScript(this.activeTab.id, this.activeTab.frameId);
       await new Promise((resolve) => setTimeout(resolve, 1000));

+ 1 - 1
src/background/workflow-engine/blocks-handler/handler-trigger.js

@@ -6,7 +6,7 @@ async function trigger(block) {
 
   try {
     if (block.data.type === 'visit-web' && this.activeTab.id) {
-      this.activeTab.frames = await executeContentScript(this.activeTab.id);
+      await executeContentScript(this.activeTab.id);
     }
 
     return { nextBlockId, data: '' };

+ 1 - 4
src/background/workflow-engine/engine.js

@@ -344,11 +344,8 @@ class WorkflowEngine {
       }
 
       await waitTabLoaded(this.activeTab.id);
+      await executeContentScript(this.activeTab.id, options.frameId || 0);
 
-      this.activeTab.frames = await executeContentScript(
-        this.activeTab.id,
-        options.frameId || 0
-      );
       const data = await browser.tabs.sendMessage(
         this.activeTab.id,
         { isBlock: true, ...payload },

+ 1 - 5
src/background/workflow-engine/execute-content-script.js

@@ -44,12 +44,8 @@ export default async function (tabId, frameId = 0) {
         file: './contentScript.bundle.js',
       });
     }
-
-    const frames = await getFrames(tabId);
-
-    return frames;
   } catch (error) {
     console.error(error);
-    return {};
+    throw error;
   }
 }

+ 1 - 1
src/components/block/BlockBase.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="block-base relative">
+  <div class="block-base relative" @dblclick="$emit('edit')">
     <div
       :class="contentClass"
       class="z-10 bg-white relative rounded-lg overflow-hidden w-full p-4"

+ 1 - 1
src/components/block/BlockConditions.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :id="componentId" class="p-4">
+  <div :id="componentId" class="p-4" @dblclick="editBlock">
     <div class="flex items-center">
       <div
         :class="block.category.color"

+ 11 - 1
src/components/block/BlockGroup.vue

@@ -87,6 +87,7 @@
 import { watch } from 'vue';
 import { useI18n } from 'vue-i18n';
 import { nanoid } from 'nanoid';
+import { useToast } from 'vue-toastification';
 import draggable from 'vuedraggable';
 import emitter from '@/lib/mitt';
 import { tasks } from '@/utils/shared';
@@ -101,6 +102,7 @@ const props = defineProps({
 });
 
 const { t } = useI18n();
+const toast = useToast();
 const componentId = useComponentId('blocks-group');
 const block = useEditorBlock(`#${componentId}`, props.editor);
 
@@ -149,7 +151,15 @@ function handleDrop(event) {
 
   const { id, data } = droppedBlock;
 
-  if (excludeBlocks.includes(id)) return;
+  if (excludeBlocks.includes(id)) {
+    toast.error(
+      t('workflow.blocks.blocks-group.cantAdd', {
+        blockName: t(`workflow.blocks.${id}.name`),
+      })
+    );
+
+    return;
+  }
 
   block.data.blocks.push({ id, data, itemId: nanoid(5) });
 }

+ 1 - 1
src/components/newtab/workflow/WorkflowDetailsCard.vue

@@ -89,7 +89,7 @@
             <v-remixicon name="riInformationLine" size="18" />
           </a>
           <v-remixicon :name="block.icon" size="24" class="mb-2" />
-          <p class="leading-tight text-overflow">
+          <p class="leading-tight text-overflow capitalize">
             {{ block.name }}
           </p>
         </div>

+ 1 - 1
src/components/newtab/workflow/WorkflowEditBlock.vue

@@ -6,7 +6,7 @@
       <button class="mr-2" @click="$emit('close')">
         <v-remixicon name="riArrowLeftLine" />
       </button>
-      <p class="font-semibold inline-block flex-1">
+      <p class="font-semibold inline-block flex-1 capitalize">
         {{ t(`workflow.blocks.${data.id}.name`) }}
       </p>
       <a

+ 25 - 19
src/components/newtab/workflow/WorkflowSettings.vue

@@ -1,22 +1,29 @@
 <template>
   <div class="workflow-settings">
-    <div class="mb-6">
-      <p class="mb-1">{{ t('workflow.settings.onError.title') }}</p>
-      <div class="space-x-4">
-        <ui-radio
+    <div class="mb-4">
+      <p class="mb-1 capitalize">
+        {{ t('workflow.settings.onError.title') }}
+      </p>
+      <div class="space-x-4 flex w-full max-w-sm items-center">
+        <div
           v-for="item in onError"
           :key="item.id"
-          :model-value="settings.onError"
-          :value="item.id"
-          class="mr-4"
-          @change="settings.onError = $event"
+          class="p-3 rounded-lg border transition-colors w-full hoverable"
+          @click="settings.onError = item.id"
         >
-          {{ item.name }}
-        </ui-radio>
+          <ui-radio
+            :model-value="settings.onError"
+            :value="item.id"
+            class="capitalize"
+            @change="settings.onError = $event"
+          >
+            {{ item.name }}
+          </ui-radio>
+        </div>
       </div>
     </div>
     <div>
-      <p class="mb-1">
+      <p class="mb-1 capitalize">
         {{ t('workflow.settings.blockDelay.title') }}
         <span :title="t('workflow.settings.blockDelay.description')">
           &#128712;
@@ -28,13 +35,17 @@
         class="w-full max-w-sm"
       />
     </div>
+    <div v-if="false" class="flex mt-6">
+      <ui-switch v-model="settings.debugMode" class="mr-4" />
+      <p class="capitalize">{{ t('workflow.settings.debugMode') }}</p>
+    </div>
     <div class="flex mt-6">
       <ui-switch v-model="settings.saveLog" class="mr-4" />
-      <p>{{ t('workflow.settings.saveLog') }}</p>
+      <p class="capitalize">{{ t('workflow.settings.saveLog') }}</p>
     </div>
     <div class="flex mt-6">
       <ui-switch v-model="settings.executedBlockOnWeb" class="mr-4" />
-      <p>{{ t('workflow.settings.executedBlockOnWeb') }}</p>
+      <p class="capitalize">{{ t('workflow.settings.executedBlockOnWeb') }}</p>
     </div>
   </div>
 </template>
@@ -63,12 +74,7 @@ const onError = [
   },
 ];
 
-const settings = reactive({
-  blockDelay: 0,
-  saveLog: true,
-  onError: 'stop-workflow',
-  executedBlockOnWeb: false,
-});
+const settings = reactive({});
 
 watch(
   settings,

+ 116 - 0
src/components/newtab/workflow/edit/EditBrowserEvent.vue

@@ -0,0 +1,116 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      class="w-full"
+      :placeholder="t('common.description')"
+      @change="updateData({ description: $event })"
+    />
+    <ui-input
+      :model-value="data.timeout"
+      :label="t('workflow.blocks.browser-event.timeout')"
+      type="number"
+      class="w-full"
+      @change="updateData({ timeout: +$event })"
+    />
+    <ui-select
+      :placeholder="t('workflow.blocks.browser-event.events')"
+      :model-value="data.eventName"
+      class="mt-2 w-full"
+      @change="updateData({ eventName: $event })"
+    >
+      <optgroup
+        v-for="(events, label) in browserEvents"
+        :key="label"
+        :label="label"
+      >
+        <option v-for="event in events" :key="event.id" :value="event.id">
+          {{ event.name }}
+        </option>
+      </optgroup>
+    </ui-select>
+    <template v-if="data.eventName === 'tab:loaded'">
+      <ui-input
+        v-if="!data.activeTabLoaded"
+        :model-value="data.tabLoadedUrl"
+        type="url"
+        class="w-full mt-1"
+        placeholder="*://*.example.org/*"
+        @change="updateData({ tabLoadedUrl: $event })"
+      >
+        <template #label>
+          <span>Match pattern</span>
+          <a
+            href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns#examples"
+            target="_blank"
+            rel="noopener"
+            title="Examples"
+          >
+            <v-remixicon
+              class="inline-block ml-1"
+              name="riInformationLine"
+              size="18"
+            />
+          </a>
+        </template>
+      </ui-input>
+      <ui-checkbox
+        :model-value="data.activeTabLoaded"
+        class="mt-1"
+        @change="updateData({ activeTabLoaded: $event })"
+      >
+        {{ t('workflow.blocks.browser-event.activeTabLoaded') }}
+      </ui-checkbox>
+    </template>
+    <template v-if="['tab:create', 'window:create'].includes(data.eventName)">
+      <ui-input
+        :model-value="data.tabUrl"
+        type="url"
+        label="Filter"
+        class="w-full mt-1"
+        placeholder="URL or Regex"
+        @change="updateData({ tabUrl: $event })"
+      />
+      <ui-checkbox
+        :model-value="data.setAsActiveTab"
+        class="mt-1"
+        @change="updateData({ setAsActiveTab: $event })"
+      >
+        {{ t('workflow.blocks.browser-event.setAsActiveTab') }}
+      </ui-checkbox>
+    </template>
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+const browserEvents = {
+  Tab: [
+    { id: 'tab:close', name: 'Tab closed' },
+    { id: 'tab:loaded', name: 'Tab loaded' },
+    { id: 'tab:create', name: 'Tab created' },
+  ],
+  // 'Downloads': [
+  //   { id: 'download:start', name: 'Download started' },
+  //   { id: 'download:complete', name: 'Download complete' },
+  // ],
+  Window: [
+    { id: 'window:create', name: 'Window created' },
+    { id: 'window:close', name: 'Window closed' },
+  ],
+};
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+</script>

+ 58 - 0
src/components/newtab/workflow/edit/EditUploadFile.vue

@@ -0,0 +1,58 @@
+<template>
+  <edit-interaction-base v-bind="{ data, hide: hideBase }" @change="updateData">
+    <div class="mt-4 space-y-2">
+      <div
+        v-for="(path, index) in filePaths"
+        :key="index"
+        class="flex items-center group"
+      >
+        <ui-input
+          v-model="filePaths[index]"
+          :placeholder="t('workflow.blocks.upload-file.filePath')"
+          class="mr-2"
+        />
+        <v-remixicon
+          name="riDeleteBin7Line"
+          class="invisible cursor-pointer group-hover:visible"
+          @click="filePaths.splice(index, 1)"
+        />
+      </div>
+    </div>
+    <ui-button variant="accent" class="mt-2" @click="filePaths.push('')">
+      {{ t('workflow.blocks.upload-file.addFile') }}
+    </ui-button>
+  </edit-interaction-base>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+import { ref, watch } from 'vue';
+import EditInteractionBase from './EditInteractionBase.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+  hideBase: {
+    type: Boolean,
+    default: false,
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+const filePaths = ref([...props.data.filePaths]);
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+
+watch(
+  filePaths,
+  (paths) => {
+    updateData({ filePaths: paths });
+  },
+  { deep: true }
+);
+</script>

+ 1 - 1
src/components/ui/UiPagination.vue

@@ -55,7 +55,7 @@ const emit = defineEmits(['update:modelValue', 'paginate']);
 const { t } = useI18n();
 
 const inputEl = ref(null);
-const maxPage = computed(() => Math.round(props.records / props.perPage) + 1);
+const maxPage = computed(() => Math.ceil(props.records / props.perPage));
 
 function emitEvent(page) {
   emit('update:modelValue', page);

+ 5 - 1
src/content/blocks-handler/handler-event-click.js

@@ -4,7 +4,11 @@ function eventClick(block) {
   return new Promise((resolve, reject) => {
     handleElement(block, {
       onSelected(element) {
-        element.click();
+        if (element.click) {
+          element.click();
+        } else {
+          element.dispatchEvent(new MouseEvent('click', { bubbles: true }));
+        }
       },
       onError(error) {
         reject(error);

+ 42 - 0
src/content/blocks-handler/handler-upload-file.js

@@ -0,0 +1,42 @@
+import { sendMessage } from '@/utils/message';
+import { handleElement } from '../helper';
+
+function injectFiles(element, files) {
+  const notFileTypeAttr = element.getAttribute('type') !== 'file';
+
+  if (element.tagName !== 'INPUT' || notFileTypeAttr) return;
+
+  element.files = files;
+
+  element.dispatchEvent(new Event('change', { bubbles: true }));
+}
+
+export default async function (block) {
+  const elements = handleElement(block, { returnElement: true });
+
+  if (!elements) throw new Error('element-not-found');
+
+  const getFile = async (path) => {
+    const file = await sendMessage('get:file', path, 'background');
+    const name = file.path.replace(/^.*[\\/]/, '');
+    const blob = await fetch(file.objUrl).then((response) => response.blob());
+
+    URL.revokeObjectURL(file.objUrl);
+
+    return new File([blob], name, { type: file.type });
+  };
+  const filesPromises = await Promise.all(block.data.filePaths.map(getFile));
+  const dataTransfer = filesPromises.reduce((acc, file) => {
+    acc.items.add(file);
+
+    return acc;
+  }, new DataTransfer());
+
+  if (block.data.multiple) {
+    elements.forEach((element) => {
+      injectFiles(element, dataTransfer.files);
+    });
+  } else {
+    injectFiles(elements, dataTransfer.files);
+  }
+}

+ 4 - 0
src/lib/v-remixicon.js

@@ -1,6 +1,8 @@
 import vRemixicon from 'v-remixicon';
 import {
   riHome5Line,
+  riFileUploadLine,
+  riLightbulbLine,
   riSideBarLine,
   riSideBarFill,
   riFolderZipLine,
@@ -81,6 +83,8 @@ import {
 
 export const icons = {
   riHome5Line,
+  riFileUploadLine,
+  riLightbulbLine,
   riSideBarLine,
   riSideBarFill,
   riFolderZipLine,

+ 16 - 1
src/locales/en/blocks.json

@@ -27,11 +27,26 @@
           "text": "Multiple"
         }
       },
+      "upload-file": {
+        "name": "Upload file",
+        "description": "Upload file into <input type=\"file\"> element",
+        "filePath": "File path",
+        "addFile": "Add file"
+      },
+      "browser-event": {
+        "name": "Browser event",
+        "description": "Execute the next block when the event is triggered",
+        "events": "Events",
+        "timeout": "Timeout (milliseconds)",
+        "activeTabLoaded": "Active tab",
+        "setAsActiveTab": "Set as active tab"
+      },
       "blocks-group": {
         "name": "Blocks group",
         "groupName": "Group name",
         "description": "Grouping blocks",
-        "dropText": "Drag & drop a block here"
+        "dropText": "Drag & drop a block here",
+        "cantAdd": "Can't add \"{blockName}\" block to the group."
       },
       "trigger": {
         "name": "Trigger",

+ 2 - 1
src/locales/en/common.json

@@ -31,7 +31,8 @@
     "disabled": "Disabled",
     "enable": "Enable",
     "fallback": "Fallback",
-    "update": "Update"
+    "update": "Update",
+    "duplicate": "Duplicate"
   },
   "message": {
     "noBlock": "No block",

+ 4 - 3
src/locales/en/newtab.json

@@ -52,6 +52,9 @@
       "duplicate": "Duplicate"
     },
     "settings": {
+      "saveLog": "Save workflow log",
+      "executedBlockOnWeb": "Show executed block on web page",
+      "debugMode": "Debug mode",
       "onError": {
         "title": "On workflow error",
         "items": {
@@ -65,9 +68,7 @@
       "blockDelay": {
         "title": "Block delay (milliseconds)",
         "description": "Add delay before executing each of the blocks"
-      },
-      "saveLog": "Save workflow log",
-      "executedBlockOnWeb": "Show executed block on web page"
+      }
     }
   },
   "collection": {

+ 1 - 0
src/models/workflow.js

@@ -26,6 +26,7 @@ class Workflow extends Model {
       settings: this.attr({
         blockDelay: 0,
         saveLog: true,
+        debugMode: false,
         onError: 'stop-workflow',
         executedBlockOnWeb: false,
       }),

+ 12 - 0
src/newtab/pages/Workflows.vue

@@ -189,6 +189,7 @@ const { t } = useI18n();
 
 const sorts = ['name', 'createdAt'];
 const menu = [
+  { id: 'duplicate', name: t('common.duplicate'), icon: 'riFileCopyLine' },
   { id: 'export', name: t('common.export'), icon: 'riDownloadLine' },
   { id: 'rename', name: t('common.rename'), icon: 'riPencilLine' },
   { id: 'delete', name: t('common.delete'), icon: 'riDeleteBin7Line' },
@@ -285,6 +286,16 @@ async function handleWorkflowModal() {
     console.error(error);
   }
 }
+function duplicateWorkflow(workflow) {
+  const copyWorkflow = { ...workflow, createdAt: Date.now() };
+  const delKeys = ['$id', 'data', 'id', 'isDisabled'];
+
+  delKeys.forEach((key) => {
+    delete copyWorkflow[key];
+  });
+
+  Workflow.insert({ data: copyWorkflow });
+}
 
 const shortcut = useShortcut(['action:search', 'action:new'], ({ id }) => {
   if (id === 'action:search') {
@@ -298,6 +309,7 @@ const menuHandlers = {
   export: exportWorkflow,
   rename: renameWorkflow,
   delete: deleteWorkflow,
+  duplicate: duplicateWorkflow,
 };
 
 watch(

+ 1 - 1
src/newtab/pages/workflows/[id].vue

@@ -409,7 +409,7 @@ onUnmounted(() => {
 <style>
 .ghost-task {
   height: 40px;
-  @apply bg-box-transparent;
+  @apply bg-gray-200;
 }
 .ghost-task:not(.workflow-task) * {
   display: none;

+ 41 - 0
src/utils/shared.js

@@ -181,6 +181,28 @@ export const tasks = {
       captureActiveTab: true,
     },
   },
+  'browser-event': {
+    name: 'Browser event',
+    description: 'Wait until the selected event is triggered',
+    icon: 'riLightbulbLine',
+    component: 'BlockBasic',
+    category: 'browser',
+    editComponent: 'EditBrowserEvent',
+    inputs: 1,
+    outputs: 1,
+    maxConnection: 1,
+    allowedInputs: true,
+    data: {
+      description: '',
+      timeout: 10000,
+      eventName: 'tab:loaded',
+      setAsActiveTab: true,
+      activeTabLoaded: true,
+      tabLoadedUrl: '',
+      tabUrl: '',
+      fileQuery: '',
+    },
+  },
   'event-click': {
     name: 'Click element',
     icon: 'riCursorLine',
@@ -533,6 +555,7 @@ export const tasks = {
       loopData: '[]',
       description: '',
       referenceKey: '',
+      specificRowAndCol: false,
       loopThrough: 'data-columns',
     },
   },
@@ -586,6 +609,24 @@ export const tasks = {
       windowType: 'main-window',
     },
   },
+  'upload-file': {
+    name: 'Upload file',
+    description: 'Upload file into <input type="file"> element',
+    icon: 'riFileUploadLine',
+    component: 'BlockBasic',
+    editComponent: 'EditUploadFile',
+    category: 'interaction',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    refDataKeys: ['selector'],
+    data: {
+      findBy: 'cssSelector',
+      selector: '',
+      filePaths: [],
+    },
+  },
 };
 
 export const categories = {

+ 197 - 134
yarn.lock

@@ -10,11 +10,11 @@
     "@babel/highlight" "^7.10.4"
 
 "@babel/code-frame@^7.0.0":
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431"
-  integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
+  integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
   dependencies:
-    "@babel/highlight" "^7.16.0"
+    "@babel/highlight" "^7.16.7"
 
 "@babel/code-frame@^7.14.5":
   version "7.14.5"
@@ -236,7 +236,7 @@
   dependencies:
     "@babel/types" "^7.15.4"
 
-"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.15.7":
+"@babel/helper-validator-identifier@^7.14.5":
   version "7.15.7"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
   integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
@@ -246,6 +246,11 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
   integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
 
+"@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
+  integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+
 "@babel/helper-validator-option@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
@@ -279,7 +284,7 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/highlight@^7.14.5", "@babel/highlight@^7.16.0":
+"@babel/highlight@^7.14.5":
   version "7.16.0"
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a"
   integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==
@@ -288,6 +293,15 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.16.7":
+  version "7.16.10"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88"
+  integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.16.7"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
 "@babel/parser@^7.15.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.0":
   version "7.15.6"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.6.tgz#043b9aa3c303c0722e5377fef9197f4cf1796549"
@@ -906,14 +920,14 @@
     to-fast-properties "^2.0.0"
 
 "@codemirror/autocomplete@^0.19.0":
-  version "0.19.9"
-  resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-0.19.9.tgz#28b6600ad617bdc8dfeb0102a1df8cc61883d87c"
-  integrity sha512-Ph1LWHtFFqNUIqEVrws6I263ihe5TH+TRBPwxQ78j7st7Q67FDAmgKX6mNbUPh02dxfqQrc9qxlo5JIqKeiVdg==
+  version "0.19.12"
+  resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-0.19.12.tgz#4c9e4487b45e6877807e4f16c1fffd5e7639ae52"
+  integrity sha512-zUQYo5gMdv7vhxlKoAY/vnNCGzlE9AU7+P649v3ovpQpoFdo3U1Nt01EJqFb4Sfaw6l1U/Elc9Iksd1lDy+MVw==
   dependencies:
     "@codemirror/language" "^0.19.0"
     "@codemirror/state" "^0.19.4"
     "@codemirror/text" "^0.19.2"
-    "@codemirror/tooltip" "^0.19.0"
+    "@codemirror/tooltip" "^0.19.12"
     "@codemirror/view" "^0.19.0"
     "@lezer/common" "^0.15.0"
 
@@ -990,7 +1004,7 @@
     "@codemirror/state" "^0.19.0"
     "@codemirror/view" "^0.19.23"
 
-"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6":
+"@codemirror/highlight@^0.19.0":
   version "0.19.6"
   resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.6.tgz#7f2e066f83f5649e8e0748a3abe0aaeaf64b8ac2"
   integrity sha512-+eibu6on9quY8uN3xJ/n3rH+YIDLlpX7YulVmFvqAIz/ukRQ5tWaBmB7fMixHmnmRIRBRZgB8rNtonuMwZSAHQ==
@@ -1002,6 +1016,18 @@
     "@lezer/common" "^0.15.0"
     style-mod "^4.0.0"
 
+"@codemirror/highlight@^0.19.7":
+  version "0.19.7"
+  resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.7.tgz#91a0c9994c759f5f153861e3aae74ff9e7c7c35b"
+  integrity sha512-3W32hBCY0pbbv/xidismw+RDMKuIag+fo4kZIbD7WoRj+Ttcaxjf+vP6RttRHXLaaqbWh031lTeON8kMlDhMYw==
+  dependencies:
+    "@codemirror/language" "^0.19.0"
+    "@codemirror/rangeset" "^0.19.0"
+    "@codemirror/state" "^0.19.3"
+    "@codemirror/view" "^0.19.0"
+    "@lezer/common" "^0.15.0"
+    style-mod "^4.0.0"
+
 "@codemirror/history@^0.19.0":
   version "0.19.0"
   resolved "https://registry.yarnpkg.com/@codemirror/history/-/history-0.19.0.tgz#cc8095c927c9566f7b69fa404074edde4c54d39c"
@@ -1011,12 +1037,12 @@
     "@codemirror/view" "^0.19.0"
 
 "@codemirror/lang-javascript@^0.19.3":
-  version "0.19.3"
-  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-0.19.3.tgz#281b3447d8b65d98311ebf25893ef5c30a11418b"
-  integrity sha512-2NE5z98Nz9Rv4OS5UtgehCSnyQjac+P85+evzy1D/4wllp/EPaHIEEtSP1daBvrLy49SdI/9vES3ZJu6rSv4/w==
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-0.19.6.tgz#bab4ea9ba65189e4bd77c9496275c82e2b6814e7"
+  integrity sha512-NgkoCIc3hdTNTBRIRuPqfUJ0WB798qEgwAgtjwYy6yoiK5CzbDS2z5CFW17h9RmaAx6t1m64iY2CZ3tC7r15Gw==
   dependencies:
     "@codemirror/autocomplete" "^0.19.0"
-    "@codemirror/highlight" "^0.19.6"
+    "@codemirror/highlight" "^0.19.7"
     "@codemirror/language" "^0.19.0"
     "@codemirror/lint" "^0.19.0"
     "@codemirror/state" "^0.19.0"
@@ -1075,9 +1101,9 @@
     "@codemirror/view" "^0.19.0"
 
 "@codemirror/rangeset@^0.19.0", "@codemirror/rangeset@^0.19.1", "@codemirror/rangeset@^0.19.5":
-  version "0.19.5"
-  resolved "https://registry.yarnpkg.com/@codemirror/rangeset/-/rangeset-0.19.5.tgz#82dd2583324f5d5ffacf58922170bc5f3010e076"
-  integrity sha512-L3b+RIwIRKOJ3pJLOtpkxCUjGnxZKFyPb0CjYWKnVLuzEIaEExWWK7sp6rsejxOy8RjYzfCHlFhYB4UdQN7brw==
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/rangeset/-/rangeset-0.19.6.tgz#2562850cb4ce7dd30088f4d13a13860b67e7d384"
+  integrity sha512-wYtgGnW2Jtrh2nj7vpcBoEZib+jfyilrLN6w7YMTzzSRN8xXhYRorOUg4VQIa1JwFcMQrjSCkIdqXsDqOX1cYg==
   dependencies:
     "@codemirror/state" "^0.19.0"
 
@@ -1109,7 +1135,12 @@
   dependencies:
     "@codemirror/text" "^0.19.0"
 
-"@codemirror/text@^0.19.0", "@codemirror/text@^0.19.2", "@codemirror/text@^0.19.4":
+"@codemirror/text@^0.19.0", "@codemirror/text@^0.19.2":
+  version "0.19.6"
+  resolved "https://registry.yarnpkg.com/@codemirror/text/-/text-0.19.6.tgz#9adcbd8137f69b75518eacd30ddb16fd67bbac45"
+  integrity sha512-T9jnREMIygx+TPC1bOuepz18maGq/92q2a+n4qTqObKwvNMg+8cMTslb8yxeEDEq7S3kpgGWxgO1UWbQRij0dA==
+
+"@codemirror/text@^0.19.4":
   version "0.19.5"
   resolved "https://registry.yarnpkg.com/@codemirror/text/-/text-0.19.5.tgz#75033af2476214e79eae22b81ada618815441c18"
   integrity sha512-Syu5Xc7tZzeUAM/y4fETkT0zgGr48rDG+w4U38bPwSIUr+L9S/7w2wDE1WGNzjaZPz12F6gb1gxWiSTg9ocLow==
@@ -1123,15 +1154,26 @@
     "@codemirror/state" "^0.19.0"
     "@codemirror/view" "^0.19.0"
 
-"@codemirror/tooltip@^0.19.0", "@codemirror/tooltip@^0.19.5":
-  version "0.19.10"
-  resolved "https://registry.yarnpkg.com/@codemirror/tooltip/-/tooltip-0.19.10.tgz#c9ce5f8844ef28ab24d4a5adab0fc7ed85c44b4a"
-  integrity sha512-xqIhCHr+IYoamdNLvBnU/oDh92zPnsbT1zLaFtKTFi9GI9SxOfBhWY3jfMENlK0j1C9rk8+AvwpXblPGvY/O6w==
+"@codemirror/tooltip@^0.19.12", "@codemirror/tooltip@^0.19.5":
+  version "0.19.13"
+  resolved "https://registry.yarnpkg.com/@codemirror/tooltip/-/tooltip-0.19.13.tgz#4af381aead14d9d7091258bdd6a5de7dc5f56915"
+  integrity sha512-7vgvjQjwFQ9hPejw2s+w3UR1XAYjQ5M0F9HRwutXkZHP1tBFV7LnNJ3xBD7F9SR9kAh8WgdL3BpUsEwX1aqoQg==
   dependencies:
     "@codemirror/state" "^0.19.0"
     "@codemirror/view" "^0.19.0"
 
-"@codemirror/view@^0.19.0", "@codemirror/view@^0.19.22", "@codemirror/view@^0.19.23", "@codemirror/view@^0.19.31":
+"@codemirror/view@^0.19.0", "@codemirror/view@^0.19.23":
+  version "0.19.40"
+  resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-0.19.40.tgz#1be9cac1725568b7fba2252658a6f255b29339eb"
+  integrity sha512-0CQV99+/nIKTVVbDs0XjW4Rkp8TobzJBXRaUHF6mOroVjuIBBcolE1eAGVEU5LrCS44C798jiP4r/HhLDNS+rw==
+  dependencies:
+    "@codemirror/rangeset" "^0.19.5"
+    "@codemirror/state" "^0.19.3"
+    "@codemirror/text" "^0.19.0"
+    style-mod "^4.0.0"
+    w3c-keyname "^2.2.4"
+
+"@codemirror/view@^0.19.22", "@codemirror/view@^0.19.31":
   version "0.19.37"
   resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-0.19.37.tgz#36fe17c774525c775af57e7dde2867b3b7cb400f"
   integrity sha512-SLuLx9p0O1ZHXLehvl5MwSvUrQRcsNGemzTgJ0zRajmc3BBsNigI1PXxdo7tvBhO5DcAzRRBXoke9DZFUR6Qqg==
@@ -1187,24 +1229,32 @@
     source-map "^0.6.1"
     yaml-eslint-parser "^0.3.2"
 
-"@intlify/core-base@9.2.0-beta.25":
-  version "9.2.0-beta.25"
-  resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.2.0-beta.25.tgz#f48dfc6c05fcc7d7929d88010e1b605d076224c5"
-  integrity sha512-ReJ1qytJQ1pD3YIM474MFzAFIA/MNO3LiIogXQslK89WVFxCklAQOQQOe075AMAi90ng+fZM4/bp6hslQgjn4w==
+"@intlify/core-base@9.2.0-beta.28":
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.2.0-beta.28.tgz#e8b1e4adfa7a262c6ed169ad7b15dbe2a173cb27"
+  integrity sha512-p7iXwVQFyBmEo65KoqRCbT6Ig3OI6rnaS/zeMCKtp6Bjsbg35VGAaiN05Eyrq78BCh2Ir1S6nl+Cz3y00D0yoQ==
   dependencies:
-    "@intlify/devtools-if" "9.2.0-beta.25"
-    "@intlify/message-compiler" "9.2.0-beta.25"
-    "@intlify/shared" "9.2.0-beta.25"
-    "@intlify/vue-devtools" "9.2.0-beta.25"
+    "@intlify/devtools-if" "9.2.0-beta.28"
+    "@intlify/message-compiler" "9.2.0-beta.28"
+    "@intlify/shared" "9.2.0-beta.28"
+    "@intlify/vue-devtools" "9.2.0-beta.28"
 
-"@intlify/devtools-if@9.2.0-beta.25":
-  version "9.2.0-beta.25"
-  resolved "https://registry.yarnpkg.com/@intlify/devtools-if/-/devtools-if-9.2.0-beta.25.tgz#44bcfeb43912d9eff71cbdd712964692aef7e933"
-  integrity sha512-iqBKiQ4rRP0xbbkq00o/TmfmsEBQulnCMO8JuZ5kBBroXqwyp65dQ6DbwojjP+TG0ON5IFKL39JntF96sin1LQ==
+"@intlify/devtools-if@9.2.0-beta.28":
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/@intlify/devtools-if/-/devtools-if-9.2.0-beta.28.tgz#daca7b4348a59109778558e7f5769e5f6b422d4e"
+  integrity sha512-3RL38hDBRipipoYRl4Ggu98M4/XqDKm0jW8kcOWpuocB/aZBBEGzoQfeaq09Xa9SA46podjntBlYDAOGQyXqqg==
   dependencies:
-    "@intlify/shared" "9.2.0-beta.25"
+    "@intlify/shared" "9.2.0-beta.28"
 
-"@intlify/message-compiler@9.2.0-beta.25", "@intlify/message-compiler@beta":
+"@intlify/message-compiler@9.2.0-beta.28":
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.2.0-beta.28.tgz#caae08ead8c6c02e2d0de39e1e8bdbbb99683c83"
+  integrity sha512-NBH9fZyitN2cijGt8bmU1W7ZPdhKbgW01L1RxJKFJW0cRaCmknJq63Aif1Q6xcxKt9ZhPbvIKHgPGzg1nWMfeA==
+  dependencies:
+    "@intlify/shared" "9.2.0-beta.28"
+    source-map "0.6.1"
+
+"@intlify/message-compiler@beta":
   version "9.2.0-beta.25"
   resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.2.0-beta.25.tgz#360df77b5233c05a29b0a3512cda292f22bcdfc7"
   integrity sha512-/YMG6LmQLvD8uHCJvWLaK0t8exYbek3ya4BZZ99AcM5+JC/JRdLIK8WiVJnGpfrvleQArxvHed4GokS+oWZ5rQ==
@@ -1217,13 +1267,18 @@
   resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.2.0-beta.25.tgz#a178975e77dcca59203f46269037ea1d4b858899"
   integrity sha512-I2L05aWh0azr5KwQjLV7gMTN0SrdglgMAfpJniT53Pvvc8l+OTs8IEhdPCQwsbgOravpWt14O7m3deOzw3ln6w==
 
-"@intlify/vue-devtools@9.2.0-beta.25":
-  version "9.2.0-beta.25"
-  resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.2.0-beta.25.tgz#6b0ffd2280b4bf38d74adce7d2fc74dbc655ee27"
-  integrity sha512-47rmZmrM1FihTWQkixgYu3lOCBpT1NyGfYSxSYnUw1s2Ky8w84S81nYmbus2GZjfj/zAovkKyRNclETVTy6O2Q==
+"@intlify/shared@9.2.0-beta.28":
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.2.0-beta.28.tgz#50bd3f769bcab6f80e00027761b3397e268f9d02"
+  integrity sha512-JBMcoj1D4kSAma7Vb0+d8z6lPLIn7hIdZJPxbU8bgeMMniwKLoIS/jGlEfrZihsB5+otckPeQp203z8skwVS0w==
+
+"@intlify/vue-devtools@9.2.0-beta.28":
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/@intlify/vue-devtools/-/vue-devtools-9.2.0-beta.28.tgz#60113c137a380433961934045b9cf046c8773341"
+  integrity sha512-kf9Gt64sjP1fJQHUlB3m/RFDeJBcrvRImcEl6g0BV13K/xyA9u9RGM89YpR16F5KKTXdhpkvroLWh2uo4pc6jg==
   dependencies:
-    "@intlify/core-base" "9.2.0-beta.25"
-    "@intlify/shared" "9.2.0-beta.25"
+    "@intlify/core-base" "9.2.0-beta.28"
+    "@intlify/shared" "9.2.0-beta.28"
 
 "@intlify/vue-i18n-loader@^4.0.1":
   version "4.1.0"
@@ -1256,9 +1311,9 @@
     "@lezer/lr" "^0.15.0"
 
 "@lezer/lr@^0.15.0":
-  version "0.15.5"
-  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.5.tgz#4bce44169c441d9dda7be398f5202ea65c5f1138"
-  integrity sha512-DEcLyhdmBxD1foQe7RegLrSlfS/XaTMGLkO5evkzHWAQKh/JnFWp7j7iNB7s2EpxzRrBCh0U+W7JDCeFhv2mng==
+  version "0.15.7"
+  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.7.tgz#e7e6a8a106c6474b4586a66a3e60ba85f1faf368"
+  integrity sha512-rmUukgyKSm6xzXO4cK5hkpX3+ZTHF+bHDkEuhofAVUTS3J23YytUxGWsrDwBVvGbhvxW87kheb2mRYHRwKacDQ==
   dependencies:
     "@lezer/common" "^0.15.0"
 
@@ -1697,9 +1752,9 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5:
     uri-js "^4.2.2"
 
 ajv@^8.0.0, ajv@^8.8.0:
-  version "8.8.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb"
-  integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==
+  version "8.9.0"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18"
+  integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==
   dependencies:
     fast-deep-equal "^3.1.1"
     json-schema-traverse "^1.0.0"
@@ -2279,9 +2334,9 @@ chokidar@^2.1.8:
     fsevents "^1.2.7"
 
 chokidar@^3.5.2:
-  version "3.5.2"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
-  integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
   dependencies:
     anymatch "~3.1.2"
     braces "~3.0.2"
@@ -2433,9 +2488,9 @@ commondir@^1.0.1:
   integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
 
 compare-versions@^4.1.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-4.1.2.tgz#a7b1678c897000d03a70a0e01efee43e7b04dda7"
-  integrity sha512-LAfbAbAgjnIwPsr2fvJLfrSyqAhK5nj/ffIg7a5aigry9RXJfNzVnOu0Egw8Z+G8LMDu1Qig2q48bpBzjyjZoQ==
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-4.1.3.tgz#8f7b8966aef7dc4282b45dfa6be98434fc18a1a4"
+  integrity sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==
 
 component-emitter@^1.2.1:
   version "1.3.0"
@@ -2749,9 +2804,9 @@ defined@^1.0.0:
   integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
 
 defu@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/defu/-/defu-5.0.0.tgz#5768f0d402a555bfc4c267246b20f82ce8b5a10b"
-  integrity sha512-VHg73EDeRXlu7oYWRmmrNp/nl7QkdXUxkQQKig0Zk8daNmm84AbGoC8Be6/VVLJEKxn12hR0UBmz8O+xQiAPKQ==
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/defu/-/defu-5.0.1.tgz#a034278f9b032bf0845d261aa75e9ad98da878ac"
+  integrity sha512-EPS1carKg+dkEVy3qNTqIdp2qV7mUP08nIsupfwQpz++slCVRw7qbQyWvSTig+kFPwz2XXp5/kIIkH+CwrJKkQ==
 
 del@^4.1.1:
   version "4.1.1"
@@ -3421,7 +3476,7 @@ fast-diff@^1.1.2:
   resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
   integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
 
-fast-glob@^3.1.1, fast-glob@^3.2.5, fast-glob@^3.2.7:
+fast-glob@^3.1.1, fast-glob@^3.2.5:
   version "3.2.7"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
   integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
@@ -3432,6 +3487,17 @@ fast-glob@^3.1.1, fast-glob@^3.2.5, fast-glob@^3.2.7:
     merge2 "^1.3.0"
     micromatch "^4.0.4"
 
+fast-glob@^3.2.7:
+  version "3.2.11"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
+  integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
 fast-json-stable-stringify@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
@@ -3710,7 +3776,7 @@ glob-to-regexp@^0.4.1:
   resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
   integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
 
-glob@^7.0.3, glob@^7.1.3:
+glob@^7.0.3:
   version "7.1.7"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
   integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
@@ -3722,7 +3788,7 @@ glob@^7.0.3, glob@^7.1.3:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.1.4:
+glob@^7.1.3, glob@^7.1.4:
   version "7.2.0"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
   integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
@@ -4016,13 +4082,6 @@ ignore@^5.1.4:
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
   integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
 
-import-cwd@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92"
-  integrity sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==
-  dependencies:
-    import-from "^3.0.0"
-
 import-fresh@^3.0.0, import-fresh@^3.2.1:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -4031,13 +4090,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
     parent-module "^1.0.0"
     resolve-from "^4.0.0"
 
-import-from@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966"
-  integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==
-  dependencies:
-    resolve-from "^5.0.0"
-
 import-local@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
@@ -4195,7 +4247,14 @@ is-callable@^1.1.4, is-callable@^1.2.4:
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
   integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
 
-is-core-module@^2.2.0, is-core-module@^2.7.0, is-core-module@^2.8.0:
+is-core-module@^2.2.0:
+  version "2.8.1"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
+  integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
+  dependencies:
+    has "^1.0.3"
+
+is-core-module@^2.7.0, is-core-module@^2.8.0:
   version "2.8.0"
   resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548"
   integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==
@@ -4275,14 +4334,14 @@ is-glob@^3.1.0:
   dependencies:
     is-extglob "^2.1.0"
 
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
+is-glob@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
   integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
   dependencies:
     is-extglob "^2.1.1"
 
-is-glob@^4.0.3:
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
   integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
@@ -4582,10 +4641,10 @@ levn@^0.4.1:
     prelude-ls "^1.2.1"
     type-check "~0.4.0"
 
-lilconfig@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd"
-  integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==
+lilconfig@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082"
+  integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==
 
 lines-and-columns@^1.1.6:
   version "1.2.4"
@@ -4875,9 +4934,9 @@ mimic-fn@^2.1.0:
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 
 mini-css-extract-plugin@^2.3.0:
-  version "2.4.5"
-  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.5.tgz#191d6c170226037212c483af1180b4010b7b9eef"
-  integrity sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA==
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.2.tgz#b3b9b98320c2c054d92c16f6a94ddfdbbba13755"
+  integrity sha512-Lwgq9qLNyBK6yNLgzssXnq4r2+mB9Mz3cJWlM8kseysHIvTicFhDNimFgY94jjqlwhNzLPsq8wv4X+vOHtMdYA==
   dependencies:
     schema-utils "^4.0.0"
 
@@ -4971,16 +5030,16 @@ nanocolors@^0.2.2, nanocolors@^0.2.8:
   resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.2.12.tgz#4d05932e70116078673ea4cc6699a1c56cc77777"
   integrity sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==
 
-nanoid@3.1.28, nanoid@^3.1.25:
+nanoid@^3.1.23, nanoid@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
+  integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
+
+nanoid@^3.1.25:
   version "3.1.28"
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.28.tgz#3c01bac14cb6c5680569014cc65a2f26424c6bd4"
   integrity sha512-gSu9VZ2HtmoKYe/lmyPFES5nknFrHa+/DT9muUFWFMi6Jh9E1I7bkvlQ8xxf1Kos9pi9o8lBnIOkatMhKX/YUw==
 
-nanoid@^3.1.23:
-  version "3.1.25"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
-  integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
-
 nanomatch@^1.2.9:
   version "1.2.13"
   resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -5397,7 +5456,7 @@ path-key@^3.0.0, path-key@^3.1.0:
   resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
   integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
 
-path-parse@^1.0.6:
+path-parse@^1.0.6, path-parse@^1.0.7:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
@@ -5413,9 +5472,9 @@ path-type@^4.0.0:
   integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
 
 picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
-  integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
 pify@^2.0.0:
   version "2.3.0"
@@ -5481,21 +5540,19 @@ posix-character-classes@^0.1.0:
   resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
   integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
 
-postcss-js@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33"
-  integrity sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==
+postcss-js@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
+  integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
   dependencies:
     camelcase-css "^2.0.1"
-    postcss "^8.1.6"
 
 postcss-load-config@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.0.tgz#d39c47091c4aec37f50272373a6a648ef5e97829"
-  integrity sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.1.tgz#2f53a17f2f543d9e63864460af42efdac0d41f87"
+  integrity sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==
   dependencies:
-    import-cwd "^3.0.0"
-    lilconfig "^2.0.3"
+    lilconfig "^2.0.4"
     yaml "^1.10.2"
 
 postcss-loader@^6.1.1:
@@ -5542,7 +5599,7 @@ postcss-nested@5.0.6:
   dependencies:
     postcss-selector-parser "^6.0.6"
 
-postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.6:
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
   version "6.0.6"
   resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
   integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
@@ -5550,10 +5607,10 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
 
-postcss-selector-parser@^6.0.7:
-  version "6.0.8"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz#f023ed7a9ea736cd7ef70342996e8e78645a7914"
-  integrity sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==
+postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.8:
+  version "6.0.9"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f"
+  integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==
   dependencies:
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
@@ -5577,7 +5634,7 @@ postcss@8.3.8:
     nanoid "^3.1.25"
     source-map-js "^0.6.2"
 
-postcss@^8.1.10, postcss@^8.1.6, postcss@^8.2.15:
+postcss@^8.1.10, postcss@^8.2.15:
   version "8.3.6"
   resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
   integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
@@ -5910,7 +5967,7 @@ resolve-url@^0.2.1:
   resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
-resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0:
+resolve@^1.12.0, resolve@^1.14.2, resolve@^1.9.0:
   version "1.20.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
   integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -5918,6 +5975,15 @@ resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.9.0:
     is-core-module "^2.2.0"
     path-parse "^1.0.6"
 
+resolve@^1.20.0, resolve@^1.21.0:
+  version "1.21.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.1.tgz#1a88c73f5ca8ab0aabc8b888c4170de26c92c4cc"
+  integrity sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ==
+  dependencies:
+    is-core-module "^2.8.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
 restore-cursor@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@@ -5953,7 +6019,7 @@ rimraf@^2.6.3:
   dependencies:
     glob "^7.1.3"
 
-rimraf@^3.0.0, rimraf@^3.0.2:
+rimraf@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
   integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -6539,6 +6605,11 @@ supports-color@^7.1.0:
   dependencies:
     has-flag "^4.0.0"
 
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
 table@^6.0.9:
   version "6.7.1"
   resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"
@@ -6552,9 +6623,9 @@ table@^6.0.9:
     strip-ansi "^6.0.0"
 
 tailwindcss@^3.0.7:
-  version "3.0.7"
-  resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.7.tgz#15936881f042a7eb8d6f2b6a454bac9f51181bbd"
-  integrity sha512-rZdKNHtC64jcQncLoWOuCzj4lQDTAgLtgK3WmQS88tTdpHh9OwLqULTQxI3tw9AMJsqSpCKlmcjW/8CSnni6zQ==
+  version "3.0.15"
+  resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.15.tgz#e4db219771eb7678a3bfd97b3f6c8fe20be0a410"
+  integrity sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==
   dependencies:
     arg "^5.0.1"
     chalk "^4.1.2"
@@ -6569,14 +6640,13 @@ tailwindcss@^3.0.7:
     is-glob "^4.0.3"
     normalize-path "^3.0.0"
     object-hash "^2.2.0"
-    postcss-js "^3.0.3"
+    postcss-js "^4.0.0"
     postcss-load-config "^3.1.0"
     postcss-nested "5.0.6"
-    postcss-selector-parser "^6.0.7"
+    postcss-selector-parser "^6.0.8"
     postcss-value-parser "^4.2.0"
     quick-lru "^5.1.1"
-    resolve "^1.20.0"
-    tmp "^0.2.1"
+    resolve "^1.21.0"
 
 tapable@^0.1.8:
   version "0.1.10"
@@ -6651,13 +6721,6 @@ tippy.js@^6.3.1:
   dependencies:
     "@popperjs/core" "^2.9.0"
 
-tmp@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
-  integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
-  dependencies:
-    rimraf "^3.0.0"
-
 to-fast-properties@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@@ -6888,13 +6951,13 @@ vue-eslint-parser@^7.10.0:
     semver "^6.3.0"
 
 vue-i18n@^9.2.0-beta.20:
-  version "9.2.0-beta.25"
-  resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.2.0-beta.25.tgz#cd26980ab4e7b2131198c23e243d74f3f19f93a1"
-  integrity sha512-l/A5W5KLuwnI5NHOV0WQrF79BwVku83ed7wHmq5NLm/Uofmsc8qmgJ95zw8EK3fmSBzb3F1NbjxxK2DZcg8c/g==
+  version "9.2.0-beta.28"
+  resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.2.0-beta.28.tgz#fcfa1d2deafb0914817fb338ed8e5deb54ba4e44"
+  integrity sha512-Jn7DHA3JgOYaB6ahqmuW0wQ2zZx0ivastVDUul8325geyT0Q4PblJvXvfWHi2L0eb+YjWMZvf30MQYJ1FWDlfQ==
   dependencies:
-    "@intlify/core-base" "9.2.0-beta.25"
-    "@intlify/shared" "9.2.0-beta.25"
-    "@intlify/vue-devtools" "9.2.0-beta.25"
+    "@intlify/core-base" "9.2.0-beta.28"
+    "@intlify/shared" "9.2.0-beta.28"
+    "@intlify/vue-devtools" "9.2.0-beta.28"
     "@vue/devtools-api" "^6.0.0-beta.13"
 
 vue-loader@16.8.1: