mirror of
https://github.com/teableio/teable
synced 2024-11-21 14:51:09 +00:00
feat: inject dynamic env to next (#392)
* fix: auto disable template entry * feat: inject dynamic env to next
This commit is contained in:
parent
b6e533b9fa
commit
ed056d63ce
@ -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
|
||||
|
||||
# ↓↓↓↓↓↓↓↓ backend(nestjs) 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
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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';
|
||||
|
@ -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}");
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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 = () => {
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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';
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
6
apps/nextjs-app/src/features/app/hooks/useEnv.ts
Normal file
6
apps/nextjs-app/src/features/app/hooks/useEnv.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
import { EnvContext } from '@/lib/server-env';
|
||||
|
||||
export function useEnv() {
|
||||
return useContext(EnvContext);
|
||||
}
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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">
|
||||
|
@ -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;
|
9
apps/nextjs-app/src/lib/server-env.ts
Normal file
9
apps/nextjs-app/src/lib/server-env.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface IServerEnv {
|
||||
helpSiteLink?: string;
|
||||
templateSiteLink?: string;
|
||||
microsoftClarityId?: string;
|
||||
}
|
||||
|
||||
export const EnvContext = React.createContext<IServerEnv>({});
|
@ -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;
|
||||
|
@ -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} />;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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}>
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user