Bläddra i källkod

feat: add notification block

Ahmad Kholid 3 år sedan
förälder
incheckning
298354b598

+ 1 - 1
src/background/index.js

@@ -144,7 +144,7 @@ async function openDashboard(url) {
     if (tab) {
       await browser.tabs.update(tab.id, tabOptions);
 
-      if (tab.url.includes('workflows/')) {
+      if (tabOptions.url.includes('workflows/')) {
         await browser.tabs.reload(tab.id);
       }
     } else {

+ 47 - 0
src/background/workflowEngine/blocksHandler/handlerNotification.js

@@ -0,0 +1,47 @@
+import { nanoid } from 'nanoid';
+import browser from 'webextension-polyfill';
+import { getBlockConnection } from '../helper';
+
+export default async function ({ data, outputs }) {
+  const nextBlockId = getBlockConnection({ outputs });
+
+  try {
+    const hasPermission = await browser.permissions.contains({
+      permissions: ['notifications'],
+    });
+
+    if (!hasPermission) {
+      const error = new Error('no-permission');
+      error.data = { permission: 'notifications' };
+
+      throw error;
+    }
+
+    const options = {
+      title: data.title,
+      message: data.message,
+      iconUrl: browser.runtime.getURL('icon-128.png'),
+    };
+
+    ['iconUrl', 'imageUrl'].forEach((key) => {
+      const url = data[key];
+      if (!url || !url.startsWith('http')) return;
+
+      options[key] = url;
+    });
+
+    await browser.notifications.create(nanoid(), {
+      ...options,
+      type: options.imageUrl ? 'image' : 'basic',
+    });
+
+    return {
+      data: '',
+      nextBlockId,
+    };
+  } catch (error) {
+    error.nextBlockId = nextBlockId;
+
+    throw error;
+  }
+}

+ 62 - 0
src/components/newtab/workflow/edit/EditNotification.vue

@@ -0,0 +1,62 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full mb-2"
+      @change="updateData({ description: $event })"
+    />
+    <edit-autocomplete class="mb-2">
+      <ui-input
+        :model-value="data.title"
+        :label="t('workflow.blocks.notification.title')"
+        placeholder="Hello world!"
+        class="w-full"
+        @change="updateData({ title: $event })"
+      />
+    </edit-autocomplete>
+    <label class="input-label" for="notification-message">
+      {{ t('workflow.blocks.notification.message') }}
+    </label>
+    <edit-autocomplete>
+      <ui-textarea
+        id="notification-message"
+        :model-value="data.message"
+        placeholder="Notification message"
+        class="w-full"
+        @change="updateData({ message: $event })"
+      />
+    </edit-autocomplete>
+    <edit-autocomplete
+      v-for="type in ['iconUrl', 'imageUrl']"
+      :key="type"
+      class="mt-2"
+    >
+      <ui-input
+        :model-value="data[type]"
+        :label="t(`workflow.blocks.notification.${type}`)"
+        class="w-full"
+        placeholder="https://example.com/image.png"
+        @change="updateData({ [type]: $event })"
+      />
+    </edit-autocomplete>
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+import EditAutocomplete from './EditAutocomplete.vue';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+</script>

+ 6 - 0
src/components/newtab/workflow/edit/EditProxy.vue

@@ -1,5 +1,11 @@
 <template>
   <div>
+    <ui-textarea
+      :model-value="data.description"
+      :placeholder="t('common.description')"
+      class="w-full mb-2"
+      @change="updateData({ description: $event })"
+    />
     <ui-input
       :model-value="data.host"
       placeholder="socks5://1.2.3.4"

+ 2 - 0
src/lib/vRemixicon.js

@@ -104,6 +104,7 @@ import {
   riFileDownloadLine,
   riShieldKeyholeLine,
   riArrowDropDownLine,
+  riNotification3Line,
   riArrowLeftRightLine,
   riArrowGoForwardLine,
   riCheckboxCircleLine,
@@ -215,6 +216,7 @@ export const icons = {
   riFileDownloadLine,
   riShieldKeyholeLine,
   riArrowDropDownLine,
+  riNotification3Line,
   riArrowLeftRightLine,
   riArrowGoForwardLine,
   riCheckboxCircleLine,

+ 8 - 0
src/locales/en/blocks.json

@@ -83,6 +83,14 @@
         "specificFlow": "Only continue a specific flow",
         "selectFlow": "Select flow"
       },
+      "notification": {
+        "name": "notification",
+        "description": "Display a notification",
+        "title": "Title",
+        "message": "Message",
+        "imageUrl": "Image URL (optional)",
+        "iconUrl": "Icon URL (optional)"
+      },
       "delete-data": {
         "name": "Delete data",
         "description": "Delete table or variable data",

+ 1 - 0
src/locales/en/newtab.json

@@ -312,6 +312,7 @@
       "no-clipboard-acces": "Don't have permission to access clipboard",
       "browser-not-supported": "This feature not supported in {browser} browser",
       "element-not-found": "Can't find an element with \"{selector}\" selector.",
+      "no-permission": "Don't have \"{permission}\" permission to do this action",
       "not-iframe": "Element with \"{selector}\" selector is not an Iframe element",
       "iframe-not-found": "Can't find an Iframe element with \"{selector}\" selector.",
       "workflow-infinite-loop": "Can't execute the workflow to prevent an infinite loop",

+ 1 - 1
src/models/workflow.js

@@ -45,7 +45,7 @@ class Workflow extends Model {
         defaultColumnName: 'column',
       }),
       logs: this.hasMany(Log, 'workflowId'),
-      globalData: this.string('[{ "key": "value" }]'),
+      globalData: this.string('{\n\t"key": "value"\n}'),
     };
   }
 

+ 22 - 0
src/utils/shared.js

@@ -163,6 +163,7 @@ export const tasks = {
     allowedInputs: true,
     refDataKeys: ['host', 'port', 'scheme'],
     data: {
+      description: '',
       disableBlock: false,
       scheme: 'https',
       host: '',
@@ -981,6 +982,27 @@ export const tasks = {
       flowBlockId: '',
     },
   },
+  notification: {
+    name: 'Notification',
+    description: 'Display a notification',
+    icon: 'riNotification3Line',
+    editComponent: 'EditNotification',
+    component: 'BlockBasic',
+    category: 'general',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    refDataKeys: ['message', 'title', 'iconUrl', 'imageUrl'],
+    data: {
+      disableBlock: false,
+      description: '',
+      message: '',
+      iconUrl: '',
+      imageUrl: '',
+      title: 'Hello world!',
+    },
+  },
 };
 
 export const categories = {