feat: support embed page (#786)

Co-authored-by: sealday <sealday@gmail.com>
Reviewed-on: daoyoucloud/tachybase#786
This commit is contained in:
sealday 2024-04-21 03:57:48 +08:00
parent cd9c2e1e8c
commit 4bc1eb5ac2
8 changed files with 135 additions and 0 deletions

View File

@ -0,0 +1,30 @@
import { css } from '@nocobase/client';
import { Layout } from 'antd';
import React from 'react';
import { Outlet } from 'react-router-dom';
export const EmbedLayout = () => (
<Layout style={{ height: '100%' }}>
<Layout.Content
className={css`
display: flex;
flex-direction: column;
position: relative;
overflow-y: auto;
> div {
position: relative;
}
.ant-layout-footer {
position: absolute;
bottom: 0;
text-align: center;
width: 100%;
z-index: 0;
padding: 0px 50px;
}
`}
>
<Outlet />
</Layout.Content>
</Layout>
);

View File

@ -0,0 +1,33 @@
import { AdminProvider } from '@nocobase/client';
import React, { useEffect } from 'react';
import { useLocation, useMatch, useNavigate } from 'react-router-dom';
import { NotAuthorityResult } from './NotAuthorityResult';
import { EmbedLayout } from './EmbedLayout';
import { useEmbedToken } from './useEmbedToken';
export const EmbedPage = () => {
const embedToken = useEmbedToken();
const navigate = useNavigate();
const location = useLocation();
const match = useMatch('/embed/:name');
// FIXME
useEffect(
() => () => {
setTimeout(() => {
match &&
setTimeout(() => {
window.location.pathname !== location.pathname && navigate('/embed/not-authorized');
});
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
return !embedToken || location.pathname === '/embed/not-authorized' ? (
<NotAuthorityResult />
) : (
<AdminProvider>
<EmbedLayout />
</AdminProvider>
);
};

View File

@ -0,0 +1,8 @@
import { RemoteSchemaComponent } from '@nocobase/client';
import React from 'react';
import { useParams } from 'react-router-dom';
export function EmbedSchemaComponent() {
const params = useParams();
return <RemoteSchemaComponent uid={params.name} />;
}

View File

@ -0,0 +1,6 @@
import { Result } from 'antd';
import React from 'react';
export function NotAuthorityResult() {
return <Result status="403" title="403" subTitle="Sorry, you are not authorized to access this page." />;
}

View File

@ -0,0 +1,18 @@
import { Plugin } from '@nocobase/client';
import { usePageSettingsProps } from './usePageSettingsProps';
import { EmbedSchemaComponent } from './EmbedSchemaComponent';
import { EmbedPage } from './EmbedPage';
const keyEmbed = 'embed';
const pathEmbed = `/${keyEmbed}`;
export class EmbedPlugin extends Plugin {
async load() {
this.router.add(keyEmbed, { path: pathEmbed, Component: EmbedPage });
this.router.add(`${keyEmbed}.page`, { path: `${pathEmbed}/:name`, Component: EmbedSchemaComponent });
this.router.add(`${keyEmbed}.notAuthorized`, { path: `${pathEmbed}/not-authorized`, element: null });
this.schemaSettingsManager.addItem('PageSettings', keyEmbed, {
type: 'item',
useComponentProps: usePageSettingsProps,
});
}
}

View File

@ -0,0 +1,8 @@
import { useAPIClient } from '@nocobase/client';
export function useEmbedToken() {
const url = new URL(window.location.href);
const api = useAPIClient();
const token = url.searchParams.get('token');
return token && api.auth.setToken(token), api.auth.getToken();
}

View File

@ -0,0 +1,30 @@
import { useFieldSchema } from '@nocobase/schema';
import { App } from 'antd';
import { useMatch } from 'react-router-dom';
import { useTranslation } from '../locale';
export function usePageSettingsProps() {
const isAdmin = useMatch('/admin/:name');
const isEmbed = useMatch('/embed/:name');
const currentRoute = isAdmin || isEmbed;
const fieldSchema = useFieldSchema();
const { message, notification } = App.useApp();
const { t } = useTranslation();
return {
title: t('Copy embedded link'),
onClick: () => {
const link = window.location.href
.replace('/admin', '/embed')
.replace(currentRoute.params.name, fieldSchema['x-uid'])
.replace(window.location.search || '', '');
navigator.clipboard
.writeText(link)
.then(() => {
message.success(t('Copy successful'));
})
.catch((error) => {
notification.error({ message: t('Copy Failed'), description: error.message, placement: 'topRight' });
});
},
};
}

View File

@ -74,6 +74,7 @@ import {
useCustomPresets1, useCustomPresets1,
} from './schema-settings/SchemaSettingsDatePresets'; } from './schema-settings/SchemaSettingsDatePresets';
import { SchemaSettingsSubmitDataType } from './schema-settings/SchemaSettingsSubmitDataType'; import { SchemaSettingsSubmitDataType } from './schema-settings/SchemaSettingsSubmitDataType';
import { EmbedPlugin } from './embed';
export { usePDFViewerRef } from './schema-initializer'; export { usePDFViewerRef } from './schema-initializer';
export * from './components/custom-components/custom-components'; export * from './components/custom-components/custom-components';
@ -82,6 +83,7 @@ export class PluginCoreClient extends Plugin {
async afterAdd() { async afterAdd() {
await this.app.pm.add(GroupBlockPlugin); await this.app.pm.add(GroupBlockPlugin);
await this.app.pm.add(EmbedPlugin);
} }
async registerSettings() { async registerSettings() {