Browse Source

Merge pull request #9169 from nocodb/nc-fix/integration-followup

Nc fix/integration followup
pull/9170/head
Ramesh Mane 4 months ago committed by GitHub
parent
commit
caa25b22f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      packages/nc-gui/assets/nc-icons/whatsapp-solid.svg
  2. 5
      packages/nc-gui/components/dashboard/settings/DataSources.vue
  3. 10
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  4. 6
      packages/nc-gui/components/workspace/integrations/ConnectionsTab.vue
  5. 225
      packages/nc-gui/components/workspace/integrations/IntegrationsTab.vue
  6. 2
      packages/nc-gui/utils/iconUtils.ts
  7. 4
      packages/nc-gui/utils/syncDataUtils.ts

11
packages/nc-gui/assets/nc-icons/whatsapp-solid.svg

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
<g clip-path="url(#clip0_917_11898)">
<path d="M14.4393 31.2257C12.6537 31.1105 10.7977 30.5857 9.14652 29.7281C7.58492 28.9089 7.57212 28.9089 7.30972 28.9793C7.18172 29.0113 6.74012 29.1329 6.33692 29.2481C5.22972 29.5553 4.18012 29.8241 3.71292 29.9201C3.48252 29.9713 3.13052 30.0673 2.93212 30.1377C2.72732 30.2145 2.49052 30.2721 2.40732 30.2721C2.31772 30.2721 2.17692 30.2977 2.08732 30.3361C1.94652 30.3873 1.90812 30.3745 1.81852 30.2401C1.72892 30.0993 1.72892 30.0481 1.85052 29.5873C1.92092 29.3121 1.99772 29.0177 2.02332 28.9281C2.08732 28.6593 2.34332 27.7441 2.72092 26.4129C3.21372 24.6913 3.21372 24.6721 2.65692 23.7441C1.73532 22.1889 1.05052 20.4801 0.730523 18.9441C0.410523 17.3953 0.384923 14.8929 0.672923 13.3441C0.826523 12.4993 1.37052 10.5729 1.64572 9.89452C2.34972 8.16012 3.41852 6.57292 4.86492 5.11372C6.12572 3.84652 7.54652 2.82252 9.11452 2.04812C10.6057 1.31212 11.6873 0.960121 13.4729 0.633721C14.4265 0.460921 16.4809 0.396921 17.4665 0.505721C18.6249 0.640121 20.6281 1.10092 21.2745 1.37612C21.3833 1.42092 21.7033 1.55532 21.9849 1.67692C23.1049 2.13772 24.4105 2.93772 25.5049 3.82092C28.9609 6.60492 31.0153 10.6241 31.2905 15.1361C31.4953 18.4705 30.6953 21.5553 28.9289 24.1985C27.2457 26.7137 25.2297 28.5249 22.7529 29.7281C20.0713 31.0337 17.8121 31.4369 14.4393 31.2257Z" fill="#02E677"/>
<path d="M20.3198 24.5373C20.2494 24.5245 20.0254 24.4669 19.8206 24.4093C19.6222 24.3581 19.2958 24.2877 19.1038 24.2557C18.9118 24.2237 18.6622 24.1533 18.547 24.1021C18.4318 24.0509 18.195 23.9741 18.0158 23.9293C17.843 23.8909 17.6382 23.8205 17.5678 23.7757C17.4974 23.7373 17.3246 23.6605 17.1838 23.6157C17.043 23.5709 16.7998 23.4685 16.6398 23.3853C16.4798 23.3021 16.307 23.2317 16.243 23.2317C16.1854 23.2317 16.0894 23.1869 16.0318 23.1293C15.9742 23.0717 15.8334 22.9885 15.7246 22.9501C15.5518 22.8861 15.1294 22.6685 14.7838 22.4573C14.7326 22.4253 14.5854 22.3421 14.4574 22.2781C14.3358 22.2077 14.195 22.1053 14.1502 22.0541C14.099 21.9965 14.0222 21.9517 13.9774 21.9517C13.9262 21.9517 13.8366 21.9005 13.7726 21.8429C13.7086 21.7789 13.4846 21.6125 13.2734 21.4717C12.6654 21.0685 12.2046 20.6589 10.9438 19.3917C9.54215 17.9965 8.87655 17.2221 8.31335 16.3517C8.22375 16.2109 8.09575 16.0125 8.02535 15.9101C7.67975 15.3981 7.03975 14.1885 7.03975 14.0541C7.03975 14.0029 6.99495 13.9325 6.94375 13.8877C6.89255 13.8429 6.82855 13.7085 6.80935 13.5741C6.78375 13.4461 6.69415 13.1581 6.60455 12.9277C6.46375 12.5501 6.44455 12.4221 6.44455 11.5197C6.43815 10.5597 6.45095 10.5085 6.64935 9.91975C6.76455 9.58695 6.89895 9.26695 6.95015 9.20935C7.00135 9.15815 7.03975 9.08775 7.03975 9.05575C7.03975 8.95335 7.62215 8.12775 7.89735 7.83975C8.13415 7.59015 8.30695 7.46855 8.83175 7.18695C9.06215 7.06535 10.3806 7.07175 10.6174 7.19975C10.8606 7.32135 11.091 7.60295 11.2574 7.98055C11.3406 8.14695 11.4686 8.43495 11.5518 8.60775C11.635 8.78695 11.7758 9.08775 11.8654 9.27975C11.955 9.47175 12.0318 9.67015 12.0318 9.71495C12.0318 9.75975 12.0894 9.90695 12.1598 10.0349C12.4862 10.6493 12.6334 11.1037 12.659 11.6349C12.6782 12.1661 12.6782 12.1725 12.435 12.5309C12.3006 12.7293 12.1406 12.9405 12.083 13.0045C12.019 13.0685 11.9678 13.1389 11.9678 13.1709C11.9678 13.1965 11.8398 13.3565 11.6798 13.5229C11.0718 14.1565 11.1038 14.5789 11.8398 15.6477C12.5246 16.6333 13.427 17.6061 14.3294 18.3357C14.5854 18.5469 14.867 18.7837 14.9566 18.8669C15.0398 18.9437 15.1358 19.0077 15.1614 19.0077C15.187 19.0077 15.2638 19.0653 15.3214 19.1293C15.3854 19.1997 15.5262 19.2893 15.635 19.3341C15.7502 19.3789 15.8846 19.4493 15.9358 19.4941C16.0702 19.6029 16.8318 20.0061 17.0238 20.0637C17.1134 20.0893 17.2222 20.1405 17.267 20.1789C17.3182 20.2173 17.5422 20.3133 17.7726 20.3965C18.163 20.5309 18.195 20.5309 18.355 20.4349C18.547 20.3197 19.3662 19.4813 19.7886 18.9693C20.1982 18.4829 20.4158 18.3485 20.8254 18.3549C21.0814 18.3549 21.2606 18.4061 21.5358 18.5533C21.7406 18.6621 21.939 18.7517 21.9838 18.7517C22.0286 18.7517 22.099 18.7965 22.1438 18.8477C22.1886 18.9053 22.3486 18.9757 22.5022 19.0141C22.6558 19.0525 22.8158 19.1229 22.8542 19.1741C22.8926 19.2253 23.0462 19.2957 23.1934 19.3341C23.3342 19.3725 23.5262 19.4557 23.6158 19.5197C23.7054 19.5837 23.8654 19.6541 23.9806 19.6733C24.0958 19.6989 24.2494 19.7693 24.3326 19.8333C24.4158 19.8973 24.5694 19.9677 24.6718 19.9933C24.7806 20.0189 24.9406 20.1149 25.043 20.2109C25.1966 20.3581 25.2158 20.4221 25.2158 20.7997C25.2158 21.0877 25.1646 21.3693 25.0558 21.6829C24.9662 21.9325 24.8958 22.1821 24.8958 22.2333C24.8958 22.3869 24.3646 22.9885 23.8654 23.3981C23.0014 24.1085 22.035 24.4989 21.0302 24.5437C20.7102 24.5565 20.3902 24.5565 20.3198 24.5373Z" fill="#F6FEFA"/>
</g>
<defs>
<clipPath id="clip0_917_11898">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

5
packages/nc-gui/components/dashboard/settings/DataSources.vue

@ -337,7 +337,7 @@ const handleClickRow = (source: SourceType, tab?: string) => {
>
<div v-if="activeSource" class="h-full">
<div class="px-4 pt-4 pb-2 flex items-center justify-between gap-3">
<a-breadcrumb separator=">" class="flex-1 cursor-pointer font-weight-bold">
<a-breadcrumb separator=">" class="flex-1 cursor-pointer font-weight-bold !ml-1">
<a-breadcrumb-item @click="activeSource = null">
<a class="!no-underline text-base">Data Sources</a>
</a-breadcrumb-item>
@ -692,5 +692,8 @@ const handleClickRow = (source: SourceType, tab?: string) => {
height: min(calc(100vh - 100px), 1024px);
max-height: min(calc(100vh - 100px), 1024px) !important;
}
.ant-tabs-nav{
@apply pl-3;
}
}
</style>

10
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -416,9 +416,7 @@ function handleAutoScroll(scroll: boolean, className: string) {
}
}
const filterIntegrationCategory = (c: IntegrationCategoryItemType) =>
[IntegrationCategoryType.DATABASE, IntegrationCategoryType.OTHERS].includes(c.value)
const filterIntegration = (c: IntegrationItemType) => c.categories.includes(IntegrationCategoryType.DATABASE)
const filterIntegrationCategory = (c: IntegrationCategoryItemType) => [IntegrationCategoryType.DATABASE].includes(c.value)
</script>
<template>
@ -723,11 +721,7 @@ const filterIntegration = (c: IntegrationItemType) => c.categories.includes(Inte
</div>
</a-form>
<WorkspaceIntegrationsTab
is-modal
:filter-category="filterIntegrationCategory"
:filter-integration="filterIntegration"
/>
<WorkspaceIntegrationsTab is-modal :filter-category="filterIntegrationCategory" />
<WorkspaceIntegrationsEditOrAdd load-datasource-info :base-id="baseId" />
</div>
</div>

6
packages/nc-gui/components/workspace/integrations/ConnectionsTab.vue

@ -229,18 +229,18 @@ onKeyStroke('ArrowDown', onDown)
<template>
<div class="h-full flex flex-col gap-6 nc-workspace-connections">
<div class="flex justify-between gap-12">
<div class="flex flex-col justify-between gap-2 mx-1">
<div class="text-sm font-normal text-gray-600">
<div>
Manage connections for your integrations.
<a target="_blank" rel="noopener noreferrer"> Learn more </a>
</div>
</div>
<div class="flex items-center justify-end gap-3 mx-1">
<div class="flex items-center gap-3">
<a-input
v-model:value="searchQuery"
type="text"
class="nc-search-integration-input !min-w-[300px] nc-input-sm flex-none"
class="nc-search-integration-input !min-w-[300px] !max-w-[400px] nc-input-sm flex-none"
:placeholder="`${$t('general.search')} ${$t('general.connections').toLowerCase()}`"
allow-clear
@input="handleSearchConnection"

225
packages/nc-gui/components/workspace/integrations/IntegrationsTab.vue

@ -1,4 +1,5 @@
<script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core'
import NcModal from '~/components/nc/Modal.vue'
/* eslint-disable @typescript-eslint/consistent-type-imports */
import { IntegrationCategoryType, type IntegrationItemType, SyncDataType } from '#imports'
@ -26,12 +27,12 @@ const { syncDataUpvotes, updateSyncDataUpvotes } = useGlobal()
const { pageMode, IntegrationsPageMode, requestIntegration, addIntegration, saveIntegraitonRequest } = useIntegrationStore()
const focusTextArea: VNodeRef = (el) => el && el?.focus?.()
const activeCategory = ref<IntegrationCategoryItemType | null>(null)
const searchQuery = ref<string>('')
const requestNewIntegrationRef = ref<HTMLDivElement>()
const integrationListRef = ref<HTMLDivElement>()
const { width: integrationListContainerWidth } = useElementSize(integrationListRef)
@ -73,6 +74,7 @@ const integrationsMapByCategory = computed(() => {
acc[curr.value] = {
title: curr.title,
list: getIntegrationsByCategory(curr.value, searchQuery.value),
isAvailable: curr.isAvailable,
}
return acc
@ -82,6 +84,7 @@ const integrationsMapByCategory = computed(() => {
{
title: string
list: IntegrationItemType[]
isAvailable?: boolean
}
>,
)
@ -100,17 +103,17 @@ const isAddNewIntegrationModalOpen = computed({
},
})
const handleUpvote = (syncDataType: SyncDataType) => {
const handleUpvote = (category: IntegrationCategoryType, syncDataType: SyncDataType) => {
if (upvotesData.value.has(syncDataType)) return
$e(`a:integration-request:${syncDataType}`)
$e(`a:integration-request:${category}:${syncDataType}`)
updateSyncDataUpvotes([...syncDataUpvotes.value, syncDataType])
}
const handleAddIntegration = (category: IntegrationCategoryType, integration: IntegrationItemType) => {
if (!integration.isAvailable) {
handleUpvote(integration.value)
handleUpvote(category, integration.value)
return
}
@ -121,23 +124,6 @@ const handleAddIntegration = (category: IntegrationCategoryType, integration: In
addIntegration(integration.value)
}
const handleSetRequestIntegrationRef = (node) => {
requestNewIntegrationRef.value = node as HTMLDivElement
return node
}
const handleOpenRequestIntegration = () => {
requestIntegration.value.isOpen = true
nextTick(() => {
requestNewIntegrationRef.value?.scrollIntoView?.({ behavior: 'smooth' })
requestNewIntegrationRef.value?.querySelector('textarea')?.focus?.()
requestNewIntegrationRef.value?.querySelector('textarea')?.select?.()
})
}
</script>
<template>
@ -153,54 +139,6 @@ const handleOpenRequestIntegration = () => {
@keydown.esc="isAddNewIntegrationModalOpen = false"
>
<a-layout>
<!-- <a-layout-sider class="nc-integration-layout-sidebar"> -->
<!-- <div class="h-full flex flex-col gap-3"> -->
<!-- <div class="px-5 pt-3 text-sm text-gray-500 font-bold"> -->
<!-- {{ $t('title.categories') }} -->
<!-- </div> -->
<!-- <div class="px-3 pb-3 flex-1 flex flex-col gap-1 overflow-y-auto nc-scrollbar-thin"> -->
<!-- <div -->
<!-- class="nc-integration-category-item" -->
<!-- :class="{ -->
<!-- active: activeCategory === null, -->
<!-- }" -->
<!-- data-testid="all-integrations" -->
<!-- @click="activeCategory = null" -->
<!-- > -->
<!-- <div class="nc-integration-category-item-icon-wrapper bg-gray-200"> -->
<!-- <GeneralIcon icon="globe" class="stroke-transparent !text-gray-700" /> -->
<!-- </div> -->
<!-- <div class="nc-integration-category-item-content-wrapper"> -->
<!-- <div class="nc-integration-category-item-title">All Integrations</div> -->
<!-- &lt;!&ndash; <div class="nc-integration-category-item-subtitle">Content needed</div>&ndash;&gt; -->
<!-- </div> -->
<!-- </div> -->
<!-- <div -->
<!-- v-for="category of integrationCategories" -->
<!-- :key="category.value" -->
<!-- class="nc-integration-category-item" -->
<!-- :class="{ -->
<!-- active: activeCategory === category, -->
<!-- }" -->
<!-- :data-testid="category.value" -->
<!-- @click="activeCategory = category" -->
<!-- > -->
<!-- <div -->
<!-- class="nc-integration-category-item-icon-wrapper" -->
<!-- :style="{ -->
<!-- backgroundColor: category.iconBgColor, -->
<!-- }" -->
<!-- > -->
<!-- <component :is="category.icon" class="nc-integration-category-item-icon" :style="category.iconStyle" /> -->
<!-- </div> -->
<!-- <div class="nc-integration-category-item-content-wrapper"> -->
<!-- <div class="nc-integration-category-item-title">{{ $t(category.title) }}</div> -->
<!-- &lt;!&ndash; <div class="nc-integration-category-item-subtitle">{{ $t(category.subtitle) }}</div>&ndash;&gt; -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<!-- </a-layout-sider> -->
<a-layout-content class="nc-integration-layout-content">
<div v-if="isModal" class="p-4 w-full flex items-center justify-between gap-3 border-b-1 border-gray-200">
<NcButton type="text" size="small" @click="isAddNewIntegrationModalOpen = false">
@ -223,25 +161,30 @@ const handleOpenRequestIntegration = () => {
>
<div class="px-6 pt-6">
<div
class="flex items-center justify-between flex-wrap gap-3 m-auto"
class="flex items-end justify-end flex-wrap gap-3 m-auto"
:style="{
maxWidth: listWrapperMaxWidth,
}"
>
<div class="text-sm font-normal text-gray-600">
<div>Connect integrations with NocoDB. <a target="_blank" rel="noopener noreferrer"> Learn more </a></div>
<div class="flex-1">
<div class="text-sm font-normal text-gray-600 mb-2">
<div>Connect integrations with NocoDB. <a target="_blank" rel="noopener noreferrer"> Learn more </a></div>
</div>
<a-input
v-model:value="searchQuery"
type="text"
class="nc-input-border-on-value nc-search-integration-input !min-w-[300px] !max-w-[400px] nc-input-sm flex-none"
placeholder="Search integration"
allow-clear
>
<template #prefix>
<GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500" />
</template>
</a-input>
</div>
<a-input
v-model:value="searchQuery"
type="text"
class="nc-input-border-on-value nc-search-integration-input !min-w-[300px] !max-w-[400px] nc-input-sm flex-none"
placeholder="Search integration..."
allow-clear
>
<template #prefix>
<GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500" />
</template>
</a-input>
<NcButton type="ghost" size="small" class="!text-primary" @click="requestIntegration.isOpen = true">
Request integration
</NcButton>
</div>
</div>
@ -262,7 +205,15 @@ const handleOpenRequestIntegration = () => {
:key="key"
class="integration-type-wrapper"
>
<div class="category-type-title">{{ $t(category.title) }}</div>
<div class="category-type-title flex gap-2">
{{ $t(category.title) }}
<NcBadge
v-if="!category.isAvailable"
:border="false"
class="text-brand-500 !h-5 bg-brand-50 text-xs font-normal px-2"
>{{ $t('msg.toast.futureRelease') }}</NcBadge
>
</div>
<div v-if="category.list.length" class="integration-type-list">
<NcTooltip
v-for="integration of category.list"
@ -302,67 +253,49 @@ const handleOpenRequestIntegration = () => {
</NcTooltip>
</div>
</div>
<div
v-if="key === IntegrationCategoryType.OTHERS"
:key="`${key}-request-integration`"
:ref="handleSetRequestIntegrationRef"
class="integration-type-wrapper !mt-4"
>
<div>
<div
class="source-card-request-integration"
:class="{
active: requestIntegration.isOpen,
}"
>
<div
v-if="!requestIntegration.isOpen"
class="source-card-item border-none"
@click="handleOpenRequestIntegration"
>
<div class="flex items-center justify-center rounded-lg w-[44px] h-[44px]">
<GeneralIcon icon="plusSquare" class="flex-none w-8 h-8 !text-brand-500" />
</div>
<div class="name">Request New Integration</div>
</div>
<div v-show="requestIntegration.isOpen" class="flex flex-col gap-4">
<div class="flex items-center justify-between gap-4">
<div class="text-base font-bold text-gray-800">Request Integration</div>
<NcButton size="xsmall" type="text" @click="requestIntegration.isOpen = false">
<GeneralIcon icon="close" class="text-gray-600" />
</NcButton>
</div>
<div class="flex flex-col gap-2">
<a-textarea
v-model:value="requestIntegration.msg"
class="!rounded-md !text-sm !min-h-[120px] max-h-[500px] nc-scrollbar-thin"
size="large"
hide-details
placeholder="Provide integration name and your use-case."
/>
</div>
<div class="flex items-center justify-end gap-3">
<NcButton size="small" type="secondary" @click="requestIntegration.isOpen = false">
{{ $t('general.cancel') }}
</NcButton>
<NcButton
:disabled="!requestIntegration.msg?.trim()"
:loading="requestIntegration.isLoading"
size="small"
@click="saveIntegraitonRequest(requestIntegration.msg)"
>
{{ $t('general.submit') }}
</NcButton>
</div>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
<NcModal
v-model:visible="requestIntegration.isOpen"
centered
size="medium"
@keydown.esc="requestIntegration.isOpen = false"
>
<div v-show="requestIntegration.isOpen" class="flex flex-col gap-4">
<div class="flex items-center justify-between gap-4">
<div class="text-base font-bold text-gray-800">Request Integration</div>
<NcButton size="small" type="text" @click="requestIntegration.isOpen = false">
<GeneralIcon icon="close" class="text-gray-600" />
</NcButton>
</div>
<div class="flex flex-col gap-2">
<a-textarea
:ref="focusTextArea"
v-model:value="requestIntegration.msg"
class="!rounded-md !text-sm !min-h-[120px] max-h-[500px] nc-scrollbar-thin"
size="large"
hide-details
placeholder="Provide integration name and your use-case."
/>
</div>
<div class="flex items-center justify-end gap-3">
<NcButton size="small" type="secondary" @click="requestIntegration.isOpen = false">
{{ $t('general.cancel') }}
</NcButton>
<NcButton
:disabled="!requestIntegration.msg?.trim()"
:loading="requestIntegration.isLoading"
size="small"
@click="saveIntegraitonRequest(requestIntegration.msg)"
>
{{ $t('general.submit') }}
</NcButton>
</div>
</div>
</NcModal>
</a-layout-content>
</a-layout>
</component>
@ -485,15 +418,15 @@ const handleOpenRequestIntegration = () => {
.integration-icon-wrapper {
// @apply bg-gray-50;
.integration-icon {
@apply !grayscale;
// .integration-icon {
// @apply !grayscale;
filter: grayscale(100%) brightness(115%);
}
// filter: grayscale(100%) brightness(115%);
// }
}
.name {
@apply text-gray-500;
@apply text-gray-800;
}
}

2
packages/nc-gui/utils/iconUtils.ts

@ -249,6 +249,7 @@ import NcMicrosoftTeams from '~icons/nc-icons/microsoft-teams'
import NcMattermost from '~icons/nc-icons/mattermost'
import NcTwilio from '~icons/nc-icons/twilio'
import NcWhatsapp from '~icons/nc-icons/whatsapp'
import NcWhatsappSolid from '~icons/nc-icons/whatsapp-solid'
// View icons
import NcViewGantt from '~icons/nc-icons/view-gantt'
@ -751,6 +752,7 @@ export const iconMap = {
mattermost: NcMattermost,
twilio: NcTwilio,
whatsapp: NcWhatsapp,
whatsappSolid: NcWhatsappSolid,
viewGannt: NcViewGantt,
dollerSign: NcDollerSign,
multiFile: NcMultiFile,

4
packages/nc-gui/utils/syncDataUtils.ts

@ -17,6 +17,7 @@ export interface IntegrationCategoryItemType {
icon: FunctionalComponent<SVGAttributes, {}, any, {}>
iconBgColor?: string
iconStyle?: CSSProperties
isAvailable?: boolean
}
export const integrationCategories: IntegrationCategoryItemType[] = [
@ -29,6 +30,7 @@ export const integrationCategories: IntegrationCategoryItemType[] = [
iconStyle: {
color: '#17803D',
},
isAvailable: true
},
{
title: 'objects.integrationCategories.communication',
@ -252,7 +254,7 @@ export const allIntegrations: IntegrationItemType[] = [
{
title: 'objects.syncData.whatsapp',
value: SyncDataType.WHATSAPP,
icon: iconMap.whatsapp,
icon: iconMap.whatsappSolid,
categories: [IntegrationCategoryType.COMMUNICATION],
iconStyle: {
width: '32px',

Loading…
Cancel
Save