fix: get app info (#1107)

Reviewed-on: daoyoucloud/tachybase#1107
This commit is contained in:
sealday 2024-06-04 12:03:59 +08:00
parent b01ed166be
commit 5c25f23082
20 changed files with 53 additions and 114 deletions

View File

@ -1,7 +1,6 @@
import React, { createContext, useContext } from 'react';
import { useRequest } from '../api-client';
import { useAppSpin } from '../application/hooks/useAppSpin';
export const CurrentAppInfoContext = createContext(null);
CurrentAppInfoContext.displayName = 'CurrentAppInfoContext';
@ -18,12 +17,11 @@ export const useCurrentAppInfo = () => {
}>(CurrentAppInfoContext);
};
export const CurrentAppInfoProvider = (props) => {
const { render } = useAppSpin();
const result = useRequest({
url: 'app:getInfo',
});
if (result.loading) {
return render();
return;
}
return <CurrentAppInfoContext.Provider value={result.data}>{props.children}</CurrentAppInfoContext.Provider>;
};

View File

@ -1,9 +1,11 @@
import { render, sleep, screen, waitFor } from '@tachybase/test/client';
import React from 'react';
import { render, screen, sleep, waitFor } from '@tachybase/test/client';
import { describe } from 'vitest';
import { Application } from '../Application';
import { useApp, usePlugin, useRouter } from '../hooks';
import { Plugin } from '../Plugin';
import { useApp, usePlugin, useRouter, useAppSpin } from '../hooks';
describe('Application Hooks', () => {
describe('useApp()', () => {
@ -59,37 +61,4 @@ describe('Application Hooks', () => {
await sleep(10);
});
});
describe('useAppSpin()', () => {
test('no app, should render ant-design Spin', async () => {
const Demo = () => {
const spin = useAppSpin();
return spin.render();
};
render(<Demo />);
await waitFor(() => {
expect(document.querySelector('.ant-spin')).toBeTruthy();
});
});
test('has app, should render AppSpin Component', () => {
const Demo = () => {
const spin = useAppSpin();
return spin.render();
};
const app = new Application({
providers: [Demo],
components: {
AppSpin: () => <div data-testid="content">test</div>,
},
});
const Root = app.getRootComponent();
render(<Root></Root>);
expect(document.querySelector('.ant-spin')).toBeFalsy();
expect(screen.getByTestId('content')).toBeTruthy();
});
});
});

View File

@ -1,4 +1,4 @@
import React, { FC } from 'react';
import React from 'react';
import { MainComponent } from './MainComponent';

View File

@ -1,4 +1,3 @@
export * from './useApp';
export * from './usePlugin';
export * from './useRouter';
export * from './useAppSpin';

View File

@ -1,12 +0,0 @@
import React from 'react';
import { Spin } from 'antd';
import { useApp } from './useApp';
export const useAppSpin = () => {
const app = useApp();
return {
render: () => (app?.renderComponent ? app?.renderComponent?.('AppSpin') : React.createElement(Spin)),
};
};

View File

@ -6,7 +6,6 @@ import { Navigate } from 'react-router-dom';
import { useAPIClient, useRequest } from '../../api-client';
import { useApp } from '../../application';
import { useAppSpin } from '../../application/hooks/useAppSpin';
import { useBlockRequestContext } from '../../block-provider/BlockProvider';
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../collection-manager';
import { useResourceActionContext } from '../../collection-manager/ResourceActionProvider';
@ -38,7 +37,6 @@ const getRouteUrl = (props) => {
export const ACLRolesCheckProvider = (props) => {
const route = getRouteUrl(props.children.props);
const { setDesignable } = useDesignable();
const { render } = useAppSpin();
const api = useAPIClient();
const app = useApp();
const result = useRequest<{
@ -68,7 +66,7 @@ export const ACLRolesCheckProvider = (props) => {
},
);
if (result.loading) {
return render();
return;
}
if (result.error) {
return <Navigate replace to={'/signin'} />;

View File

@ -22,7 +22,6 @@ import {
useRequest,
useSystemSettings,
} from '../..';
import { useAppSpin } from '../../application/hooks/useAppSpin';
import { Plugin } from '../../application/Plugin';
import { VariablesProvider } from '../../variables';
@ -202,7 +201,6 @@ const MenuEditor = (props) => {
setCurrent(schema);
navigate(`/admin/${schema['x-uid']}`);
};
const { render } = useAppSpin();
const adminSchemaUid = useAdminSchemaUid();
const { data, loading } = useRequest<{
data: any;
@ -320,7 +318,7 @@ const MenuEditor = (props) => {
);
if (loading) {
return render();
return;
}
return (
<SchemaIdContext.Provider value={defaultSelectedUid}>

View File

@ -36,8 +36,18 @@ interface AppStatusProps {
}
const AppSpin = () => {
// TODO: better loading and mobile loading fix
return (
<Spin style={{ position: 'fixed', top: '50%', left: '50%', fontSize: 72, transform: 'translate(-50%, -50%)' }} />
<Spin
size="large"
style={{
position: 'fixed',
top: '50%',
left: '50%',
fontSize: 72 * (window.devicePixelRatio || 1),
transform: 'translate(-50%, -50%)',
}}
/>
);
};

View File

@ -3,7 +3,6 @@ import React, { createContext, ReactNode, useContext } from 'react';
import { Result } from 'ahooks/es/useRequest/src/types';
import { useRequest } from '../../api-client';
import { useAppSpin } from '../../application/hooks/useAppSpin';
export const SystemSettingsContext = createContext<Result<any, any>>(null);
SystemSettingsContext.displayName = 'SystemSettingsContext';
@ -13,12 +12,11 @@ export const useSystemSettings = () => {
};
export const SystemSettingsProvider: React.FC<{ children?: ReactNode }> = (props) => {
const { render } = useAppSpin();
const result = useRequest({
url: 'systemSettings:get/1?appends=logo',
});
if (result.loading) {
return render();
return;
}
return <SystemSettingsContext.Provider value={result}>{props.children}</SystemSettingsContext.Provider>;

View File

@ -3,7 +3,6 @@ import React, { createContext, useContext, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { useAPIClient, useRequest } from '../api-client';
import { useAppSpin } from '../application/hooks/useAppSpin';
export interface CollectionHistoryContextValue {
historyCollections: any[];
@ -42,7 +41,6 @@ export const CollectionHistoryProvider = (props) => {
const isAdminPage = location.pathname.startsWith('/admin');
const token = api.auth.getToken() || '';
const { render } = useAppSpin();
useEffect(() => {
if (isAdminPage && token) {
@ -58,7 +56,7 @@ export const CollectionHistoryProvider = (props) => {
};
if (service.loading) {
return render();
return;
}
return (

View File

@ -1,12 +1,12 @@
import React from 'react';
import { useAPIClient, useRequest } from '../api-client';
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
import { CollectionCategroriesContext } from './context';
import { CollectionManagerOptions } from './types';
import { CollectionManagerProvider } from '../data-source/collection/CollectionManagerProvider';
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
import { useCollectionHistory } from './CollectionHistoryProvider';
import { useAppSpin } from '../application/hooks/useAppSpin';
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
import { CollectionCategroriesContext } from './context';
import { CollectionManagerOptions } from './types';
/**
* @deprecated use `CollectionManagerProvider` instead
@ -40,9 +40,8 @@ export const RemoteCollectionManagerProvider = (props: any) => {
data: any;
}>(coptions);
const { render } = useAppSpin();
if (service.loading) {
return render();
return;
}
const refreshCategory = async () => {

View File

@ -12,7 +12,6 @@ import { useSearchParams } from 'react-router-dom';
import { FormDialog } from '..';
import { useToken } from '../__builtins__';
import { useAppSpin } from '../../../application/hooks/useAppSpin';
import { useStyles as useAClStyles } from '../../../built-in/acl/style';
import { useDocumentTitle } from '../../../built-in/document-title';
import { FilterBlockProvider } from '../../../filter-provider/FilterProvider';
@ -202,10 +201,9 @@ function PageContent(
props: any,
): React.ReactNode {
const { token } = useToken();
const { render } = useAppSpin();
if (loading) {
return render();
return;
}
return !disablePageHeader && enablePageTabs ? (

View File

@ -3,7 +3,6 @@ import React, { createContext, useContext, useMemo } from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { ReturnTypeOfUseRequest, useRequest } from '../api-client';
import { useAppSpin } from '../application/hooks/useAppSpin';
import { useACLRoleContext } from '../built-in/acl';
import { useCompile } from '../schema-component';
@ -33,13 +32,12 @@ export const useCurrentRoles = () => {
};
export const CurrentUserProvider = (props) => {
const { render } = useAppSpin();
const result = useRequest<any>({
url: 'auth:check',
});
if (result.loading) {
return render();
return;
}
return <CurrentUserContext.Provider value={result}>{props.children}</CurrentUserContext.Provider>;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { useAppSpin, useRequest } from '@tachybase/client';
import { useRequest } from '@tachybase/client';
import { Carousel, Image } from 'antd';
@ -7,7 +7,6 @@ import { useStyles } from './style';
export const HomePage: React.FC<{}> = () => {
const { styles } = useStyles();
const { render } = useAppSpin();
const { data, loading } = useRequest<{ data: any }>({
url: 'home_page_presentations:list',
params: {
@ -16,7 +15,7 @@ export const HomePage: React.FC<{}> = () => {
});
if (loading) {
return render();
return;
}
const date = new Date();
const year = date.getFullYear();

View File

@ -2,11 +2,7 @@ import React from 'react';
import { CurrentAppInfoProvider, SchemaComponentOptions } from '@tachybase/client';
export const DuplicatorProvider = function (props) {
return (
<CurrentAppInfoProvider>
<SchemaComponentOptions>{props.children}</SchemaComponentOptions>
</CurrentAppInfoProvider>
);
return <SchemaComponentOptions>{props.children}</SchemaComponentOptions>;
};
DuplicatorProvider.displayName = 'DuplicatorProvider';

View File

@ -16,16 +16,14 @@ Gantt.Designer = GanttDesigner;
Gantt.Event = Event;
export { Gantt };
const GanttProvider = React.memo((props) => {
const GanttProvider = React.memo((props: { children: React.ReactNode }) => {
return (
<CurrentAppInfoProvider>
<SchemaComponentOptions
components={{ Gantt, GanttBlockInitializer, GanttBlockProvider }}
scope={{ useGanttBlockProps }}
>
{props.children}
</SchemaComponentOptions>
</CurrentAppInfoProvider>
);
});

View File

@ -19,16 +19,14 @@ Kanban.Designer = KanbanDesigner;
const KanbanV2 = Kanban;
const KanbanPluginProvider = React.memo((props) => {
const KanbanPluginProvider = React.memo((props: { children: React.ReactNode }) => {
return (
<CurrentAppInfoProvider>
<SchemaComponentOptions
components={{ Kanban, KanbanBlockProvider, KanbanV2, KanbanBlockInitializer }}
scope={{ useKanbanBlockProps }}
>
{props.children}
</SchemaComponentOptions>
</CurrentAppInfoProvider>
);
});
KanbanPluginProvider.displayName = 'KanbanPluginProvider';

View File

@ -6,7 +6,7 @@ import { MapBlockDesigner } from './MapBlockDesigner';
import { MapBlockInitializer } from './MapBlockInitializer';
import { MapBlockProvider, useMapBlockProps } from './MapBlockProvider';
export const MapBlockOptions: React.FC = (props) => {
export const MapBlockOptions = (props) => {
return (
<SchemaComponentOptions
scope={{ useMapBlockProps }}

View File

@ -9,13 +9,11 @@ import { Configuration, Map } from './components';
import { fields } from './fields';
import { generateNTemplate, NAMESPACE } from './locale';
const MapProvider = React.memo((props) => {
const MapProvider = React.memo((props: { children: React.ReactNode }) => {
return (
<CurrentAppInfoProvider>
<SchemaComponentOptions components={{ Map }}>
<MapBlockOptions>{props.children}</MapBlockOptions>
</SchemaComponentOptions>
</CurrentAppInfoProvider>
);
});
MapProvider.displayName = 'MapProvider';

View File

@ -1,11 +1,10 @@
import React from 'react';
import { css } from '@tachybase/client';
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
import { Input, InputProps, TextArea, TextAreaProps } from 'antd-mobile';
type ComposedInput = React.FC<InputProps> & {
TextArea?: React.FC<TextAreaProps>;
type ComposedInput = ((props: InputProps) => React.ReactNode) & {
TextArea?: (props: TextAreaProps) => React.ReactNode;
};
export const MInput: ComposedInput = connect(
@ -14,7 +13,7 @@ export const MInput: ComposedInput = connect(
return { placeholder: '请输入内容', clearable: true, ...props, style: { '--font-size': '12px' } };
}),
mapReadPretty((props) => {
return <text style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{props.value}</text>;
return <span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{props.value}</span>;
}),
);