|
|
@ -1,28 +1,44 @@ |
|
|
|
<script setup lang="ts"> |
|
|
|
<script setup lang="ts"> |
|
|
|
import { ref } from 'vue' |
|
|
|
import { ref } from 'vue' |
|
|
|
import { useToast } from 'vue-toastification' |
|
|
|
import { useToast } from 'vue-toastification' |
|
|
|
|
|
|
|
import type { PluginType } from 'nocodb-sdk' |
|
|
|
import MdiDeleteOutlineIcon from '~icons/mdi/delete-outline' |
|
|
|
import MdiDeleteOutlineIcon from '~icons/mdi/delete-outline' |
|
|
|
import MdiPlusIcon from '~icons/mdi/plus' |
|
|
|
import MdiPlusIcon from '~icons/mdi/plus' |
|
|
|
|
|
|
|
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils' |
|
|
|
|
|
|
|
|
|
|
|
import { extractSdkResponseErrorMsg } from '~~/utils/errorUtils' |
|
|
|
|
|
|
|
interface Props { |
|
|
|
interface Props { |
|
|
|
id: string |
|
|
|
id: string |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type Plugin = PluginType & { |
|
|
|
|
|
|
|
formDetails: Record<string, any> |
|
|
|
|
|
|
|
parsedInput: Record<string, any> |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { id } = defineProps<Props>() |
|
|
|
const { id } = defineProps<Props>() |
|
|
|
|
|
|
|
|
|
|
|
const emits = defineEmits(['saved']) |
|
|
|
const emits = defineEmits(['saved']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum Action { |
|
|
|
|
|
|
|
Save = 'save', |
|
|
|
|
|
|
|
Test = 'test', |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const toast = useToast() |
|
|
|
const toast = useToast() |
|
|
|
|
|
|
|
|
|
|
|
const { $api } = useNuxtApp() |
|
|
|
const { $api } = useNuxtApp() |
|
|
|
|
|
|
|
|
|
|
|
const formRef = ref() |
|
|
|
const formRef = ref() |
|
|
|
let plugin = $ref<any>(null) |
|
|
|
|
|
|
|
let pluginFormData = $ref<any>({}) |
|
|
|
let plugin = $ref<Plugin | null>(null) |
|
|
|
|
|
|
|
let pluginFormData = $ref<Record<string, any>>({}) |
|
|
|
let isLoading = $ref(true) |
|
|
|
let isLoading = $ref(true) |
|
|
|
let loadingAction = $ref<null | string>(null) |
|
|
|
let loadingAction = $ref<null | Action>(null) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const addSetting = () => pluginFormData.push({}) |
|
|
|
|
|
|
|
|
|
|
|
const saveSettings = async () => { |
|
|
|
const saveSettings = async () => { |
|
|
|
loadingAction = 'save' |
|
|
|
loadingAction = Action.Save |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
await formRef.value?.validateFields() |
|
|
|
await formRef.value?.validateFields() |
|
|
@ -33,7 +49,7 @@ const saveSettings = async () => { |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
emits('saved') |
|
|
|
emits('saved') |
|
|
|
toast.success(plugin.formDetails.msgOnInstall || 'Plugin settings saved successfully') |
|
|
|
toast.success(plugin?.formDetails.msgOnInstall || 'Plugin settings saved successfully') |
|
|
|
} catch (_e: any) { |
|
|
|
} catch (_e: any) { |
|
|
|
const e = await extractSdkResponseErrorMsg(_e) |
|
|
|
const e = await extractSdkResponseErrorMsg(_e) |
|
|
|
toast.error(e.message) |
|
|
|
toast.error(e.message) |
|
|
@ -42,12 +58,9 @@ const saveSettings = async () => { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const addSetting = () => { |
|
|
|
|
|
|
|
pluginFormData.push({}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const testSettings = async () => { |
|
|
|
const testSettings = async () => { |
|
|
|
loadingAction = 'test' |
|
|
|
loadingAction = Action.Test |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
const res = await $api.plugin.test({ |
|
|
|
const res = await $api.plugin.test({ |
|
|
|
input: pluginFormData, |
|
|
|
input: pluginFormData, |
|
|
@ -55,6 +68,7 @@ const testSettings = async () => { |
|
|
|
category: plugin?.category, |
|
|
|
category: plugin?.category, |
|
|
|
title: plugin?.title, |
|
|
|
title: plugin?.title, |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
if (res) { |
|
|
|
if (res) { |
|
|
|
toast.success('Successfully tested plugin settings') |
|
|
|
toast.success('Successfully tested plugin settings') |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -68,15 +82,16 @@ const testSettings = async () => { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const doAction = async (action: { key: string }) => { |
|
|
|
const doAction = async (action: Action) => { |
|
|
|
switch (action.key) { |
|
|
|
switch (action) { |
|
|
|
case 'save': |
|
|
|
case Action.Save: |
|
|
|
await saveSettings() |
|
|
|
await saveSettings() |
|
|
|
break |
|
|
|
break |
|
|
|
case 'test': |
|
|
|
case Action.Test: |
|
|
|
await testSettings() |
|
|
|
await testSettings() |
|
|
|
break |
|
|
|
break |
|
|
|
default: |
|
|
|
default: |
|
|
|
|
|
|
|
// noop |
|
|
|
break |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -84,6 +99,7 @@ const doAction = async (action: { key: string }) => { |
|
|
|
const readPluginDetails = async () => { |
|
|
|
const readPluginDetails = async () => { |
|
|
|
try { |
|
|
|
try { |
|
|
|
isLoading = true |
|
|
|
isLoading = true |
|
|
|
|
|
|
|
|
|
|
|
const res = await $api.plugin.read(id) |
|
|
|
const res = await $api.plugin.read(id) |
|
|
|
const formDetails = JSON.parse(res.input_schema ?? '{}') |
|
|
|
const formDetails = JSON.parse(res.input_schema ?? '{}') |
|
|
|
const emptyParsedInput = formDetails.array ? [{}] : {} |
|
|
|
const emptyParsedInput = formDetails.array ? [{}] : {} |
|
|
@ -98,12 +114,10 @@ const readPluginDetails = async () => { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const deleteFormRow = (index: number) => { |
|
|
|
const deleteFormRow = (index: number) => pluginFormData.splice(index, 1) |
|
|
|
pluginFormData.splice(index, 1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
onMounted(async () => { |
|
|
|
if (plugin === null) { |
|
|
|
if (!plugin) { |
|
|
|
await readPluginDetails() |
|
|
|
await readPluginDetails() |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
@ -113,14 +127,14 @@ onMounted(async () => { |
|
|
|
<div v-if="isLoading" class="flex flex-row w-full justify-center items-center h-52"> |
|
|
|
<div v-if="isLoading" class="flex flex-row w-full justify-center items-center h-52"> |
|
|
|
<a-spin size="large" /> |
|
|
|
<a-spin size="large" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<template v-else> |
|
|
|
<template v-else> |
|
|
|
<div class="flex flex-col"> |
|
|
|
<div class="flex flex-col"> |
|
|
|
<div class="flex flex-row justify-center pb-4 mb-2 border-b-1 w-full space-x-1"> |
|
|
|
<div class="flex flex-row justify-center pb-4 mb-2 border-b-1 w-full gap-x-1"> |
|
|
|
<div |
|
|
|
<div |
|
|
|
v-if="plugin.logo" |
|
|
|
v-if="plugin.logo" |
|
|
|
:style="{ background: plugin.title === 'SES' ? '#242f3e' : '' }" |
|
|
|
class="mr-1 flex items-center justify-center" |
|
|
|
class="mr-1 d-flex align-center justify-center" |
|
|
|
:class="[plugin.title === 'SES' ? 'p-2 bg-[#242f3e]' : '']" |
|
|
|
:class="{ 'pa-2': plugin.title === 'SES' }" |
|
|
|
|
|
|
|
> |
|
|
|
> |
|
|
|
<img :src="`/${plugin.logo}`" class="h-6" /> |
|
|
|
<img :src="`/${plugin.logo}`" class="h-6" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -173,7 +187,7 @@ onMounted(async () => { |
|
|
|
|
|
|
|
|
|
|
|
<tr> |
|
|
|
<tr> |
|
|
|
<td :colspan="plugin.formDetails.items.length" class="text-center"> |
|
|
|
<td :colspan="plugin.formDetails.items.length" class="text-center"> |
|
|
|
<a-button type="default" class="!bg-gray-100 rounded-md border-0" @click="addSetting"> |
|
|
|
<a-button type="default" class="!bg-gray-100 rounded-md border-none" @click="addSetting"> |
|
|
|
<template #icon> |
|
|
|
<template #icon> |
|
|
|
<MdiPlusIcon class="flex mx-auto" /> |
|
|
|
<MdiPlusIcon class="flex mx-auto" /> |
|
|
|
</template> |
|
|
|
</template> |
|
|
@ -214,9 +228,9 @@ onMounted(async () => { |
|
|
|
v-for="(action, i) in plugin.formDetails.actions" |
|
|
|
v-for="(action, i) in plugin.formDetails.actions" |
|
|
|
:key="i" |
|
|
|
:key="i" |
|
|
|
:loading="loadingAction === action.key" |
|
|
|
:loading="loadingAction === action.key" |
|
|
|
:type="action.key === 'save' ? 'primary' : 'default'" |
|
|
|
:type="action.key === Action.Save ? 'primary' : 'default'" |
|
|
|
:disabled="!!loadingAction" |
|
|
|
:disabled="!!loadingAction" |
|
|
|
@click="doAction(action)" |
|
|
|
@click="doAction(action.key)" |
|
|
|
> |
|
|
|
> |
|
|
|
{{ action.label }} |
|
|
|
{{ action.label }} |
|
|
|
</a-button> |
|
|
|
</a-button> |
|
|
@ -228,11 +242,10 @@ onMounted(async () => { |
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss"> |
|
|
|
<style scoped lang="scss"> |
|
|
|
.form-table { |
|
|
|
.form-table { |
|
|
|
border: none; |
|
|
|
@apply border-none min-w-[400px]; |
|
|
|
min-width: 400px; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tbody tr:nth-of-type(odd) { |
|
|
|
tbody tr:nth-of-type(odd) { |
|
|
|
background-color: transparent; |
|
|
|
@apply bg-transparent; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
</style> |
|
|
|