import type { BaseType, OracleUi, ProjectType, TableType } from 'nocodb-sdk' import { SqlUiFactory } from 'nocodb-sdk' import { isString } from '@vueuse/core' import { defineStore } from 'pinia' import { ClientType, computed, createEventHook, ref, useApi, useGlobal, useNuxtApp, useRoles, useRouter, useTheme, } from '#imports' import type { ProjectMetaInfo, ThemeConfig } from '~/lib' export const useProject = defineStore('projectStore', () => { const { $e } = useNuxtApp() const { api, isLoading } = useApi() const router = useRouter() const route = $(router.currentRoute) const { includeM2M } = useGlobal() const { setTheme, theme } = useTheme() const { projectRoles, loadProjectRoles } = useRoles() const projectLoadedHook = createEventHook() const project = ref({}) const bases = computed(() => project.value?.bases || []) const tables = ref([]) const projectMetaInfo = ref() const lastOpenedViewMap = ref>({}) const forcedProjectId = ref() const projectId = computed(() => forcedProjectId.value || (route.params.projectId as string)) // todo: refactor path param name and variable name const projectType = $computed(() => route.params.projectType as string) const projectMeta = computed>(() => { const defaultMeta = { showNullAndEmptyInFilter: false, } try { return (isString(project.value.meta) ? JSON.parse(project.value.meta) : project.value.meta) ?? defaultMeta } catch (e) { return defaultMeta } }) const sqlUis = computed(() => { const temp: Record = {} for (const base of bases.value) { if (base.id) { temp[base.id] = SqlUiFactory.create({ client: base.type }) as Exclude< ReturnType, typeof OracleUi > } } return temp }) function getBaseType(baseId?: string) { return bases.value.find((base) => base.id === baseId)?.type || ClientType.MYSQL } function isMysql(baseId?: string) { return ['mysql', ClientType.MYSQL].includes(getBaseType(baseId)) } function isSqlite(baseId?: string) { return getBaseType(baseId) === ClientType.SQLITE } function isMssql(baseId?: string) { return getBaseType(baseId) === 'mssql' } function isPg(baseId?: string) { return getBaseType(baseId) === 'pg' } function isXcdbBase(baseId?: string) { return (bases.value.find((base) => base.id === baseId)?.is_meta as boolean) || false } const isSharedBase = computed(() => projectType === 'base') async function loadProjectMetaInfo(force?: boolean) { if (!projectMetaInfo.value || force) { projectMetaInfo.value = await api.project.metaGet(project.value.id!, {}) } } async function loadTables() { if (project.value.id) { const tablesResponse = await api.dbTable.list(project.value.id, { includeM2M: includeM2M.value, }) if (tablesResponse.list) { tables.value = tablesResponse.list.filter((table) => bases.value.find((base) => base.id === table.base_id)?.enabled) } } } async function loadProject(withTheme = true, forcedId?: string) { if (forcedId) forcedProjectId.value = forcedId if (projectType === 'base') { try { const baseData = await api.public.sharedBaseGet(route.params.projectId as string) project.value = await api.project.read(baseData.project_id!) } catch (e: any) { if (e?.response?.status === 404) { return router.push('/error/404') } throw e } } else if (projectId.value) { project.value = await api.project.read(projectId.value) } else { console.warn('Project id not found') return } await loadProjectRoles(project.value.id || projectId.value, isSharedBase.value, projectId.value) await loadTables() if (withTheme) setTheme(projectMeta.value?.theme) return projectLoadedHook.trigger(project.value) } async function updateProject(data: Partial) { if (projectType === 'base') { return } if (data.meta && typeof data.meta === 'string') { await api.project.update(projectId.value, data) } else { await api.project.update(projectId.value, { ...data, meta: stringifyProp(data.meta) }) } } async function saveTheme(_theme: Partial) { const fullTheme = { primaryColor: theme.value.primaryColor, accentColor: theme.value.accentColor, ..._theme, } await updateProject({ color: fullTheme.primaryColor, meta: { ...projectMeta.value, theme: fullTheme, }, }) setTheme(fullTheme) $e('c:themes:change') } async function hasEmptyOrNullFilters() { return await api.project.hasEmptyOrNullFilters(projectId.value) } const reset = () => { project.value = {} tables.value = [] projectMetaInfo.value = undefined projectRoles.value = {} setTheme() } const setProject = (projectVal: ProjectType) => { project.value = projectVal } watch( () => route.params.projectType, (n) => { if (!n) reset() }, { immediate: true }, ) return { project, bases, tables, loadProjectRoles, loadProject, updateProject, loadTables, isMysql, isMssql, isPg, isSqlite, sqlUis, isSharedBase, loadProjectMetaInfo, projectMetaInfo, projectMeta, saveTheme, projectLoadedHook: projectLoadedHook.on, reset, isLoading, lastOpenedViewMap, isXcdbBase, hasEmptyOrNullFilters, setProject, } })