mirror of https://github.com/nocodb/nocodb
Pranav C
5 months ago
9 changed files with 364 additions and 247 deletions
@ -0,0 +1,122 @@
|
||||
<script setup lang="ts"> |
||||
import { Action } from '../../../composables/useAccountSetupStore' |
||||
|
||||
const props = defineProps<{ |
||||
id: string |
||||
modelValue?: boolean |
||||
}>() |
||||
const emit = defineEmits(['saved', 'close', 'update:modelValue']) |
||||
|
||||
const vOpen = useVModel(props, 'modelValue', emit) |
||||
|
||||
const { |
||||
readPluginDetails, |
||||
activePluginFormData: pluginFormData, |
||||
activePlugin: plugin, |
||||
isLoading, |
||||
loadingAction, |
||||
testSettings, |
||||
saveSettings, |
||||
} = useAccountSetupStoreOrThrow() |
||||
|
||||
if (!plugin.value) { |
||||
await readPluginDetails(props.id) |
||||
} |
||||
|
||||
const pluginTypeMap = { |
||||
Input: FormBuilderInputType.Input, |
||||
Select: FormBuilderInputType.Select, |
||||
Checkbox: FormBuilderInputType.Switch, |
||||
LongText: FormBuilderInputType.Input, |
||||
Password: FormBuilderInputType.Input, |
||||
} |
||||
|
||||
const { formState, validate } = useProvideFormBuilderHelper({ |
||||
formSchema: [ |
||||
...plugin.value.formDetails.items.map((item) => ({ |
||||
type: pluginTypeMap[item.type] || FormBuilderInputType.Input, |
||||
label: item.label, |
||||
placeholder: item.placeholder, |
||||
model: item.key, |
||||
required: item.required, |
||||
})), |
||||
], |
||||
onSubmit: async () => { |
||||
console.log('submit', formState) |
||||
}, |
||||
initialState: pluginFormData, |
||||
}) |
||||
|
||||
const doAction = async (action: Action) => { |
||||
try { |
||||
switch (action) { |
||||
case Action.Save: |
||||
await validate() |
||||
await saveSettings() |
||||
break |
||||
case Action.Test: |
||||
await validate() |
||||
await testSettings() |
||||
break |
||||
default: |
||||
// noop |
||||
break |
||||
} |
||||
} catch (e: any) { |
||||
console.log(e) |
||||
} finally { |
||||
loadingAction.value = null |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<template> |
||||
<NcModal |
||||
:visible="vOpen" |
||||
:keyboard="isModalClosable" |
||||
centered |
||||
width="70rem" |
||||
wrap-class-name="nc-modal-create-source" |
||||
@keydown.esc="vOpen = false" |
||||
> |
||||
<div class="flex-1 flex flex-col max-h-full min-h-400px"> |
||||
<div class="px-4 pb-4 w-full flex items-center gap-3 border-b-1 border-gray-200"> |
||||
<GeneralIcon icon="arrowLeft" class="flex-none text-[20px]" @click="vOpen = false" /> |
||||
<div |
||||
v-if="plugin.logo" |
||||
class="mr-1 flex items-center justify-center" |
||||
:class="[plugin.title === 'SES' ? 'p-2 bg-[#242f3e]' : '']" |
||||
> |
||||
<img :alt="plugin.title || 'plugin'" :src="plugin.logo" class="h-3" /> |
||||
</div> |
||||
|
||||
<span class="font-semibold text-lg">{{ plugin.formDetails.title }}</span> |
||||
<div class="flex-grow" /> |
||||
|
||||
<div class="flex gap-2"> |
||||
<NcButton |
||||
v-for="(action, i) in plugin.formDetails.actions" |
||||
:key="i" |
||||
class="!px-5" |
||||
:loading="loadingAction === action.key" |
||||
:type="action.key === Action.Save ? 'primary' : 'default'" |
||||
size="small" |
||||
:disabled="!!loadingAction" |
||||
@click="doAction(action.key)" |
||||
> |
||||
{{ action.label }} |
||||
</NcButton> |
||||
</div> |
||||
</div> |
||||
<div class="h-[calc(100%_-_58px)] flex py-4 flex-col"> |
||||
<div v-if="isLoading || !plugin" class="flex flex-row w-full justify-center items-center h-52"> |
||||
<a-spin size="large" /> |
||||
</div> |
||||
|
||||
<div v-else class="flex"> |
||||
<NcFormBuilder class="w-500px mx-auto" /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</NcModal> |
||||
</template> |
@ -1,115 +0,0 @@
|
||||
<script setup lang="ts"> |
||||
|
||||
const { emailApps } = useAccountSetupStoreOrThrow() |
||||
</script> |
||||
|
||||
<template> |
||||
<div class="w-full"> |
||||
<div class="p-4 flex flex-wrap w-full gap-5 mx-auto my-2"> |
||||
<div v-for="(app) in emailApps" :key="app.title" class="w-296px max-w-296px flex gap-6 border-1 border-gray-100 py-3 px-6 rounded items-center"> |
||||
<img |
||||
v-if="app.title !== 'SMTP'" |
||||
class="max-w-32px max-h-32px" |
||||
alt="logo" |
||||
:style="{ |
||||
backgroundColor: app.title === 'SES' ? '#242f3e' : '', |
||||
}" |
||||
:src="app.logo" |
||||
/> |
||||
<GeneralIcon v-else icon="mail" /> |
||||
<span class="font-weight-bold">{{ app.title }}</span> |
||||
</div> |
||||
<!-- |
||||
<a-card |
||||
v-for="(app, i) in emailApps" |
||||
:key="i" |
||||
class="sm:w-100 md:w-130" |
||||
:class="`relative flex overflow-x-hidden app-item-card !shadow-sm rounded-md w-full nc-app-store-card-${app.title}`" |
||||
> |
||||
<div class="install-btn flex flex-row justify-end space-x-1"> |
||||
<a-button v-if="app.parsedInput" size="small" type="primary" @click="showInstallPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-edit"> |
||||
<IcRoundEdit class="pr-0.5" :height="12" /> |
||||
{{ $t('general.edit') }} |
||||
</div> |
||||
</a-button> |
||||
|
||||
<a-button v-if="app.parsedInput" size="small" outlined @click="showResetPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-reset"> |
||||
<component :is="iconMap.closeCircle" /> |
||||
<div class="flex ml-0.5">{{ $t('general.reset') }}</div> |
||||
</div> |
||||
</a-button> |
||||
|
||||
<a-button v-else size="small" type="primary" @click="showInstallPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-install"> |
||||
<component :is="iconMap.plus" /> |
||||
{{ $t('general.install') }} |
||||
</div> |
||||
</a-button> |
||||
</div> |
||||
|
||||
<div class="flex flex-row space-x-2 items-center justify-start w-full"> |
||||
<div class="flex w-[68px]"> |
||||
<img |
||||
v-if="app.title !== 'SMTP'" |
||||
class="avatar" |
||||
alt="logo" |
||||
:style="{ |
||||
backgroundColor: app.title === 'SES' ? '#242f3e' : '', |
||||
}" |
||||
:src="app.logo" |
||||
/> |
||||
|
||||
<div v-else /> |
||||
</div> |
||||
|
||||
<div class="flex flex-col flex-1 w-3/5 pl-3"> |
||||
<a-typography-title :level="5">{{ app.title }}</a-typography-title> |
||||
|
||||
{{ app.description }} |
||||
</div> |
||||
</div> |
||||
</a-card>--> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<style scoped lang="scss"> |
||||
.app-item-card { |
||||
position: relative; |
||||
transition: 0.4s background-color; |
||||
|
||||
.install-btn { |
||||
position: absolute; |
||||
opacity: 1; |
||||
right: -100%; |
||||
top: 10px; |
||||
transition: 0.4s opacity, 0.4s right; |
||||
} |
||||
|
||||
&:hover .install-btn { |
||||
right: 10px; |
||||
opacity: 1; |
||||
} |
||||
} |
||||
|
||||
.app-item-card { |
||||
transition: 0.4s background-color, 0.4s transform; |
||||
|
||||
&:hover { |
||||
background: rgba(123, 126, 136, 0.1) !important; |
||||
} |
||||
} |
||||
|
||||
.caption { |
||||
font-size: 0.7rem; |
||||
} |
||||
|
||||
.avatar { |
||||
width: 5rem; |
||||
height: 5rem; |
||||
padding: 0.25rem; |
||||
object-fit: contain; |
||||
} |
||||
</style> |
@ -0,0 +1,75 @@
|
||||
<script setup lang="ts"> |
||||
const props = defineProps<{ |
||||
category: string |
||||
modelValue?: boolean |
||||
}>() |
||||
|
||||
const emit = defineEmits(['update:modelValue']) |
||||
|
||||
const vOpen = useVModel(props, 'modelValue', emit) |
||||
|
||||
const selectedApp = ref<string | null>(null) |
||||
|
||||
const { categorizeApps, confirmModalDlg } = useAccountSetupStoreOrThrow() |
||||
|
||||
const selectApp = (app: any) => { |
||||
selectedApp.value = app |
||||
confirmModalDlg.value = true |
||||
} |
||||
</script> |
||||
|
||||
<template> |
||||
<NcModal |
||||
:visible="vOpen" |
||||
:keyboard="isModalClosable" |
||||
centered |
||||
width="70rem" |
||||
wrap-class-name="nc-modal-create-source" |
||||
@keydown.esc="vOpen = false" |
||||
> |
||||
<div class="flex-1 flex flex-col max-h-full min-h-400px"> |
||||
<div class="px-4 py-3 w-full flex items-center gap-3 border-b-1 border-gray-200"> |
||||
<div class="flex-1 text-base font-weight-700">Setup {{ category }}</div> |
||||
</div> |
||||
<div class="h-[calc(100%_-_58px)] flex"> |
||||
<div class="w-full"> |
||||
<div class="container"> |
||||
<div v-for="app in categorizeApps[category] || []" :key="app.title" class="item" @click="selectApp(app)"> |
||||
<img |
||||
v-if="app.title !== 'SMTP'" |
||||
class="icon" |
||||
:alt="app.title" |
||||
:style="{ |
||||
backgroundColor: app.title === 'SES' ? '#242f3e' : '', |
||||
}" |
||||
:src="app.logo" |
||||
/> |
||||
<GeneralIcon v-else icon="mail" /> |
||||
<span class="title">{{ app.title }}</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<AccountSetupConfigModal v-if="selectedApp" :id="selectedApp.id" v-model="confirmModalDlg" /> |
||||
</NcModal> |
||||
</template> |
||||
|
||||
<style scoped lang="scss"> |
||||
.container { |
||||
@apply p-4 flex flex-wrap w-full gap-5 mx-auto my-2 justify-center; |
||||
|
||||
.item { |
||||
@apply w-296px max-w-296px flex gap-6 border-1 border-gray-100 py-3 px-6 rounded items-center cursor-pointer hover:(shadow bg-gray-50); |
||||
|
||||
.icon { |
||||
@apply max-w-32px max-h-32px; |
||||
} |
||||
|
||||
.title { |
||||
@apply font-weight-bold; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -1,114 +0,0 @@
|
||||
<script setup lang="ts"> |
||||
const { storageApps } = useAccountSetupStoreOrThrow() |
||||
</script> |
||||
|
||||
<template> |
||||
<div class="w-full"> |
||||
<div class="p-4 flex flex-wrap w-full gap-5 mx-auto my-2"> |
||||
<div v-for="(app) in storageApps" :key="app.title" class="w-296px max-w-296px flex gap-6 border-1 border-gray-100 py-3 px-6 rounded items-center"> |
||||
<img |
||||
v-if="app.title !== 'SMTP'" |
||||
class="max-w-32px max-h-32px" |
||||
alt="logo" |
||||
:style="{ |
||||
backgroundColor: app.title === 'SES' ? '#242f3e' : '', |
||||
}" |
||||
:src="app.logo" |
||||
/> |
||||
<GeneralIcon v-else icon="mail" /> |
||||
<span class="font-weight-bold">{{ app.title }}</span> |
||||
</div> |
||||
<!-- |
||||
<a-card |
||||
v-for="(app, i) in storageApps" |
||||
:key="i" |
||||
class="sm:w-100 md:w-130" |
||||
:class="`relative flex overflow-x-hidden app-item-card !shadow-sm rounded-md w-full nc-app-store-card-${app.title}`" |
||||
> |
||||
<div class="install-btn flex flex-row justify-end space-x-1"> |
||||
<a-button v-if="app.parsedInput" size="small" type="primary" @click="showInstallPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-edit"> |
||||
<IcRoundEdit class="pr-0.5" :height="12" /> |
||||
{{ $t('general.edit') }} |
||||
</div> |
||||
</a-button> |
||||
|
||||
<a-button v-if="app.parsedInput" size="small" outlined @click="showResetPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-reset"> |
||||
<component :is="iconMap.closeCircle" /> |
||||
<div class="flex ml-0.5">{{ $t('general.reset') }}</div> |
||||
</div> |
||||
</a-button> |
||||
|
||||
<a-button v-else size="small" type="primary" @click="showInstallPluginModal(app)"> |
||||
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-install"> |
||||
<component :is="iconMap.plus" /> |
||||
{{ $t('general.install') }} |
||||
</div> |
||||
</a-button> |
||||
</div> |
||||
|
||||
<div class="flex flex-row space-x-2 items-center justify-start w-full"> |
||||
<div class="flex w-[68px]"> |
||||
<img |
||||
v-if="app.title !== 'SMTP'" |
||||
class="avatar" |
||||
alt="logo" |
||||
:style="{ |
||||
backgroundColor: app.title === 'SES' ? '#242f3e' : '', |
||||
}" |
||||
:src="app.logo" |
||||
/> |
||||
|
||||
<div v-else /> |
||||
</div> |
||||
|
||||
<div class="flex flex-col flex-1 w-3/5 pl-3"> |
||||
<a-typography-title :level="5">{{ app.title }}</a-typography-title> |
||||
|
||||
{{ app.description }} |
||||
</div> |
||||
</div> |
||||
</a-card>--> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<style scoped lang="scss"> |
||||
.app-item-card { |
||||
position: relative; |
||||
transition: 0.4s background-color; |
||||
|
||||
.install-btn { |
||||
position: absolute; |
||||
opacity: 1; |
||||
right: -100%; |
||||
top: 10px; |
||||
transition: 0.4s opacity, 0.4s right; |
||||
} |
||||
|
||||
&:hover .install-btn { |
||||
right: 10px; |
||||
opacity: 1; |
||||
} |
||||
} |
||||
|
||||
.app-item-card { |
||||
transition: 0.4s background-color, 0.4s transform; |
||||
|
||||
&:hover { |
||||
background: rgba(123, 126, 136, 0.1) !important; |
||||
} |
||||
} |
||||
|
||||
.caption { |
||||
font-size: 0.7rem; |
||||
} |
||||
|
||||
.avatar { |
||||
width: 5rem; |
||||
height: 5rem; |
||||
padding: 0.25rem; |
||||
object-fit: contain; |
||||
} |
||||
</style> |
Loading…
Reference in new issue