import type { IntegrationType, PaginatedType } from 'nocodb-sdk' import { IntegrationsType } from 'nocodb-sdk' import { ClientType } from '../lib/enums' import GeneralBaseLogo from '~/components/general/BaseLogo.vue' import type { IntegrationStoreEvents as IntegrationStoreEventsTypes } from '#imports' enum IntegrationsPageMode { LIST, ADD, EDIT, } const integrationType: Record<'PostgreSQL' | 'MySQL', ClientType> = { PostgreSQL: ClientType.PG, MySQL: ClientType.MYSQL, } type IntegrationsSubType = (typeof integrationType)[keyof typeof integrationType] function defaultValues(type: IntegrationsSubType) { const genericValues = { payload: {}, } switch (type) { case integrationType.PostgreSQL: return { ...genericValues, type: integrationType.PostgreSQL, title: 'PostgreSQL', logo: h(GeneralBaseLogo, { 'source-type': 'pg', 'class': 'logo', }), } case integrationType.MySQL: return { ...genericValues, type: integrationType.MySQL, title: 'MySQL', logo: h(GeneralBaseLogo, { 'source-type': 'mysql2', 'class': 'logo', }), } } } const [useProvideIntegrationViewStore, _useIntegrationStore] = useInjectionState(() => { const router = useRouter() const route = router.currentRoute const { api } = useApi() const pageMode = ref(null) const activeIntegration = ref(null) const workspaceStore = useWorkspace() const { activeWorkspaceId } = storeToRefs(workspaceStore) const integrations = ref([]) const searchQuery = ref('') const integrationPaginationData = ref({ page: 1, pageSize: 25, totalRows: 0 }) const deleteConfirmText = ref() const isLoadingIntegrations = ref(false) const eventBus = useEventBus(Symbol('integrationStore')) const { $e } = useNuxtApp() const { t } = useI18n() const isFromIntegrationPage = ref(false) const successConfirmModal = ref({ isOpen: false, title: t('msg.success.connectionAdded'), connectionTitle: '', description: t('msg.success.connectionAddedDesc'), }) const requestIntegration = ref({ isOpen: false, msg: '', isLoading: false, }) const activeViewTab = computed({ get() { return (route.value.query?.tab as string) ?? 'integrations' }, set(tab: string) { if (requestIntegration.value.isOpen) { requestIntegration.value.isOpen = false } router.push({ query: { ...route.value.query, tab } }) }, }) const loadIntegrations = async ( databaseOnly = false, baseId = undefined, page: number = integrationPaginationData.value.page!, limit: number = integrationPaginationData.value.pageSize!, ) => { try { if (!activeWorkspaceId.value) return isLoadingIntegrations.value = true if (!databaseOnly && limit * (page - 1) > integrationPaginationData.value.totalRows!) { integrationPaginationData.value.page = 1 page = 1 } const { list, pageInfo } = await api.integration.list( databaseOnly ? { type: IntegrationsType.Database, includeDatabaseInfo: true, baseId, } : { offset: limit * (page - 1), limit, ...(searchQuery.value.trim() ? { query: searchQuery.value } : {}), }, ) integrations.value = list if (!databaseOnly) { integrationPaginationData.value.totalRows = pageInfo.totalRows ?? 0 } } catch (e) { await message.error(await extractSdkResponseErrorMsg(e)) integrations.value = [] integrationPaginationData.value.totalRows = 0 integrationPaginationData.value.page = 1 } finally { isLoadingIntegrations.value = false } } const addIntegration = (type: IntegrationsSubType) => { activeIntegration.value = defaultValues(type) pageMode.value = IntegrationsPageMode.ADD $e('c:integration:add') } const deleteIntegration = async (integration: IntegrationType, force = false) => { if (!integration?.id) return try { await api.integration.delete(integration.id, { query: force ? { force: 'true' } : {}, }) $e('a:integration:delete') await loadIntegrations() // await message.success(`Connection ${integration.title} deleted successfully`) return true } catch (e) { const error = await extractSdkResponseErrorMsgv2(e) if (error.error === NcErrorType.INTEGRATION_NOT_FOUND) { await message.error(error.message?.replace(integration.id, integration.title!)) window.location.reload() return } await message.error(await extractSdkResponseErrorMsg(e)) } deleteConfirmText.value = null } const updateIntegration = async (integration: IntegrationType) => { if (!integration.id) return try { await api.integration.update(integration.id, integration) $e('a:integration:update') await loadIntegrations() pageMode.value = null activeIntegration.value = null await message.success(`Connection "${integration.title}" updated successfully`) } catch (e) { await message.error(await extractSdkResponseErrorMsg(e)) } } const saveIntegration = async ( integration: IntegrationType, mode: 'create' | 'duplicate' = 'create', loadDatasourceInfo = false, baseId: string | undefined = undefined, ) => { try { const response = await api.integration.create(integration) if (mode === 'create') { $e('a:integration:create') } else { $e('a:integration:duplicate') } if (response && response?.id) { if (!loadDatasourceInfo) { integrations.value.push(response) } } await loadIntegrations(loadDatasourceInfo, baseId) eventBus.emit(IntegrationStoreEvents.INTEGRATION_ADD, response) pageMode.value = null activeIntegration.value = null if (response?.title && mode === 'create') { if (isFromIntegrationPage.value) { activeViewTab.value = 'connections' successConfirmModal.value.connectionTitle = response.title ?? '' successConfirmModal.value.isOpen = true } else { await message.success(`Connection "${response.title}" created successfully`) } } } catch (e) { await message.error(await extractSdkResponseErrorMsg(e)) } } const duplicateIntegration = async (integration: IntegrationType) => { if (!integration?.id) return try { isLoadingIntegrations.value = true saveIntegration( { title: integration.title, config: {}, type: integration.type, copy_from_id: integration.id, }, 'duplicate', ) } catch (e) { await message.error(await extractSdkResponseErrorMsg(e)) } finally { isLoadingIntegrations.value = false } } const getIntegration = async ( integration: IntegrationType, options?: { includeConfig?: boolean includeSources?: boolean }, ) => { if (!integration?.id) return try { const integrationWithConfig = await api.integration.read(integration.id, { ...(options || {}), }) return integrationWithConfig } catch (e) { const error = await extractSdkResponseErrorMsgv2(e) if (error.error === NcErrorType.INTEGRATION_NOT_FOUND) { await message.error(error.message?.replace(integration.id!, integration.title!)) window.location.reload() return } await message.error(await extractSdkResponseErrorMsg(e)) } } const editIntegration = async (integration: IntegrationType) => { if (!integration?.id) return try { const integrationWithConfig = await getIntegration(integration, { includeConfig: true }) activeIntegration.value = integrationWithConfig pageMode.value = IntegrationsPageMode.EDIT $e('c:integration:edit') } catch {} } const saveIntegraitonRequest = async (msg: string) => { if (!msg?.trim()) return requestIntegration.value.isLoading = true try { $e('a:integration:new-request', { value: requestIntegration.value.msg, }) requestIntegration.value.isLoading = false requestIntegration.value.isOpen = false requestIntegration.value.msg = '' await message.success('Your request has been successfully submitted') } catch (e) { requestIntegration.value.isLoading = false await message.error(await extractSdkResponseErrorMsg(e)) } } return { IntegrationsPageMode, integrationType, pageMode, activeIntegration, integrations, isLoadingIntegrations, deleteConfirmText, eventBus, requestIntegration, integrationPaginationData, activeViewTab, isFromIntegrationPage, successConfirmModal, searchQuery, addIntegration, loadIntegrations, deleteIntegration, updateIntegration, saveIntegration, editIntegration, duplicateIntegration, saveIntegraitonRequest, getIntegration, } }, 'integrations-store') export { useProvideIntegrationViewStore } export function useIntegrationStore() { const integrationStore = _useIntegrationStore() if (integrationStore == null) return useProvideIntegrationViewStore() return integrationStore }