feat: inject dynamic env to next (#392)

* fix: auto disable template entry

* feat: inject dynamic env to next
This commit is contained in:
tea artist 2024-03-04 00:21:30 +08:00 committed by GitHub
parent b6e533b9fa
commit ed056d63ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 107 additions and 97 deletions

View File

@ -15,9 +15,9 @@ NEXT_BUILD_ENV_SENTRY_TRACING=false
NEXTJS_DISABLE_SENTRY=true
NEXTJS_SENTRY_UPLOAD_DRY_RUN=true
# set metrics id
NEXT_PUBLIC_MICROSOFT_CLARITY=your-metrics-id
MICROSOFT_CLARITY_ID=your-metrics-id
# help site link
NEXT_PUBLIC_HELP_SITE_LINK=https://help.teable.io
HELP_SITE_LINK=https://help.teable.io
# ↓↓↓↓↓↓↓↓ backendnestjs env ↓↓↓↓↓↓↓↓
NEXTJS_DIR=../nextjs-app
@ -48,7 +48,7 @@ BACKEND_MAIL_AUTH_PASS=usertoken
# The spaceId where your template base is located, it is the basic info of template center operation
TEMPLATE_SPACE_ID=your-template-space-id
# template site link, you need to set the current value to enable create from template
NEXT_PUBLIC_TEMPLATE_SITE_LINK=https://template.teable.io
TEMPLATE_SITE_LINK=https://template.teable.io
# ↓↓↓↓↓↓↓↓ limitaions, time unit is ms ↓↓↓↓↓↓↓↓
MAX_COPY_CELLS=50000

View File

@ -1,16 +1,19 @@
import { Toaster as SoonerToaster } from '@teable/ui-lib/shadcn/ui/sonner';
import { Toaster } from '@teable/ui-lib/shadcn/ui/toaster';
import type { FC, PropsWithChildren } from 'react';
import type { IServerEnv } from './lib/server-env';
import { EnvContext } from './lib/server-env';
type Props = PropsWithChildren;
export const AppProviders: FC<Props> = (props) => {
const { children } = props;
export const AppProviders: FC<Props & { env: IServerEnv }> = (props) => {
const { children, env } = props;
return (
<>
<EnvContext.Provider value={env}>
{children}
<Toaster />
<SoonerToaster />
</>
</EnvContext.Provider>
);
};

View File

@ -1,8 +1,8 @@
import type { IUserMeVo } from '@teable/openapi';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/router';
import { useTranslation, Trans } from 'next-i18next';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { ACTIONS, EVENTS, STATUS } from 'react-joyride';
import type { CallBackProps, Step, StoreHelpers } from 'react-joyride';
import colors from 'tailwindcss/colors';

View File

@ -1,7 +1,7 @@
import Script from 'next/script';
export const MicrosoftClarity = () => {
if (!process.env.NEXT_PUBLIC_MICROSOFT_CLARITY) {
export const MicrosoftClarity = ({ clarityId }: { clarityId?: string }) => {
if (!clarityId) {
return null;
}
@ -15,7 +15,7 @@ export const MicrosoftClarity = () => {
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "${process.env.NEXT_PUBLIC_MICROSOFT_CLARITY}");
})(window, document, "clarity", "script", "${clarityId}");
`,
}}
/>

View File

@ -1,3 +1,4 @@
import type { DriverClient } from '@teable/core';
import type { ShareViewGetVo } from '@teable/openapi';
import { AnchorContext, AppProvider, FieldProvider, ViewProvider } from '@teable/sdk/context';
import { getWsPath } from '@teable/sdk/context/app/useConnection';
@ -12,6 +13,7 @@ import { ViewProxy } from './ViewProxy';
export interface IShareViewPageProps {
shareViewData: ShareViewGetVo;
driver: DriverClient;
}
export const ShareViewPage = (props: IShareViewPageProps) => {
@ -30,7 +32,7 @@ export const ShareViewPage = (props: IShareViewPageProps) => {
return (
<ShareViewPageContext.Provider value={props.shareViewData}>
<AppLayout>
<AppProvider wsPath={wsPath} locale={sdkLocale}>
<AppProvider wsPath={wsPath} locale={sdkLocale} driver={props.driver}>
<AnchorContext.Provider
value={{
tableId,

View File

@ -2,10 +2,10 @@ import { HelpCircle, Settings, UserPlus } from '@teable/icons';
import { useBase, useTableId } from '@teable/sdk/hooks';
import { Button } from '@teable/ui-lib/shadcn';
import Link from 'next/link';
import { useTranslation } from 'react-i18next';
import { useTranslation } from 'next-i18next';
import { SpaceCollaboratorModalTrigger } from '@/features/app/components/collaborator-manage/space/SpaceCollaboratorModalTrigger';
import { useEnv } from '@/features/app/hooks/useEnv';
import { spaceConfig } from '@/features/i18n/space.config';
import { getHelpLink } from '@/lib/off-site-link';
import { ExpandViewList } from '../../view/list/ExpandViewList';
import { ViewList } from '../../view/list/ViewList';
@ -16,6 +16,7 @@ import { TableInfo } from './TableInfo';
export const TableHeader: React.FC = () => {
const base = useBase();
const tableId = useTableId();
const { helpSiteLink } = useEnv();
const { t } = useTranslation(spaceConfig.i18nNamespaces);
return (
@ -42,7 +43,7 @@ export const TableHeader: React.FC = () => {
</Link>
</Button>
<Button asChild variant="ghost" size="xs" className="hidden sm:flex">
<a href={getHelpLink()} title="Help" target="_blank" rel="noreferrer">
<a href={helpSiteLink} title="Help" target="_blank" rel="noreferrer">
<HelpCircle className="size-4" />
</a>
</Button>

View File

@ -1,6 +1,6 @@
/* eslint-disable @next/next/no-html-link-for-pages */
import { TeableNew } from '@teable/icons';
import { Trans, useTranslation } from 'react-i18next';
import { Trans, useTranslation } from 'next-i18next';
import { tableConfig } from '@/features/i18n/table.config';
export const BrandFooter = () => {

View File

@ -17,8 +17,8 @@ import {
Textarea,
cn,
} from '@teable/ui-lib/shadcn';
import { useTranslation } from 'next-i18next';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FieldOperator } from '@/features/app/components/field-setting';
import { tableConfig } from '@/features/i18n/table.config';
import { useFieldSettingStore } from '../../field/useFieldSettingStore';

View File

@ -1,7 +1,7 @@
import { useFieldStaticGetter, useView } from '@teable/sdk/hooks';
import type { FormView, IFieldInstance } from '@teable/sdk/model';
import { useTranslation } from 'next-i18next';
import type { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { tableConfig } from '@/features/i18n/table.config';
import { FormCellEditor } from './FormCellEditor';

View File

@ -11,8 +11,8 @@ import {
TooltipProvider,
TooltipTrigger,
} from '@teable/ui-lib/shadcn';
import { useTranslation } from 'next-i18next';
import type { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { tableConfig } from '@/features/i18n/table.config';
interface IFormFieldEditorProps {

View File

@ -4,8 +4,8 @@ import { useFields, useTableId, useView } from '@teable/sdk/hooks';
import { type FormView } from '@teable/sdk/model';
import { Button, cn, useToast } from '@teable/ui-lib/shadcn';
import { omit } from 'lodash';
import { useTranslation } from 'next-i18next';
import { useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocalStorage, useMap, useSet } from 'react-use';
import { tableConfig } from '@/features/i18n/table.config';
import { generateUniqLocalKey } from '../util';

View File

@ -13,9 +13,9 @@ import {
TooltipTrigger,
cn,
} from '@teable/ui-lib/shadcn';
import { useTranslation } from 'next-i18next';
import type { FC } from 'react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { FieldOperator } from '@/features/app/components/field-setting';
import { tableConfig } from '@/features/i18n/table.config';
import { useFieldSettingStore } from '../../field/useFieldSettingStore';

View File

@ -3,8 +3,8 @@ import { Plus } from '@teable/icons';
import { LinkCard } from '@teable/sdk/components';
import type { LinkField } from '@teable/sdk/model';
import { Button, Popover, PopoverContent, PopoverTrigger } from '@teable/ui-lib/shadcn';
import { useTranslation } from 'next-i18next';
import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { tableConfig } from '@/features/i18n/table.config';
import { LinkRecordList } from './LinkRecordList';

View File

@ -14,8 +14,8 @@ import {
cn,
} from '@teable/ui-lib/shadcn';
import { debounce } from 'lodash';
import { useTranslation } from 'next-i18next';
import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useUnmount } from 'react-use';
import { tableConfig } from '@/features/i18n/table.config';

View File

@ -1,8 +1,8 @@
import { ArrowUpRight, Settings as Edit, Edit as Fill } from '@teable/icons';
import { useTableId, useTablePermission, useViewId } from '@teable/sdk/hooks';
import { Button } from '@teable/ui-lib/shadcn';
import { useTranslation } from 'next-i18next';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { tableConfig } from '@/features/i18n/table.config';
import { generateUniqLocalKey } from '../form/util';
import { SharePopover } from './SharePopover';

View File

@ -13,7 +13,7 @@ import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import type { ReactNode } from 'react';
import { spaceConfig } from '@/features/i18n/space.config';
import { getTemplateCenterLink } from '@/lib/off-site-link';
import { useEnv } from '../../hooks/useEnv';
export const CreateBaseModalTrigger = ({
spaceId,
@ -33,7 +33,7 @@ export const CreateBaseModalTrigger = ({
});
},
});
const templateCenterLink = getTemplateCenterLink();
const { templateSiteLink } = useEnv();
return (
<Dialog>
@ -53,15 +53,13 @@ export const CreateBaseModalTrigger = ({
{t('space:baseModal.fromScratch')}
</Button>
<Button
asChild
className="flex h-auto grow flex-col items-center gap-4"
variant="ghost"
disabled={!templateCenterLink}
disabled={!templateSiteLink}
onClick={() => (window.location.href = templateSiteLink as string)}
>
<a href={templateCenterLink}>
<LayoutTemplate className="size-8" />
{t('space:baseModal.fromTemplate')}
</a>
<LayoutTemplate className="size-8" />
{t('space:baseModal.fromTemplate')}
</Button>
</div>
</DialogContent>

View File

@ -4,7 +4,8 @@ import { useTranslation } from 'next-i18next';
import { useState } from 'react';
import { useLocalStorage } from 'react-use';
import { dashboardConfig } from '@/features/i18n/dashboard.config';
import { getHelpLink } from '@/lib/off-site-link';
import { useEnv } from '../hooks/useEnv';
import { Pickers } from './components/Pickers';
import { GridContent } from './GridContent';
@ -13,7 +14,7 @@ export function DashboardPage() {
const [anchor, setAnchor] = useState<{ tableId?: string; viewId?: string }>({});
const { viewId, tableId } = anchor;
const [showDashboard, setShowDashboard] = useLocalStorage('showDashboard', false);
const { helpSiteLink } = useEnv();
return (
<AnchorProvider viewId={viewId} tableId={tableId}>
<div className="h-full flex-col md:flex">
@ -28,7 +29,7 @@ export function DashboardPage() {
<li>
Visit the{' '}
<a
href={getHelpLink()}
href={helpSiteLink}
className="text-blue-500 hover:text-blue-700"
target="_blank"
rel="noreferrer"

View File

@ -1,7 +1,6 @@
import type { ISelectFieldOptions } from '@teable/core';
import { Colors, ColorUtils, CellValueType, FieldType } from '@teable/core';
import { useBase, useFields, useTable, useView } from '@teable/sdk/hooks';
import { Base } from '@teable/sdk/model';
import { useEffect, useMemo, useState } from 'react';
interface IData {
@ -35,7 +34,8 @@ export function useChartData() {
return;
}
const nativeSql = Base.knex(table.dbTableName)
const nativeSql = base
.knex(table.dbTableName)
.select(`${groupingField.dbFieldName} as name`)
.sum(`${numberField.dbFieldName} as total`)
.groupBy(groupingField.dbFieldName)

View File

@ -1,6 +1,5 @@
import { CellValueType, FieldType } from '@teable/core';
import { useBase, useFields, useTable, useViewId } from '@teable/sdk/hooks';
import { Base } from '@teable/sdk/model';
import { useEffect, useMemo, useState } from 'react';
interface IData {
@ -35,7 +34,8 @@ export function useLineChartData() {
const nameColumn = selectField.dbFieldName;
const numberColumn = numberField.dbFieldName;
const nativeSql = Base.knex(table.dbTableName)
const nativeSql = base
.knex(table.dbTableName)
.select(nameColumn)
.min(numberColumn + ' as total')
.avg(numberColumn + ' as average')

View File

@ -0,0 +1,6 @@
import { useContext } from 'react';
import { EnvContext } from '@/lib/server-env';
export function useEnv() {
return useContext(EnvContext);
}

View File

@ -1,4 +1,4 @@
import type { ITableVo } from '@teable/core';
import type { DriverClient, ITableVo } from '@teable/core';
import type { IGetBaseVo } from '@teable/openapi';
import { NotificationProvider, SessionProvider } from '@teable/sdk';
import type { IUser } from '@teable/sdk';
@ -14,15 +14,16 @@ export const BaseLayout: React.FC<{
children: React.ReactNode;
tableServerData: ITableVo[];
baseServerData: IGetBaseVo;
driver?: DriverClient;
user?: IUser;
}> = ({ children, tableServerData, baseServerData, user }) => {
}> = ({ children, tableServerData, baseServerData, driver, user }) => {
const router = useRouter();
const { baseId, tableId, viewId } = router.query;
const sdkLocale = useSdkLocale();
return (
<AppLayout>
<AppProvider locale={sdkLocale}>
<AppProvider locale={sdkLocale} driver={driver as DriverClient}>
<SessionProvider user={user}>
<NotificationProvider>
<AnchorContext.Provider

View File

@ -1,3 +1,4 @@
import type { DriverClient } from '@teable/core';
import type { IUser } from '@teable/sdk';
import { AppProvider, SessionProvider } from '@teable/sdk';
import React from 'react';
@ -7,12 +8,13 @@ import { useSdkLocale } from '../hooks/useSdkLocale';
export const SettingLayout: React.FC<{
children: React.ReactNode;
user?: IUser;
driver: DriverClient;
dehydratedState?: unknown;
}> = ({ children, user, dehydratedState }) => {
}> = ({ children, user, driver, dehydratedState }) => {
const sdkLocale = useSdkLocale();
return (
<AppLayout>
<AppProvider locale={sdkLocale} dehydratedState={dehydratedState}>
<AppProvider locale={sdkLocale} dehydratedState={dehydratedState} driver={driver}>
<SessionProvider user={user}>
<div id="portal" className="relative flex h-screen w-full items-start px-5">
{children}

View File

@ -1,3 +1,4 @@
import type { DriverClient } from '@teable/core';
import type { IUser } from '@teable/sdk';
import { NotificationProvider, SessionProvider } from '@teable/sdk';
import { AppProvider } from '@teable/sdk/context';
@ -10,12 +11,13 @@ export const SpaceLayout: React.FC<{
children: React.ReactNode;
user?: IUser;
dehydratedState?: unknown;
}> = ({ children, user, dehydratedState }) => {
driver: DriverClient;
}> = ({ children, user, driver, dehydratedState }) => {
const sdkLocale = useSdkLocale();
return (
<AppLayout>
<AppProvider locale={sdkLocale} dehydratedState={dehydratedState}>
<AppProvider locale={sdkLocale} dehydratedState={dehydratedState} driver={driver}>
<SessionProvider user={user}>
<NotificationProvider>
<div id="portal" className="relative flex h-screen w-full items-start">

View File

@ -1,3 +0,0 @@
export const getHelpLink = () => process.env.NEXT_PUBLIC_HELP_SITE_LINK || 'https://help.teable.io';
export const getTemplateCenterLink = () => process.env.NEXT_PUBLIC_TEMPLATE_SITE_LINK;

View File

@ -0,0 +1,9 @@
import React from 'react';
export interface IServerEnv {
helpSiteLink?: string;
templateSiteLink?: string;
microsoftClarityId?: string;
}
export const EnvContext = React.createContext<IServerEnv>({});

View File

@ -13,6 +13,7 @@ import { getUserMe } from '@/backend/api/rest/get-user';
import { Guide } from '@/components/Guide';
import { MicrosoftClarity } from '@/components/Metrics';
import RouterProgressBar from '@/components/RouterProgress';
import type { IServerEnv } from '@/lib/server-env';
import type { NextPageWithLayout } from '@/lib/type';
import { colors } from '@/themes/colors';
import { INITIAL_THEME } from '@/themes/initial';
@ -42,24 +43,20 @@ type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
user?: IUser;
driver: string;
env: IServerEnv;
};
/**
* @link https://nextjs.org/docs/advanced-features/custom-app
*/
const MyApp = (appProps: AppPropsWithLayout) => {
const { Component, pageProps, err, user, driver } = appProps;
const { Component, pageProps, err, user, driver, env } = appProps;
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
const serverInfo = {
driver,
user,
};
return (
<>
<AppProviders>
<AppProviders env={env}>
<Head>
<meta
name="viewport"
@ -67,18 +64,17 @@ const MyApp = (appProps: AppPropsWithLayout) => {
/>
<style>{getColorsCssVariablesText(colors)}</style>
</Head>
<MicrosoftClarity />
<MicrosoftClarity clarityId={env?.microsoftClarityId} />
<script dangerouslySetInnerHTML={{ __html: INITIAL_THEME }} />
<script
dangerouslySetInnerHTML={{
__html: `
window.__s = ${JSON.stringify(serverInfo)};
window.clarity && window.clarity("identify", "${user?.email || user?.id}");
`,
}}
/>
{/* Workaround for https://github.com/vercel/next.js/issues/8592 */}
{getLayout(<Component {...pageProps} err={err} />, { ...pageProps, user })}
{getLayout(<Component {...pageProps} err={err} />, { ...pageProps, user, driver })}
</AppProviders>
<Guide user={user} />
<RouterProgressBar />
@ -106,6 +102,11 @@ MyApp.getInitialProps = async (appContext: AppContext) => {
const initialProps = {
...appProps,
driver,
env: {
helpSiteLink: process.env.HELP_SITE_LINK,
templateSiteLink: process.env.TEMPLATE_SITE_LINK,
microsoftClarityId: process.env.MICROSOFT_CLARITY_ID,
},
};
if (!isLoginPage && !needLoginPage) {
return initialProps;

View File

@ -1,4 +1,4 @@
import type { IHttpError } from '@teable/core';
import { parseDsn, type DriverClient, type IHttpError } from '@teable/core';
import type { ShareViewGetVo } from '@teable/openapi';
import type { GetServerSideProps } from 'next';
import { SsrApi } from '@/backend/api/rest/table.ssr';
@ -17,9 +17,11 @@ export const getServerSideProps: GetServerSideProps<IShareViewPageProps> = async
res.setHeader('Content-Security-Policy', "frame-ancestors 'self' *;");
ssrApi.axios.defaults.headers['cookie'] = req.headers.cookie || '';
const shareViewData = await ssrApi.getShareView(shareId as string);
const driver = parseDsn(process.env.PRISMA_DATABASE_URL as string).driver as DriverClient;
return {
props: {
shareViewData,
driver,
...(await getTranslationsProps(context, i18nNamespaces)),
},
};
@ -40,6 +42,12 @@ export const getServerSideProps: GetServerSideProps<IShareViewPageProps> = async
}
};
export default function ShareView({ shareViewData }: { shareViewData: ShareViewGetVo }) {
return <ShareViewPage shareViewData={shareViewData} />;
export default function ShareView({
shareViewData,
driver,
}: {
shareViewData: ShareViewGetVo;
driver: DriverClient;
}) {
return <ShareViewPage shareViewData={shareViewData} driver={driver} />;
}

View File

@ -32,8 +32,6 @@ FROM deps AS builder
ARG INTEGRATION_TEST
ARG NEXT_PUBLIC_MICROSOFT_CLARITY
ENV NEXT_BUILD_ENV_TYPECHECK=false
ENV NEXT_BUILD_ENV_LINT=false
ENV NEXT_BUILD_ENV_OUTPUT=classic

View File

@ -1,7 +1,7 @@
import { Hydrate, QueryClientProvider } from '@tanstack/react-query';
import type { DriverClient } from '@teable/core';
import { isObject } from 'lodash';
import { useEffect, useMemo } from 'react';
import { getDriver } from '../../utils/driver';
import { AppContext } from '../app/AppContext';
import type { ILocale, ILocalePartial } from './i18n';
import { defaultLocale } from './i18n';
@ -15,11 +15,12 @@ interface IAppProviderProps {
children: React.ReactNode;
wsPath?: string;
locale?: ILocalePartial;
driver: DriverClient;
dehydratedState?: unknown;
}
export const AppProvider = (props: IAppProviderProps) => {
const { children, wsPath, locale, dehydratedState } = props;
const { children, wsPath, locale, driver, dehydratedState } = props;
const { connected, connection } = useConnection(wsPath);
const themeProps = useTheme();
@ -34,11 +35,11 @@ export const AppProvider = (props: IAppProviderProps) => {
return {
connection,
connected,
driver: getDriver(),
driver,
locale: isObject(locale) ? ({ ...defaultLocale, ...locale } as ILocale) : defaultLocale,
...themeProps,
};
}, [connection, connected, locale, themeProps]);
}, [connection, connected, driver, locale, themeProps]);
return (
<AppContext.Provider value={value}>

View File

@ -5,6 +5,7 @@ import type { FC, ReactNode } from 'react';
import { useContext, useMemo } from 'react';
import { Base } from '../../model';
import { AnchorContext } from '../anchor';
import { AppContext } from '../app';
import { BaseContext } from './BaseContext';
interface IBaseProviderProps {
@ -14,6 +15,7 @@ interface IBaseProviderProps {
export const BaseProvider: FC<IBaseProviderProps> = ({ children, serverData }) => {
const { baseId } = useContext(AnchorContext);
const { driver } = useContext(AppContext);
const { data: baseData, isLoading } = useQuery({
queryKey: ['base', baseId],
queryFn: ({ queryKey }) => (queryKey[1] ? getBaseById(queryKey[1]) : undefined),
@ -21,8 +23,8 @@ export const BaseProvider: FC<IBaseProviderProps> = ({ children, serverData }) =
const value = useMemo(() => {
const base = isLoading ? serverData : baseData?.data;
return { base: base ? new Base(base) : undefined };
}, [isLoading, baseData, serverData]);
return { base: base ? new Base(base, driver) : undefined };
}, [isLoading, serverData, baseData?.data, driver]);
return <BaseContext.Provider value={value}>{children}</BaseContext.Provider>;
};

View File

@ -8,15 +8,6 @@ interface ISessionProviderProps {
user?: IUser;
}
declare global {
interface Window {
__s: {
user?: IUser;
driver: string;
};
}
}
export const SessionProvider: React.FC<React.PropsWithChildren<ISessionProviderProps>> = (
props
) => {
@ -25,9 +16,6 @@ export const SessionProvider: React.FC<React.PropsWithChildren<ISessionProviderP
if (user) {
return user;
}
if (typeof window === 'object') {
return window.__s.user;
}
return undefined;
});

View File

@ -1,21 +1,18 @@
import type { ICreateTableRo, SpaceRole } from '@teable/core';
import type { DriverClient, ICreateTableRo, SpaceRole } from '@teable/core';
import type { IGetBaseVo } from '@teable/openapi';
import knex from 'knex';
import { getDriver } from '../utils/driver';
import { knex, type Knex } from 'knex';
import { Table } from './table/table';
export class Base implements IGetBaseVo {
// eslint-disable-next-line @typescript-eslint/naming-convention
static knex = knex({ client: getDriver() });
id: string;
name: string;
spaceId: string;
order: number;
icon: string | null;
role: SpaceRole;
knex: Knex;
constructor(base: IGetBaseVo) {
constructor(base: IGetBaseVo, driver: DriverClient) {
const { id, name, order, spaceId, icon, role } = base;
this.id = id;
this.name = name;
@ -23,6 +20,7 @@ export class Base implements IGetBaseVo {
this.order = order;
this.icon = icon;
this.role = role;
this.knex = knex({ client: driver });
}
async sqlQuery(tableId: string, viewId: string, sql: string) {

View File

@ -1,8 +0,0 @@
import { DriverClient } from '@teable/core';
export function getDriver(): DriverClient {
if (typeof window === 'object') {
return (window.__s?.driver as DriverClient) || DriverClient.Sqlite;
}
return DriverClient.Sqlite;
}