Revert "Revert "fix: add displayName (#3628)""

This reverts commit 58e2fd6ea6.
This commit is contained in:
sealday 2024-03-10 03:06:57 +08:00
parent fbe0c14920
commit 350c0ac1f4
135 changed files with 1089 additions and 868 deletions

View File

@ -14,6 +14,7 @@ import { useApp } from '../application';
import { useDataSourceKey } from '../data-source/data-source/DataSourceProvider'; import { useDataSourceKey } from '../data-source/data-source/DataSourceProvider';
export const ACLContext = createContext<any>({}); export const ACLContext = createContext<any>({});
ACLContext.displayName = 'ACLContext';
// TODO: delete thisreplace by `ACLPlugin` // TODO: delete thisreplace by `ACLPlugin`
export const ACLProvider = (props) => { export const ACLProvider = (props) => {
@ -90,6 +91,7 @@ export const useACLContext = () => {
}; };
export const ACLActionParamsContext = createContext<any>({}); export const ACLActionParamsContext = createContext<any>({});
ACLActionParamsContext.displayName = 'ACLActionParamsContext';
export const useACLRolesCheck = () => { export const useACLRolesCheck = () => {
const ctx = useContext(ACLContext); const ctx = useContext(ACLContext);

View File

@ -31,6 +31,7 @@ const getChildrenKeys = (data = [], arr = []) => {
}; };
const SettingMenuContext = createContext(null); const SettingMenuContext = createContext(null);
SettingMenuContext.displayName = 'SettingMenuContext';
export const SettingCenterProvider = (props) => { export const SettingCenterProvider = (props) => {
const configureItems = useContext(SettingsCenterContext); const configureItems = useContext(SettingsCenterContext);

View File

@ -4,6 +4,7 @@ import { useRequest } from '../../api-client';
import { useAdminSchemaUid } from '../../hooks'; import { useAdminSchemaUid } from '../../hooks';
const MenuItemsContext = createContext(null); const MenuItemsContext = createContext(null);
MenuItemsContext.displayName = 'MenuItemsContext';
export const toItems = (properties = {}) => { export const toItems = (properties = {}) => {
const items = []; const items = [];

View File

@ -14,6 +14,7 @@ export const SettingCenterPermissionProvider = (props) => {
}; };
export const PermissionContext = createContext<any>(null); export const PermissionContext = createContext<any>(null);
PermissionContext.displayName = 'PermissionContext';
export const PermissionProvider = (props) => { export const PermissionProvider = (props) => {
const api = useAPIClient(); const api = useAPIClient();

View File

@ -7,6 +7,7 @@ import { PermissionProvider, SettingCenterPermissionProvider } from '../Configur
import { roleSchema } from './schemas/roles'; import { roleSchema } from './schemas/roles';
const AvailableActionsContext = createContext([]); const AvailableActionsContext = createContext([]);
AvailableActionsContext.displayName = 'AvailableActionsContext';
const AvailableActionsProver: React.FC = (props) => { const AvailableActionsProver: React.FC = (props) => {
const { data, loading } = useRequest<{ const { data, loading } = useRequest<{

View File

@ -22,6 +22,7 @@ const toActionMap = (arr: any[]) => {
}; };
export const RoleResourceCollectionContext = createContext<any>({}); export const RoleResourceCollectionContext = createContext<any>({});
RoleResourceCollectionContext.displayName = 'RoleResourceCollectionContext';
export const RolesResourcesActions = connect((props) => { export const RolesResourcesActions = connect((props) => {
const { styles } = useStyles(); const { styles } = useStyles();

View File

@ -4,6 +4,7 @@ import { FormProvider, SchemaComponent } from '../../schema-component';
import { scopesSchema } from './schemas/scopes'; import { scopesSchema } from './schemas/scopes';
const RolesResourcesScopesSelectedRowKeysContext = createContext(null); const RolesResourcesScopesSelectedRowKeysContext = createContext(null);
RolesResourcesScopesSelectedRowKeysContext.displayName = 'RolesResourcesScopesSelectedRowKeysContext';
const RolesResourcesScopesSelectedRowKeysProvider: React.FC = (props) => { const RolesResourcesScopesSelectedRowKeysProvider: React.FC = (props) => {
const [keys, setKeys] = useState([]); const [keys, setKeys] = useState([]);

View File

@ -7,6 +7,7 @@ import { Plugin } from '../application/Plugin';
import { loadConstrueLocale } from './loadConstrueLocale'; import { loadConstrueLocale } from './loadConstrueLocale';
export const AppLangContext = createContext<any>({}); export const AppLangContext = createContext<any>({});
AppLangContext.displayName = 'AppLangContext';
export const useAppLangContext = () => { export const useAppLangContext = () => {
return useContext(AppLangContext); return useContext(AppLangContext);

View File

@ -2,3 +2,4 @@ import { createContext } from 'react';
import { APIClient } from './APIClient'; import { APIClient } from './APIClient';
export const APIClientContext = createContext<APIClient>(new APIClient()); export const APIClientContext = createContext<APIClient>(new APIClient());
APIClientContext.displayName = 'APIClientContext';

View File

@ -3,6 +3,7 @@ import { useRequest } from '../api-client';
import { useAppSpin } from '../application/hooks/useAppSpin'; import { useAppSpin } from '../application/hooks/useAppSpin';
export const CurrentAppInfoContext = createContext(null); export const CurrentAppInfoContext = createContext(null);
CurrentAppInfoContext.displayName = 'CurrentAppInfoContext';
export const useCurrentAppInfo = () => { export const useCurrentAppInfo = () => {
return useContext<{ return useContext<{

View File

@ -45,6 +45,7 @@ export class PluginSettingsManager {
protected settings: Record<string, PluginSettingOptions> = {}; protected settings: Record<string, PluginSettingOptions> = {};
protected aclSnippets: string[] = []; protected aclSnippets: string[] = [];
public app: Application; public app: Application;
private cachedList = {};
constructor(_pluginSettings: Record<string, PluginSettingOptions>, app: Application) { constructor(_pluginSettings: Record<string, PluginSettingOptions>, app: Application) {
this.app = app; this.app = app;
@ -141,11 +142,16 @@ export class PluginSettingsManager {
} }
getList(filterAuth = true): PluginSettingsPageType[] { getList(filterAuth = true): PluginSettingsPageType[] {
return Array.from(new Set(Object.values(this.settings).map((item) => item.topLevelName))) const cacheKey = JSON.stringify(filterAuth);
if (this.cachedList[cacheKey]) return this.cachedList[cacheKey];
return (this.cachedList[cacheKey] = Array.from(
new Set(Object.values(this.settings).map((item) => item.topLevelName)),
)
.sort((a, b) => a.localeCompare(b)) // sort by name .sort((a, b) => a.localeCompare(b)) // sort by name
.map((name) => this.get(name, filterAuth)) .map((name) => this.get(name, filterAuth))
.filter(Boolean) .filter(Boolean)
.sort((a, b) => (a.sort || 0) - (b.sort || 0)); .sort((a, b) => (a.sort || 0) - (b.sort || 0)));
} }
getAclSnippets() { getAclSnippets() {

View File

@ -8,32 +8,35 @@ export interface AppComponentProps {
app: Application; app: Application;
} }
export const AppComponent: FC<AppComponentProps> = observer((props) => { export const AppComponent: FC<AppComponentProps> = observer(
const { app } = props; (props) => {
const handleErrors = useCallback((error: Error, info: { componentStack: string }) => { const { app } = props;
console.error(error); const handleErrors = useCallback((error: Error, info: { componentStack: string }) => {
const err = new Error(); console.error(error);
err.stack = info.componentStack.trim(); const err = new Error();
console.error(err); err.stack = info.componentStack.trim();
}, []); console.error(err);
useEffect(() => { }, []);
app.load(); useEffect(() => {
}, [app]); app.load();
const AppError = app.getComponent('AppError'); }, [app]);
if (app.loading) return app.renderComponent('AppSpin', { app }); const AppError = app.getComponent('AppError');
if (!app.maintained && app.maintaining) return app.renderComponent('AppMaintaining', { app }); if (app.loading) return app.renderComponent('AppSpin', { app });
if (app.error?.code === 'LOAD_ERROR' || app.error?.code === 'APP_ERROR') { if (!app.maintained && app.maintaining) return app.renderComponent('AppMaintaining', { app });
return <AppError app={app} error={app.error} />; if (app.error?.code === 'LOAD_ERROR' || app.error?.code === 'APP_ERROR') {
} return <AppError app={app} error={app.error} />;
return ( }
<ErrorBoundary return (
FallbackComponent={(props) => <AppError app={app} error={app.error} {...props} />} <ErrorBoundary
onError={handleErrors} FallbackComponent={(props) => <AppError app={app} error={app.error} {...props} />}
> onError={handleErrors}
<ApplicationContext.Provider value={app}> >
{app.maintained && app.maintaining && app.renderComponent('AppMaintainingDialog', { app })} <ApplicationContext.Provider value={app}>
{app.renderComponent('AppMain')} {app.maintained && app.maintaining && app.renderComponent('AppMaintainingDialog', { app })}
</ApplicationContext.Provider> {app.renderComponent('AppMain')}
</ErrorBoundary> </ApplicationContext.Provider>
); </ErrorBoundary>
}); );
},
{ displayName: 'AppComponent' },
);

View File

@ -2,3 +2,4 @@ import { createContext } from 'react';
import { Application } from './Application'; import { Application } from './Application';
export const ApplicationContext = createContext<Application>(null); export const ApplicationContext = createContext<Application>(null);
ApplicationContext.displayName = 'ApplicationContext';

View File

@ -13,113 +13,114 @@ import { SchemaInitializerOptions } from '../types';
const defaultWrap = (s: ISchema) => s; const defaultWrap = (s: ISchema) => s;
export function withInitializer<T>(C: ComponentType<T>) { export function withInitializer<T>(C: ComponentType<T>) {
const WithInitializer = observer((props: SchemaInitializerOptions<T>) => { const WithInitializer = observer(
const { designable, insertAdjacent } = useDesignable(); (props: SchemaInitializerOptions<T>) => {
const { isInSubTable } = useFlag() || {}; const { designable, insertAdjacent } = useDesignable();
const { const { isInSubTable } = useFlag() || {};
insert, const {
useInsert, insert,
wrap = defaultWrap, useInsert,
insertPosition = 'beforeEnd', wrap = defaultWrap,
onSuccess, insertPosition = 'beforeEnd',
designable: propsDesignable, onSuccess,
popoverProps, designable: propsDesignable,
children, popoverProps,
popover = true, children,
style, popover = true,
componentProps,
} = props;
// 插入 schema 的能力
const insertCallback = useInsert ? useInsert() : insert;
const insertSchema = useCallback(
(schema) => {
if (insertCallback) {
insertCallback(wrap(schema, { isInSubTable }));
} else {
insertAdjacent(insertPosition, wrap(schema, { isInSubTable }), { onSuccess });
}
},
[insertCallback, wrap, insertAdjacent, insertPosition, onSuccess],
);
const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
const [visible, setVisible] = useState(false);
const { token } = theme.useToken();
const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
const cProps = useMemo(
() => ({
options: props,
style, style,
...componentProps, componentProps,
}), } = props;
[componentProps, props, style],
);
// designable 为 false 时,不渲染 // 插入 schema 的能力
if (!designable && propsDesignable !== true) { const insertCallback = useInsert ? useInsert() : insert;
return null; const insertSchema = useCallback(
} (schema) => {
if (insertCallback) {
insertCallback(wrap(schema, { isInSubTable }));
} else {
insertAdjacent(insertPosition, wrap(schema, { isInSubTable }), { onSuccess });
}
},
[insertCallback, wrap, insertAdjacent, insertPosition, onSuccess],
);
return ( const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
<SchemaInitializerContext.Provider const [visible, setVisible] = useState(false);
value={{ const { token } = theme.useToken();
visible, const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
setVisible,
insert: insertSchema, const cProps = useMemo(
() => ({
options: props, options: props,
}} style,
> ...componentProps,
{popover === false ? ( }),
React.createElement(C, cProps) [componentProps, props, style],
) : ( );
<Popover
placement={'bottomLeft'} // designable 为 false 时,不渲染
{...popoverProps} if (!designable && propsDesignable !== true) {
arrow={false} return null;
overlayClassName={css` }
.ant-popover-inner {
padding: ${`${token.paddingXXS}px 0`}; return (
.ant-menu-submenu-title { <SchemaInitializerContext.Provider
margin-block: 0; value={{
visible,
setVisible,
insert: insertSchema,
options: props,
}}
>
{popover === false ? (
React.createElement(C, cProps)
) : (
<Popover
placement={'bottomLeft'}
{...popoverProps}
arrow={false}
overlayClassName={css`
.ant-popover-inner {
padding: ${`${token.paddingXXS}px 0`};
.ant-menu-submenu-title {
margin-block: 0;
}
} }
} `}
`} open={visible}
open={visible} onOpenChange={setVisible}
onOpenChange={setVisible} content={wrapSSR(
content={wrapSSR( <div
<div className={`${componentCls} ${hashId}`}
className={`${componentCls} ${hashId}`} style={{
style={{ maxHeight: dropdownMaxHeight,
maxHeight: dropdownMaxHeight, overflowY: 'auto',
overflowY: 'auto',
}}
>
<ConfigProvider
theme={{
components: {
Menu: {
itemHeight: token.marginXL,
borderRadius: token.borderRadiusSM,
itemBorderRadius: token.borderRadiusSM,
subMenuItemBorderRadius: token.borderRadiusSM,
},
},
}} }}
> >
{children} <ConfigProvider
</ConfigProvider> theme={{
</div>, components: {
)} Menu: {
> itemHeight: token.marginXL,
{React.createElement(C, cProps)} borderRadius: token.borderRadiusSM,
</Popover> itemBorderRadius: token.borderRadiusSM,
)} subMenuItemBorderRadius: token.borderRadiusSM,
</SchemaInitializerContext.Provider> },
); },
}); }}
>
WithInitializer.displayName = `WithInitializer(${C.displayName || C.name})`; {children}
</ConfigProvider>
</div>,
)}
>
{React.createElement(C, cProps)}
</Popover>
)}
</SchemaInitializerContext.Provider>
);
},
{ displayName: `WithInitializer(${C.displayName || C.name})` },
);
return WithInitializer; return WithInitializer;
} }

View File

@ -11,7 +11,7 @@ export * from './useAriaAttributeOfMenuItem';
export function useSchemaInitializerMenuItems(items: any[], name?: string, onClick?: (args: any) => void) { export function useSchemaInitializerMenuItems(items: any[], name?: string, onClick?: (args: any) => void) {
const getMenuItems = useGetSchemaInitializerMenuItems(onClick); const getMenuItems = useGetSchemaInitializerMenuItems(onClick);
return getMenuItems(items, name); return useMemo(() => getMenuItems(items, name), [getMenuItems, items, name]);
} }
export function useGetSchemaInitializerMenuItems(onClick?: (args: any) => void) { export function useGetSchemaInitializerMenuItems(onClick?: (args: any) => void) {

View File

@ -13,3 +13,4 @@ export const SchemaSettingsIcon: FC<SchemaSettingOptions> = React.memo((props) =
const style = useMemo(() => ({ cursor: 'pointer', fontSize: 12 }), []); const style = useMemo(() => ({ cursor: 'pointer', fontSize: 12 }), []);
return <MenuOutlined role="button" style={style} aria-label={getAriaLabel('schema-settings', name)} />; return <MenuOutlined role="button" style={style} aria-label={getAriaLabel('schema-settings', name)} />;
}); });
SchemaSettingsIcon.displayName = 'SchemaSettingsIcon';

View File

@ -3,6 +3,7 @@ import React, { createContext, useContext } from 'react';
import { useRequest } from '../api-client'; import { useRequest } from '../api-client';
export const AsyncDataContext = createContext<Result<any, any> & { state?: any; setState?: any }>(null); export const AsyncDataContext = createContext<Result<any, any> & { state?: any; setState?: any }>(null);
AsyncDataContext.displayName = 'AsyncDataContext';
export interface AsyncDataProviderProps { export interface AsyncDataProviderProps {
value?: any; value?: any;

View File

@ -35,7 +35,9 @@ import { useDataBlockSourceId } from './hooks/useDataBlockSourceId';
* @deprecated * @deprecated
*/ */
export const BlockResourceContext = createContext(null); export const BlockResourceContext = createContext(null);
BlockResourceContext.displayName = 'BlockResourceContext';
export const BlockAssociationContext = createContext(null); export const BlockAssociationContext = createContext(null);
BlockAssociationContext.displayName = 'BlockAssociationContext';
/** /**
* @deprecated * @deprecated
@ -50,6 +52,7 @@ export const BlockRequestContext_deprecated = createContext<{
__parent?: any; __parent?: any;
updateAssociationValues?: any[]; updateAssociationValues?: any[];
}>({}); }>({});
BlockRequestContext_deprecated.displayName = 'BlockRequestContext_deprecated';
export const useBlockResource = () => { export const useBlockResource = () => {
const resource = useDataBlockResource(); const resource = useDataBlockResource();
@ -209,6 +212,7 @@ const BlockContext = createContext<{
/** 用以区分区块的标识 */ /** 用以区分区块的标识 */
name: string; name: string;
}>(null); }>(null);
BlockContext.displayName = 'BlockContext';
export const useBlockContext = () => { export const useBlockContext = () => {
return useContext(BlockContext); return useContext(BlockContext);

View File

@ -9,6 +9,7 @@ import { BlockProvider, useBlockRequestContext } from './BlockProvider';
import { useParsedFilter } from './hooks'; import { useParsedFilter } from './hooks';
export const DetailsBlockContext = createContext<any>({}); export const DetailsBlockContext = createContext<any>({});
DetailsBlockContext.displayName = 'DetailsBlockContext';
const InternalDetailsBlockProvider = (props) => { const InternalDetailsBlockProvider = (props) => {
const { action, readPretty } = props; const { action, readPretty } = props;

View File

@ -12,6 +12,7 @@ import { TemplateBlockProvider } from './TemplateBlockProvider';
import { FormActiveFieldsProvider } from './hooks/useFormActiveFields'; import { FormActiveFieldsProvider } from './hooks/useFormActiveFields';
export const FormBlockContext = createContext<any>({}); export const FormBlockContext = createContext<any>({});
FormBlockContext.displayName = 'FormBlockContext';
const InternalFormBlockProvider = (props) => { const InternalFormBlockProvider = (props) => {
const ctx = useFormBlockContext(); const ctx = useFormBlockContext();

View File

@ -10,6 +10,7 @@ import { BlockProvider, useBlockRequestContext } from './BlockProvider';
import { useFormBlockContext } from './FormBlockProvider'; import { useFormBlockContext } from './FormBlockProvider';
export const FormFieldContext = createContext<any>({}); export const FormFieldContext = createContext<any>({});
FormFieldContext.displayName = 'FormFieldContext';
const InternalFormFieldProvider = (props) => { const InternalFormFieldProvider = (props) => {
const { action, readPretty, fieldName } = props; const { action, readPretty, fieldName } = props;
@ -75,6 +76,7 @@ const InternalFormFieldProvider = (props) => {
}; };
export const WithoutFormFieldResource = createContext(null); export const WithoutFormFieldResource = createContext(null);
WithoutFormFieldResource.displayName = 'WithoutFormFieldResource';
export const FormFieldProvider = (props) => { export const FormFieldProvider = (props) => {
return ( return (

View File

@ -9,6 +9,8 @@ import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestCont
import { findFilterTargets, useParsedFilter } from './hooks'; import { findFilterTargets, useParsedFilter } from './hooks';
export const TableBlockContext = createContext<any>({}); export const TableBlockContext = createContext<any>({});
TableBlockContext.displayName = 'TableBlockContext';
export function getIdsWithChildren(nodes) { export function getIdsWithChildren(nodes) {
const ids = []; const ids = [];
if (nodes) { if (nodes) {

View File

@ -7,6 +7,7 @@ import { useFormBlockContext } from './FormBlockProvider';
import { useFormFieldContext } from './FormFieldProvider'; import { useFormFieldContext } from './FormFieldProvider';
export const TableFieldContext = createContext<any>({}); export const TableFieldContext = createContext<any>({});
TableFieldContext.displayName = 'TableFieldContext';
const InternalTableFieldProvider = (props) => { const InternalTableFieldProvider = (props) => {
const { params = {}, showIndex, dragSort, fieldName } = props; const { params = {}, showIndex, dragSort, fieldName } = props;
@ -122,6 +123,7 @@ export class TableFieldResource {
} }
export const WithoutTableFieldResource = createContext(null); export const WithoutTableFieldResource = createContext(null);
WithoutTableFieldResource.displayName = 'WithoutTableFieldResource';
export const TableFieldProvider = (props) => { export const TableFieldProvider = (props) => {
return ( return (

View File

@ -20,7 +20,9 @@ type Params = {
}; };
export const TableSelectorContext = createContext<any>({}); export const TableSelectorContext = createContext<any>({});
TableSelectorContext.displayName = 'TableSelectorContext';
const TableSelectorParamsContext = createContext<Params>({}); // 用于传递参数 const TableSelectorParamsContext = createContext<Params>({}); // 用于传递参数
TableSelectorParamsContext.displayName = 'TableSelectorParamsContext';
type TableSelectorProviderProps = { type TableSelectorProviderProps = {
params: Record<string, any>; params: Record<string, any>;

View File

@ -5,6 +5,7 @@ const TemplateBlockContext = createContext<{
templateFinshed?: boolean; templateFinshed?: boolean;
onTemplateSuccess?: Function; onTemplateSuccess?: Function;
}>({}); }>({});
TemplateBlockContext.displayName = 'TemplateBlockContext';
export const useTemplateBlockContext = () => { export const useTemplateBlockContext = () => {
return useContext(TemplateBlockContext); return useContext(TemplateBlockContext);

View File

@ -12,6 +12,7 @@ const CollectionHistoryContext = createContext<CollectionHistoryContextValue>({
historyCollections: [], historyCollections: [],
refreshCH: () => undefined, refreshCH: () => undefined,
}); });
CollectionHistoryContext.displayName = 'CollectionHistoryContext';
export const CollectionHistoryProvider: React.FC = (props) => { export const CollectionHistoryProvider: React.FC = (props) => {
const api = useAPIClient(); const api = useAPIClient();

View File

@ -51,6 +51,4 @@ const Summary = observer(
{ displayName: 'Summary' }, { displayName: 'Summary' },
); );
Summary.displayName = 'Summary';
export default Summary; export default Summary;

View File

@ -8,6 +8,7 @@ import { useAPIClient, useRequest } from '../api-client';
export const ResourceActionContext = createContext< export const ResourceActionContext = createContext<
Result<any, any> & { state?: any; setState?: any; dragSort?: boolean; defaultRequest?: any } Result<any, any> & { state?: any; setState?: any; dragSort?: boolean; defaultRequest?: any }
>(null); >(null);
ResourceActionContext.displayName = 'ResourceActionContext';
interface ResourceActionProviderProps { interface ResourceActionProviderProps {
type?: 'association' | 'collection'; type?: 'association' | 'collection';
@ -18,6 +19,7 @@ interface ResourceActionProviderProps {
} }
const ResourceContext = createContext<any>(null); const ResourceContext = createContext<any>(null);
ResourceContext.displayName = 'ResourceContext';
const CollectionResourceActionProvider = (props) => { const CollectionResourceActionProvider = (props) => {
const { collection, request, uid, dragSort } = props; const { collection, request, uid, dragSort } = props;

View File

@ -1,3 +1,4 @@
import { createContext } from 'react'; import { createContext } from 'react';
export const CollectionCategroriesContext = createContext({ data: [], refresh: () => {} }); export const CollectionCategroriesContext = createContext({ data: [], refresh: () => {} });
CollectionCategroriesContext.displayName = 'CollectionCategroriesContext';

View File

@ -69,6 +69,7 @@ const collection: CollectionOptions = {
}; };
export const DataSourceContext_deprecated = createContext(null); export const DataSourceContext_deprecated = createContext(null);
DataSourceContext_deprecated.displayName = 'DataSourceContext_deprecated';
const useSelectedRowKeys = () => { const useSelectedRowKeys = () => {
const ctx = useContext(DataSourceContext_deprecated); const ctx = useContext(DataSourceContext_deprecated);

View File

@ -100,115 +100,118 @@ const getDefaultCollectionFields = (presetFields, values) => {
// 其他 // 其他
return defaults; return defaults;
}; };
export const PresetFields = observer((props: any) => { export const PresetFields = observer(
const { getInterface } = useCollectionManager_deprecated(); (props: any) => {
const form = useForm(); const { getInterface } = useCollectionManager_deprecated();
const compile = useCompile(); const form = useForm();
const [selectedRowKeys, setSelectedRowKeys] = useState([]); const compile = useCompile();
const { t } = useTranslation(); const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const column = [ const { t } = useTranslation();
{ const column = [
title: t('Field'), {
dataIndex: 'field', title: t('Field'),
key: 'field', dataIndex: 'field',
}, key: 'field',
{ },
title: t('Interface'), {
dataIndex: 'interface', title: t('Interface'),
key: 'interface', dataIndex: 'interface',
render: (value) => <Tag>{compile(getInterface(value)?.title)}</Tag>, key: 'interface',
}, render: (value) => <Tag>{compile(getInterface(value)?.title)}</Tag>,
{ },
title: t('Description'), {
dataIndex: 'description', title: t('Description'),
key: 'description', dataIndex: 'description',
}, key: 'description',
]; },
const dataSource = [ ];
{ const dataSource = [
field: t('ID'), {
interface: 'integer', field: t('ID'),
description: t('Primary key, unique identifier, self growth'), interface: 'integer',
name: 'id', description: t('Primary key, unique identifier, self growth'),
}, name: 'id',
{ },
field: t('Created at'), {
interface: 'createdAt', field: t('Created at'),
description: t('Store the creation time of each record'), interface: 'createdAt',
name: 'createdAt', description: t('Store the creation time of each record'),
}, name: 'createdAt',
{ },
field: t('Last updated at'), {
interface: 'updatedAt', field: t('Last updated at'),
description: t('Store the last update time of each record'), interface: 'updatedAt',
name: 'updatedAt', description: t('Store the last update time of each record'),
}, name: 'updatedAt',
{ },
field: t('Created by'), {
interface: 'createdBy', field: t('Created by'),
description: t('Store the creation user of each record'), interface: 'createdBy',
name: 'createdBy', description: t('Store the creation user of each record'),
}, name: 'createdBy',
},
{ {
field: t('Last updated by'), field: t('Last updated by'),
interface: 'updatedBy', interface: 'updatedBy',
description: t('Store the last update user of each record'), description: t('Store the last update user of each record'),
name: 'updatedBy', name: 'updatedBy',
}, },
]; ];
useEffect(() => { useEffect(() => {
const config = { const config = {
autoGenId: true, autoGenId: true,
createdAt: true, createdAt: true,
createdBy: true, createdBy: true,
updatedAt: true, updatedAt: true,
updatedBy: true, updatedBy: true,
}; };
const initialValue = ['id', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy']; const initialValue = ['id', 'createdAt', 'createdBy', 'updatedAt', 'updatedBy'];
setSelectedRowKeys(initialValue); setSelectedRowKeys(initialValue);
form.setValues({ ...form.values, ...config }); form.setValues({ ...form.values, ...config });
}, []); }, []);
useEffect(() => { useEffect(() => {
const fields = getDefaultCollectionFields( const fields = getDefaultCollectionFields(
selectedRowKeys.map((v) => { selectedRowKeys.map((v) => {
return { return {
name: v, name: v,
};
}),
form.values,
);
form.setValuesIn('fields', fields);
}, [selectedRowKeys]);
return (
<Table
size="small"
pagination={false}
rowKey="name"
bordered
scroll={{ x: 600 }}
dataSource={dataSource}
columns={column}
rowSelection={{
type: 'checkbox',
selectedRowKeys,
onChange: (_, selectedRows) => {
const fields = getDefaultCollectionFields(selectedRows, form.values);
const config = {
autoGenId: !!fields.find((v) => v.name === 'id'),
createdAt: !!fields.find((v) => v.name === 'createdAt'),
createdBy: !!fields.find((v) => v.name === 'createdBy'),
updatedAt: !!fields.find((v) => v.name === 'updatedAt'),
updatedBy: !!fields.find((v) => v.name === 'updatedBy'),
}; };
setSelectedRowKeys( }),
fields?.map?.((v) => { form.values,
return v.name; );
}), form.setValuesIn('fields', fields);
); }, [selectedRowKeys]);
form.setValues({ ...form.values, fields, ...config }); return (
}, <Table
}} size="small"
/> pagination={false}
); rowKey="name"
}); bordered
scroll={{ x: 600 }}
dataSource={dataSource}
columns={column}
rowSelection={{
type: 'checkbox',
selectedRowKeys,
onChange: (_, selectedRows) => {
const fields = getDefaultCollectionFields(selectedRows, form.values);
const config = {
autoGenId: !!fields.find((v) => v.name === 'id'),
createdAt: !!fields.find((v) => v.name === 'createdAt'),
createdBy: !!fields.find((v) => v.name === 'createdBy'),
updatedAt: !!fields.find((v) => v.name === 'updatedAt'),
updatedBy: !!fields.find((v) => v.name === 'updatedBy'),
};
setSelectedRowKeys(
fields?.map?.((v) => {
return v.name;
}),
);
form.setValues({ ...form.values, fields, ...config });
},
}}
/>
);
},
{ displayName: 'PresetFields' },
);

View File

@ -73,222 +73,225 @@ const useSourceFieldsOptions = () => {
return data; return data;
}; };
export const FieldsConfigure = observer(() => { export const FieldsConfigure = observer(
const { t } = useTranslation(); () => {
const [dataSource, setDataSource] = useState([]); const { t } = useTranslation();
const { data: res, error, loading } = useAsyncData(); const [dataSource, setDataSource] = useState([]);
const { data, fields: sourceFields } = res || {}; const { data: res, error, loading } = useAsyncData();
const field: ArrayField = useField(); const { data, fields: sourceFields } = res || {};
const { data: curFields } = useContext(ResourceActionContext); const field: ArrayField = useField();
const compile = useCompile(); const { data: curFields } = useContext(ResourceActionContext);
const { getInterface, getCollectionField } = useCollectionManager_deprecated(); const compile = useCompile();
const options = useFieldInterfaceOptions(); const { getInterface, getCollectionField } = useCollectionManager_deprecated();
const options = useFieldInterfaceOptions();
const interfaceOptions = useMemo( const interfaceOptions = useMemo(
() => () =>
options options
.filter((v) => !['relation'].includes(v.key)) .filter((v) => !['relation'].includes(v.key))
.map((options, index) => ({ .map((options, index) => ({
...options, ...options,
key: index, key: index,
label: compile(options.label), label: compile(options.label),
options: options.children.map((option) => ({ options: options.children.map((option) => ({
...option, ...option,
label: compile(option.label), label: compile(option.label),
})),
})), })),
})), [compile],
[compile],
);
const sourceFieldsOptions = useSourceFieldsOptions();
const refGetInterface = useRef(getInterface);
useEffect(() => {
const fieldsMp = new Map();
if (!loading) {
if (data && data.length) {
Object.entries(data?.[0] || {}).forEach(([col, val]) => {
const sourceField = sourceFields[col];
const fieldInterface = inferInterface(col, val);
const defaultConfig = refGetInterface.current(fieldInterface)?.default;
const uiSchema = sourceField?.uiSchema || defaultConfig?.uiSchema || {};
fieldsMp.set(col, {
name: col,
interface: sourceField?.interface || fieldInterface,
type: sourceField?.type || defaultConfig?.type,
source: sourceField?.source,
uiSchema: {
title: col,
...uiSchema,
},
});
});
} else {
Object.entries(sourceFields || {}).forEach(([col, val]: [string, any]) =>
fieldsMp.set(col, {
name: col,
...val,
uiSchema: {
title: col,
...(val?.uiSchema || {}),
},
}),
);
}
}
if (field.value?.length) {
field.value.forEach((item) => {
if (fieldsMp.has(item.name)) {
fieldsMp.set(item.name, item);
}
});
}
// if (curFields?.data.length) {
// curFields.data.forEach((field: any) => {
// if (fieldsMp.has(field.name)) {
// fieldsMp.set(field.name, field);
// }
// });
// }
const fields = Array.from(fieldsMp.values());
if (!fields.length) {
return;
}
setDataSource(fields);
field.setValue(fields);
}, [loading, data, field, sourceFields, curFields]);
if (loading) {
return <Spin />;
}
if (!data && !error) {
return <Alert showIcon message={t('Please use a valid SELECT or WITH AS statement')} />;
}
const err = error as any;
if (err) {
const errMsg =
err?.response?.data?.errors?.map?.((item: { message: string }) => item.message).join('\n') || err.message;
return <Alert showIcon message={`${t('SQL error: ')}${errMsg}`} type="error" />;
}
const handleFieldChange = (record: any, index: number) => {
const fields = [...dataSource];
fields.splice(index, 1, record);
setDataSource(fields);
field.setValue(
fields.map((f) => ({
...f,
source: typeof f.source === 'string' ? f.source : f.source?.filter?.(Boolean)?.join('.') || null,
})),
); );
}; const sourceFieldsOptions = useSourceFieldsOptions();
const columns = [ const refGetInterface = useRef(getInterface);
{ useEffect(() => {
title: t('Field name'), const fieldsMp = new Map();
dataIndex: 'name', if (!loading) {
key: 'name', if (data && data.length) {
width: 130, Object.entries(data?.[0] || {}).forEach(([col, val]) => {
}, const sourceField = sourceFields[col];
{ const fieldInterface = inferInterface(col, val);
title: t('Field source'), const defaultConfig = refGetInterface.current(fieldInterface)?.default;
dataIndex: 'source', const uiSchema = sourceField?.uiSchema || defaultConfig?.uiSchema || {};
key: 'source', fieldsMp.set(col, {
width: 200, name: col,
render: (text: string, record: any, index: number) => { interface: sourceField?.interface || fieldInterface,
const field = dataSource[index]; type: sourceField?.type || defaultConfig?.type,
return ( source: sourceField?.source,
<Cascader uiSchema: {
defaultValue={typeof text === 'string' ? text?.split('.') : text} title: col,
allowClear ...uiSchema,
options={compile(sourceFieldsOptions)} },
placeholder={t('Select field source')} });
onChange={(value: string[]) => { });
let sourceField = sourceFields[value?.[1]]; } else {
if (!sourceField) { Object.entries(sourceFields || {}).forEach(([col, val]: [string, any]) =>
sourceField = getCollectionField(value?.join('.') || ''); fieldsMp.set(col, {
} name: col,
handleFieldChange( ...val,
{ uiSchema: {
...field, title: col,
source: value, ...(val?.uiSchema || {}),
interface: sourceField?.interface, },
type: sourceField?.type, }),
uiSchema: sourceField?.uiSchema, );
}, }
index, }
);
}} if (field.value?.length) {
/> field.value.forEach((item) => {
); if (fieldsMp.has(item.name)) {
fieldsMp.set(item.name, item);
}
});
}
// if (curFields?.data.length) {
// curFields.data.forEach((field: any) => {
// if (fieldsMp.has(field.name)) {
// fieldsMp.set(field.name, field);
// }
// });
// }
const fields = Array.from(fieldsMp.values());
if (!fields.length) {
return;
}
setDataSource(fields);
field.setValue(fields);
}, [loading, data, field, sourceFields, curFields]);
if (loading) {
return <Spin />;
}
if (!data && !error) {
return <Alert showIcon message={t('Please use a valid SELECT or WITH AS statement')} />;
}
const err = error as any;
if (err) {
const errMsg =
err?.response?.data?.errors?.map?.((item: { message: string }) => item.message).join('\n') || err.message;
return <Alert showIcon message={`${t('SQL error: ')}${errMsg}`} type="error" />;
}
const handleFieldChange = (record: any, index: number) => {
const fields = [...dataSource];
fields.splice(index, 1, record);
setDataSource(fields);
field.setValue(
fields.map((f) => ({
...f,
source: typeof f.source === 'string' ? f.source : f.source?.filter?.(Boolean)?.join('.') || null,
})),
);
};
const columns = [
{
title: t('Field name'),
dataIndex: 'name',
key: 'name',
width: 130,
}, },
}, {
{ title: t('Field source'),
title: t('Field interface'), dataIndex: 'source',
dataIndex: 'interface', key: 'source',
key: 'interface', width: 200,
width: 150, render: (text: string, record: any, index: number) => {
render: (text: string, record: any, index: number) => { const field = dataSource[index];
const field = dataSource[index]; return (
return field.source ? ( <Cascader
<Tag>{compile(getInterface(text)?.title) || text}</Tag> defaultValue={typeof text === 'string' ? text?.split('.') : text}
) : ( allowClear
<Select options={compile(sourceFieldsOptions)}
defaultValue={field.interface || 'input'} placeholder={t('Select field source')}
style={{ width: '100%' }} onChange={(value: string[]) => {
popupMatchSelectWidth={false} let sourceField = sourceFields[value?.[1]];
onChange={(value) => { if (!sourceField) {
const interfaceConfig = getInterface(value); sourceField = getCollectionField(value?.join('.') || '');
handleFieldChange( }
{ handleFieldChange(
...field, {
interface: value || null, ...field,
uiSchema: { source: value,
...interfaceConfig?.default?.uiSchema, interface: sourceField?.interface,
title: interfaceConfig?.default?.uiSchema?.title || field.uiSchema?.title, type: sourceField?.type,
uiSchema: sourceField?.uiSchema,
}, },
type: interfaceConfig?.default?.type, index,
}, );
index, }}
); />
}} );
allowClear={true} },
options={interfaceOptions}
/>
);
}, },
}, {
{ title: t('Field interface'),
title: t('Field display name'), dataIndex: 'interface',
dataIndex: 'title', key: 'interface',
key: 'title', width: 150,
width: 180, render: (text: string, record: any, index: number) => {
render: (text: string, record: any, index: number) => { const field = dataSource[index];
const field = dataSource[index]; return field.source ? (
return ( <Tag>{compile(getInterface(text)?.title) || text}</Tag>
<Input ) : (
value={field.uiSchema?.title || text} <Select
defaultValue={field.uiSchema?.title !== undefined ? field.uiSchema.title : field?.name} defaultValue={field.interface || 'input'}
onChange={(e) => style={{ width: '100%' }}
handleFieldChange({ ...field, uiSchema: { ...field?.uiSchema, title: e.target.value } }, index) popupMatchSelectWidth={false}
} onChange={(value) => {
/> const interfaceConfig = getInterface(value);
); handleFieldChange(
{
...field,
interface: value || null,
uiSchema: {
...interfaceConfig?.default?.uiSchema,
title: interfaceConfig?.default?.uiSchema?.title || field.uiSchema?.title,
},
type: interfaceConfig?.default?.type,
},
index,
);
}}
allowClear={true}
options={interfaceOptions}
/>
);
},
}, },
}, {
]; title: t('Field display name'),
return ( dataIndex: 'title',
<Table key: 'title',
bordered width: 180,
size="small" render: (text: string, record: any, index: number) => {
columns={columns} const field = dataSource[index];
dataSource={dataSource} return (
scroll={{ y: 300 }} <Input
pagination={false} value={field.uiSchema?.title || text}
rowClassName="editable-row" defaultValue={field.uiSchema?.title !== undefined ? field.uiSchema.title : field?.name}
rowKey="name" onChange={(e) =>
/> handleFieldChange({ ...field, uiSchema: { ...field?.uiSchema, title: e.target.value } }, index)
); }
}); />
);
},
},
];
return (
<Table
bordered
size="small"
columns={columns}
dataSource={dataSource}
scroll={{ y: 300 }}
pagination={false}
rowClassName="editable-row"
rowKey="name"
/>
);
},
{ displayName: 'FieldsConfigure' },
);

View File

@ -4,55 +4,58 @@ import { Table } from 'antd';
import { Schema, observer, useForm } from '@formily/react'; import { Schema, observer, useForm } from '@formily/react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export const PreviewTable = observer(() => { export const PreviewTable = observer(
const { data: res, loading, error } = useAsyncData(); () => {
const { data } = res || {}; const { data: res, loading, error } = useAsyncData();
const { t } = useTranslation(); const { data } = res || {};
const form = useForm(); const { t } = useTranslation();
const form = useForm();
const fields = form.values.fields || []; const fields = form.values.fields || [];
const titleMp = fields.reduce((mp: { [name: string]: string }, field: any) => { const titleMp = fields.reduce((mp: { [name: string]: string }, field: any) => {
mp[field.name] = field?.uiSchema?.title; mp[field.name] = field?.uiSchema?.title;
return mp; return mp;
}, {}); }, {});
const columns = error const columns = error
? [] ? []
: Object.keys(data?.[0] || {}).map((col) => { : Object.keys(data?.[0] || {}).map((col) => {
const title = titleMp[col]; const title = titleMp[col];
return { return {
title: Schema.compile(title || col, { t }), title: Schema.compile(title || col, { t }),
dataIndex: col, dataIndex: col,
key: col, key: col,
}; };
}); });
const dataSource = error const dataSource = error
? [] ? []
: data?.map((record: any, index: number) => { : data?.map((record: any, index: number) => {
const compiledRecord = Object.entries(record).reduce( const compiledRecord = Object.entries(record).reduce(
(mp: { [key: string]: any }, [key, val]: [string, any]) => { (mp: { [key: string]: any }, [key, val]: [string, any]) => {
if (typeof val !== 'string') { if (typeof val !== 'string') {
mp[key] = val; mp[key] = val;
return mp;
}
const compiled = Schema.compile(val, { t });
mp[key] = t(compiled);
return mp; return mp;
} },
const compiled = Schema.compile(val, { t }); {},
mp[key] = t(compiled); );
return mp; return { ...compiledRecord, key: index };
}, });
{},
);
return { ...compiledRecord, key: index };
});
return ( return (
<Table <Table
bordered bordered
dataSource={dataSource} dataSource={dataSource}
columns={columns} columns={columns}
scroll={{ x: columns.length * 150, y: 300 }} scroll={{ x: columns.length * 150, y: 300 }}
loading={loading} loading={loading}
rowKey="key" rowKey="key"
/> />
); );
}); },
{ displayName: 'PreviewTable' },
);

View File

@ -12,6 +12,7 @@ export interface AssociationProviderProps {
} }
const ParentCollectionContext = createContext<Collection>(null); const ParentCollectionContext = createContext<Collection>(null);
ParentCollectionContext.displayName = 'ParentCollectionContext';
const ParentCollectionProvider = (props) => { const ParentCollectionProvider = (props) => {
const collection = useCollection(); const collection = useCollection();

View File

@ -13,6 +13,7 @@ export const DocumentTitleContext = createContext<DocumentTitleContextProps>({
title: null, title: null,
setTitle() {}, setTitle() {},
}); });
DocumentTitleContext.displayName = 'DocumentTitleContext';
export const DocumentTitleProvider: React.FC<{ addonBefore?: string; addonAfter?: string }> = (props) => { export const DocumentTitleProvider: React.FC<{ addonBefore?: string; addonAfter?: string }> = (props) => {
const { addonBefore, addonAfter } = props; const { addonBefore, addonAfter } = props;

View File

@ -58,6 +58,7 @@ interface FilterContextValue {
} }
const FilterContext = createContext<FilterContextValue>(null); const FilterContext = createContext<FilterContextValue>(null);
FilterContext.displayName = 'FilterContext';
/** /**
* 使 * 使

View File

@ -15,6 +15,7 @@ const AppInner = memo(({ children }: { children: React.ReactNode }) => {
return <>{children}</>; return <>{children}</>;
}); });
AppInner.displayName = 'AppInner';
const AntdAppProvider = ({ children }: { children: React.ReactNode }) => { const AntdAppProvider = ({ children }: { children: React.ReactNode }) => {
return ( return (

View File

@ -25,6 +25,7 @@ interface GlobalThemeContextProps {
} }
const GlobalThemeContext = createContext<GlobalThemeContextProps>(null); const GlobalThemeContext = createContext<GlobalThemeContextProps>(null);
GlobalThemeContext.displayName = 'GlobalThemeContext';
export const useGlobalTheme = () => { export const useGlobalTheme = () => {
return React.useContext(GlobalThemeContext) || ({ theme: {}, isDarkTheme: false } as GlobalThemeContextProps); return React.useContext(GlobalThemeContext) || ({ theme: {}, isDarkTheme: false } as GlobalThemeContextProps);

View File

@ -10,7 +10,9 @@ type Item = MenuProps['items'][0] & {
}; };
export const GetMenuItemContext = createContext<{ collectMenuItem?(item: Item): void; onChange?: () => void }>(null); export const GetMenuItemContext = createContext<{ collectMenuItem?(item: Item): void; onChange?: () => void }>(null);
GetMenuItemContext.displayName = 'GetMenuItemContext';
export const GetMenuItemsContext = createContext<{ pushMenuItem?(item: Item): void }>(null); export const GetMenuItemsContext = createContext<{ pushMenuItem?(item: Item): void }>(null);
GetMenuItemsContext.displayName = 'GetMenuItemsContext';
/** /**
* SchemaInitializer.Item * SchemaInitializer.Item

View File

@ -65,30 +65,33 @@ const useErrorProps = (app: Application, error: any) => {
} }
}; };
const AppError: FC<{ error: Error; app: Application }> = observer(({ app, error }) => { const AppError: FC<{ error: Error; app: Application }> = observer(
const props = useErrorProps(app, error); ({ app, error }) => {
return ( const props = useErrorProps(app, error);
<div> return (
<Result <div>
className={css` <Result
top: 50%; className={css`
position: absolute; top: 50%;
width: 100%; position: absolute;
transform: translate(0, -50%); width: 100%;
`} transform: translate(0, -50%);
status="error" `}
title={app.i18n.t('App error')} status="error"
subTitle={app.i18n.t(error?.message)} title={app.i18n.t('App error')}
extra={[ subTitle={app.i18n.t(error?.message)}
<Button type="primary" key="try" onClick={() => window.location.reload()}> extra={[
{app.i18n.t('Try again')} <Button type="primary" key="try" onClick={() => window.location.reload()}>
</Button>, {app.i18n.t('Try again')}
]} </Button>,
{...props} ]}
/> {...props}
</div> />
); </div>
}); );
},
{ displayName: 'AppError' },
);
const getProps = (app: Application) => { const getProps = (app: Application) => {
if (app.ws.serverDown) { if (app.ws.serverDown) {
@ -195,39 +198,45 @@ const getProps = (app: Application) => {
return {}; return {};
}; };
const AppMaintaining: FC<{ app: Application; error: Error }> = observer(({ app }) => { const AppMaintaining: FC<{ app: Application; error: Error }> = observer(
const { icon, status, title, subTitle } = getProps(app); ({ app }) => {
return ( const { icon, status, title, subTitle } = getProps(app);
<div> return (
<Result <div>
className={css` <Result
top: 50%; className={css`
position: absolute; top: 50%;
width: 100%; position: absolute;
transform: translate(0, -50%); width: 100%;
`} transform: translate(0, -50%);
icon={icon} `}
status={status} icon={icon}
title={app.i18n.t(title)} status={status}
subTitle={app.i18n.t(subTitle)} title={app.i18n.t(title)}
// extra={[ subTitle={app.i18n.t(subTitle)}
// <Button type="primary" key="try" onClick={() => window.location.reload()}> // extra={[
// {app.i18n.t('Try again')} // <Button type="primary" key="try" onClick={() => window.location.reload()}>
// </Button>, // {app.i18n.t('Try again')}
// ]} // </Button>,
/> // ]}
</div> />
); </div>
}); );
},
{ displayName: 'AppMaintaining' },
);
const AppMaintainingDialog: FC<{ app: Application; error: Error }> = observer(({ app }) => { const AppMaintainingDialog: FC<{ app: Application; error: Error }> = observer(
const { icon, status, title, subTitle } = getProps(app); ({ app }) => {
return ( const { icon, status, title, subTitle } = getProps(app);
<Modal open={true} footer={null} closable={false}> return (
<Result icon={icon} status={status} title={app.i18n.t(title)} subTitle={app.i18n.t(subTitle)} /> <Modal open={true} footer={null} closable={false}>
</Modal> <Result icon={icon} status={status} title={app.i18n.t(title)} subTitle={app.i18n.t(subTitle)} />
); </Modal>
}); );
},
{ displayName: 'AppMaintainingDialog' },
);
const AppNotFound = () => { const AppNotFound = () => {
const navigate = useNavigate(); const navigate = useNavigate();

View File

@ -1,3 +1,4 @@
import { createContext } from 'react'; import { createContext } from 'react';
export const PinnedPluginListContext = createContext({ items: {} }); export const PinnedPluginListContext = createContext({ items: {} });
PinnedPluginListContext.displayName = 'PinnedPluginListContext';

View File

@ -73,3 +73,4 @@ export const PluginDocument: React.FC<PluginDocumentProps> = memo((props) => {
</div> </div>
); );
}); });
PluginDocument.displayName = 'PluginDocument';

View File

@ -9,6 +9,7 @@ import { ADMIN_SETTINGS_PATH, PluginSettingsPageType, useApp } from '../applicat
import { useCompile } from '../schema-component'; import { useCompile } from '../schema-component';
export const SettingsCenterContext = createContext<any>({}); export const SettingsCenterContext = createContext<any>({});
SettingsCenterContext.displayName = 'SettingsCenterContext';
function getMenuItems(list: PluginSettingsPageType[]) { function getMenuItems(list: PluginSettingsPageType[]) {
return list.map((item) => { return list.map((item) => {

View File

@ -4,7 +4,9 @@ import { CollectionRecordProvider } from '../data-source';
import { useCurrentUserContext } from '../user'; import { useCurrentUserContext } from '../user';
export const RecordContext_deprecated = createContext({}); export const RecordContext_deprecated = createContext({});
RecordContext_deprecated.displayName = 'RecordContext_deprecated';
export const RecordIndexContext = createContext(null); export const RecordIndexContext = createContext(null);
RecordIndexContext.displayName = 'RecordIndexContext';
/** /**
* @deprecated use `CollectionRecordProvider` instead * @deprecated use `CollectionRecordProvider` instead

View File

@ -54,6 +54,7 @@ const filterByACL = (schema, options) => {
}; };
const SchemaIdContext = createContext(null); const SchemaIdContext = createContext(null);
SchemaIdContext.displayName = 'SchemaIdContext';
const useMenuProps = () => { const useMenuProps = () => {
const defaultSelectedUid = useContext(SchemaIdContext); const defaultSelectedUid = useContext(SchemaIdContext);
return { return {

View File

@ -4,6 +4,7 @@ import React, { createContext } from 'react';
import { useActionContext } from './hooks'; import { useActionContext } from './hooks';
export const ActionContext = createContext<ActionContextProps>({}); export const ActionContext = createContext<ActionContextProps>({});
ActionContext.displayName = 'ActionContext';
export const ActionContextProvider: React.FC<ActionContextProps & { value?: ActionContextProps }> = (props) => { export const ActionContextProvider: React.FC<ActionContextProps & { value?: ActionContextProps }> = (props) => {
const contextProps = useActionContext(); const contextProps = useActionContext();

View File

@ -40,116 +40,119 @@ export const filterAnalyses = (filters): any[] => {
return results; return results;
}; };
const InternalAssociationSelect = observer((props: AssociationSelectProps) => { const InternalAssociationSelect = observer(
const { objectValue = true } = props; (props: AssociationSelectProps) => {
const field: any = useField(); const { objectValue = true } = props;
const fieldSchema = useFieldSchema(); const field: any = useField();
const service = useServiceOptions(props); const fieldSchema = useFieldSchema();
const { options: collectionField } = useAssociationFieldContext(); const service = useServiceOptions(props);
const initValue = isVariable(props.value) ? undefined : props.value; const { options: collectionField } = useAssociationFieldContext();
const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue; const initValue = isVariable(props.value) ? undefined : props.value;
// 因为通过 Schema 的形式书写的组件,在值变更的时候 `value` 的值没有改变,所以需要维护一个 `innerValue` 来变更值
const [innerValue, setInnerValue] = useState(value);
const addMode = fieldSchema['x-component-props']?.addMode;
const isAllowAddNew = fieldSchema['x-add-new'];
const { t } = useTranslation();
const { multiple } = props;
const form = useForm();
const api = useAPIClient();
const resource = api.resource(collectionField.target);
const linkageFields = filterAnalyses(field.componentProps?.service?.params?.filter);
const recordData = useCollectionRecordData();
useEffect(() => {
const initValue = isVariable(field.value) ? undefined : field.value;
const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue; const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue;
setInnerValue(value); // 因为通过 Schema 的形式书写的组件,在值变更的时候 `value` 的值没有改变,所以需要维护一个 `innerValue` 来变更值
}, [field.value]); const [innerValue, setInnerValue] = useState(value);
useEffect(() => { const addMode = fieldSchema['x-component-props']?.addMode;
const id = uid(); const isAllowAddNew = fieldSchema['x-add-new'];
form.addEffects(id, () => { const { t } = useTranslation();
if (linkageFields?.length > 0) { const { multiple } = props;
//支持深层次子表单 const form = useForm();
onFieldChange('*', (fieldPath: any) => { const api = useAPIClient();
if (linkageFields.includes(fieldPath.props.name) && field.value) { const resource = api.resource(collectionField.target);
props.onChange(field.initialValue); const linkageFields = filterAnalyses(field.componentProps?.service?.params?.filter);
setInnerValue(field.initialValue); const recordData = useCollectionRecordData();
} useEffect(() => {
}); const initValue = isVariable(field.value) ? undefined : field.value;
} const value = Array.isArray(initValue) ? initValue.filter(Boolean) : initValue;
}); setInnerValue(value);
}, [field.value]);
useEffect(() => {
const id = uid();
form.addEffects(id, () => {
if (linkageFields?.length > 0) {
//支持深层次子表单
onFieldChange('*', (fieldPath: any) => {
if (linkageFields.includes(fieldPath.props.name) && field.value) {
props.onChange(field.initialValue);
setInnerValue(field.initialValue);
}
});
}
});
return () => { return () => {
form.removeEffects(id); form.removeEffects(id);
};
}, []);
const handleCreateAction = async (props) => {
const { search: value, callBack } = props;
const {
data: { data },
} = await resource.create({
values: {
[field?.componentProps?.fieldNames?.label || 'id']: value,
},
});
if (data) {
if (['m2m', 'o2m'].includes(collectionField?.interface) && multiple !== false) {
const values = form.getValuesIn(field.path) || [];
values.push(data);
form.setValuesIn(field.path, values);
field.onInput(values);
} else {
form.setValuesIn(field.path, data);
field.onInput(data);
}
isFunction(callBack) && callBack?.();
message.success(t('Saved successfully'));
}
};
const QuickAddContent = (props) => {
return (
<div
onClick={() => handleCreateAction(props)}
style={{ cursor: 'pointer', padding: '5px 12px', color: '#0d0c0c' }}
>
<PlusOutlined />
<span style={{ paddingLeft: 5 }}>{t('Add') + `${props.search}`}</span>
</div>
);
}; };
}, []);
const handleCreateAction = async (props) => {
const { search: value, callBack } = props;
const {
data: { data },
} = await resource.create({
values: {
[field?.componentProps?.fieldNames?.label || 'id']: value,
},
});
if (data) {
if (['m2m', 'o2m'].includes(collectionField?.interface) && multiple !== false) {
const values = form.getValuesIn(field.path) || [];
values.push(data);
form.setValuesIn(field.path, values);
field.onInput(values);
} else {
form.setValuesIn(field.path, data);
field.onInput(data);
}
isFunction(callBack) && callBack?.();
message.success(t('Saved successfully'));
}
};
const QuickAddContent = (props) => {
return ( return (
<div <div key={fieldSchema.name}>
onClick={() => handleCreateAction(props)} <Space.Compact style={{ display: 'flex', lineHeight: '32px' }}>
style={{ cursor: 'pointer', padding: '5px 12px', color: '#0d0c0c' }} <RemoteSelect
> style={{ width: '100%' }}
<PlusOutlined /> {...props}
<span style={{ paddingLeft: 5 }}>{t('Add') + `${props.search}`}</span> size={'middle'}
objectValue={objectValue}
value={value || innerValue}
service={service}
onChange={(value) => {
const val = value?.length !== 0 ? value : null;
props.onChange?.(val);
}}
CustomDropdownRender={addMode === 'quickAdd' && QuickAddContent}
></RemoteSelect>
{(addMode === 'modalAdd' || isAllowAddNew) && (
<RecordProvider isNew={true} record={null} parent={recordData}>
<RecursionField
onlyRenderProperties
basePath={field.address}
schema={fieldSchema}
filterProperties={(s) => {
return s['x-component'] === 'Action';
}}
/>
</RecordProvider>
)}
</Space.Compact>
</div> </div>
); );
}; },
return ( { displayName: 'AssociationSelect' },
<div key={fieldSchema.name}> );
<Space.Compact style={{ display: 'flex', lineHeight: '32px' }}>
<RemoteSelect
style={{ width: '100%' }}
{...props}
size={'middle'}
objectValue={objectValue}
value={value || innerValue}
service={service}
onChange={(value) => {
const val = value?.length !== 0 ? value : null;
props.onChange?.(val);
}}
CustomDropdownRender={addMode === 'quickAdd' && QuickAddContent}
></RemoteSelect>
{(addMode === 'modalAdd' || isAllowAddNew) && (
<RecordProvider isNew={true} record={null} parent={recordData}>
<RecursionField
onlyRenderProperties
basePath={field.address}
schema={fieldSchema}
filterProperties={(s) => {
return s['x-component'] === 'Action';
}}
/>
</RecordProvider>
)}
</Space.Compact>
</div>
);
});
interface AssociationSelectInterface { interface AssociationSelectInterface {
(props: any): React.ReactElement; (props: any): React.ReactElement;

View File

@ -10,3 +10,4 @@ export interface AssociationFieldContextProps {
} }
export const AssociationFieldContext = createContext<AssociationFieldContextProps>({}); export const AssociationFieldContext = createContext<AssociationFieldContextProps>({});
AssociationFieldContext.displayName = 'AssociationFieldContext';

View File

@ -179,6 +179,7 @@ export const useFieldNames = (props) => {
}; };
const SubFormContext = createContext<Record<string, any>>(null); const SubFormContext = createContext<Record<string, any>>(null);
SubFormContext.displayName = 'SubFormContext';
export const SubFormProvider = SubFormContext.Provider; export const SubFormProvider = SubFormContext.Provider;
/** /**

View File

@ -12,6 +12,7 @@ import { Action } from '../action';
import { StablePopover } from '../popover'; import { StablePopover } from '../popover';
export const FilterActionContext = createContext<any>(null); export const FilterActionContext = createContext<any>(null);
FilterActionContext.displayName = 'FilterActionContext';
export const FilterAction = observer( export const FilterAction = observer(
(props: any) => { (props: any) => {

View File

@ -12,5 +12,8 @@ export interface FilterContextProps {
} }
export const RemoveConditionContext = createContext(null); export const RemoveConditionContext = createContext(null);
RemoveConditionContext.displayName = 'RemoveConditionContext';
export const FilterContext = createContext<FilterContextProps>(null); export const FilterContext = createContext<FilterContextProps>(null);
FilterContext.displayName = 'FilterContext';
export const FilterLogicContext = createContext(null); export const FilterLogicContext = createContext(null);
FilterLogicContext.displayName = 'FilterLogicContext';

View File

@ -1,5 +1,6 @@
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager'; import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
import { useMemo } from 'react';
/** /**
* *
@ -7,15 +8,17 @@ import { useCollection_deprecated, useCollectionManager_deprecated } from '../..
*/ */
export const useOperatorList = (): any[] => { export const useOperatorList = (): any[] => {
const schema = useFieldSchema(); const schema = useFieldSchema();
const fieldInterface = schema['x-designer-props']?.interface;
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
const { getCollectionFields, getInterface } = useCollectionManager_deprecated(); const { getCollectionFields, getInterface } = useCollectionManager_deprecated();
const collectionFields = getCollectionFields(name);
if (fieldInterface) { const res = useMemo(() => {
return getInterface(fieldInterface)?.filterable?.operators || []; const fieldInterface = schema['x-designer-props']?.interface;
} const collectionFields = getCollectionFields(name);
if (fieldInterface) {
const field = collectionFields.find((item) => item.name === schema.name); return getInterface(fieldInterface)?.filterable?.operators || [];
return getInterface(field?.interface)?.filterable?.operators || []; }
const field = collectionFields.find((item) => item.name === schema.name);
return getInterface(field?.interface)?.filterable?.operators || [];
}, [schema.name]);
return res;
}; };

View File

@ -78,9 +78,12 @@ export function FormDialog(title: any, id: any, renderer?: any, theme?: any): IF
root.unmount(); root.unmount();
}, },
}; };
const DialogContent = observer(() => { const DialogContent = observer(
return <Fragment>{isFn(renderer) ? renderer(env.form) : renderer}</Fragment>; () => {
}); return <Fragment>{isFn(renderer) ? renderer(env.form) : renderer}</Fragment>;
},
{ displayName: 'DialogContent' },
);
const renderDialog = (open = true, resolve?: () => any, reject?: () => any) => { const renderDialog = (open = true, resolve?: () => any, reject?: () => any) => {
const { form } = env; const { form } = env;
if (!form) return null; if (!form) return null;

View File

@ -87,6 +87,7 @@ const useDefaultValues = (opts: any = {}, props: FormProps = {}) => {
}; };
const FormBlockContext = createContext<any>(null); const FormBlockContext = createContext<any>(null);
FormBlockContext.displayName = 'FormBlockContext';
export const Form: React.FC<FormProps> & { Designer?: any } = observer( export const Form: React.FC<FormProps> & { Designer?: any } = observer(
(props) => { (props) => {

View File

@ -126,6 +126,7 @@ export const G2PlotRenderer = forwardRef(function <O = any>(props: ReactG2PlotPr
return <div className={cls(['g2plot', className])} ref={containerRef} />; return <div className={cls(['g2plot', className])} ref={containerRef} />;
}); });
G2PlotRenderer.displayName = 'G2PlotRenderer';
export const G2Plot: any = observer( export const G2Plot: any = observer(
(props: any) => { (props: any) => {
@ -140,12 +141,14 @@ export const G2Plot: any = observer(
if (typeof fn === 'function') { if (typeof fn === 'function') {
const result = fn.bind({ api })(); const result = fn.bind({ api })();
if (result?.then) { if (result?.then) {
result.then((data) => { result
if (Array.isArray(data)) { .then((data) => {
field.componentProps.config.data = data; if (Array.isArray(data)) {
} field.componentProps.config.data = data;
field.data.loading = false; }
}); field.data.loading = false;
})
.catch(console.error);
} else { } else {
field.data.loading = false; field.data.loading = false;
} }

View File

@ -5,6 +5,7 @@ import React, { createContext, useContext, useEffect, useMemo } from 'react';
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider'; import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
import useStyles from './GridCard.Decorator.style'; import useStyles from './GridCard.Decorator.style';
export const GridCardBlockContext = createContext<any>({}); export const GridCardBlockContext = createContext<any>({});
GridCardBlockContext.displayName = 'GridCardBlockContext';
const InternalGridCardBlockProvider = (props) => { const InternalGridCardBlockProvider = (props) => {
const { resource, service } = useBlockRequestContext(); const { resource, service } = useBlockRequestContext();

View File

@ -11,8 +11,11 @@ import { useToken } from '../__builtins__';
import useStyles from './Grid.style'; import useStyles from './Grid.style';
const GridRowContext = createContext<any>({}); const GridRowContext = createContext<any>({});
GridRowContext.displayName = 'GridRowContext';
const GridColContext = createContext<any>({}); const GridColContext = createContext<any>({});
GridColContext.displayName = 'GridColContext';
const GridContext = createContext<any>({}); const GridContext = createContext<any>({});
GridContext.displayName = 'GridContext';
const breakRemoveOnGrid = (s: Schema) => s['x-component'] === 'Grid'; const breakRemoveOnGrid = (s: Schema) => s['x-component'] === 'Grid';
const breakRemoveOnRow = (s: Schema) => s['x-component'] === 'Grid.Row'; const breakRemoveOnRow = (s: Schema) => s['x-component'] === 'Grid.Row';

View File

@ -77,3 +77,4 @@ export const EllipsisWithTooltip = forwardRef((props: Partial<IEllipsisWithToolt
</Popover> </Popover>
); );
}); });
EllipsisWithTooltip.displayName = 'EllipsisWithTooltip';

View File

@ -67,3 +67,4 @@ export const Json = React.forwardRef<typeof Input.TextArea, JSONTextAreaProps>(
); );
}, },
); );
Json.displayName = 'Json';

View File

@ -7,6 +7,7 @@ import React, { createContext, useContext, useEffect, useMemo } from 'react';
import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider'; import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider';
export const ListBlockContext = createContext<any>({}); export const ListBlockContext = createContext<any>({});
ListBlockContext.displayName = 'ListBlockContext';
const InternalListBlockProvider = (props) => { const InternalListBlockProvider = (props) => {
const { resource, service } = useBlockRequestContext(); const { resource, service } = useBlockRequestContext();

View File

@ -350,7 +350,6 @@ const SideMenu = ({
}; };
const MenuModeContext = createContext(null); const MenuModeContext = createContext(null);
MenuModeContext.displayName = 'MenuModeContext'; MenuModeContext.displayName = 'MenuModeContext';
const useSideMenuRef = () => { const useSideMenuRef = () => {

View File

@ -6,74 +6,80 @@ import React, { useMemo, useRef } from 'react';
import { useCollectionManager_deprecated } from '../../../collection-manager'; import { useCollectionManager_deprecated } from '../../../collection-manager';
import { StablePopover } from '../popover'; import { StablePopover } from '../popover';
export const Editable = observer((props) => { export const Editable = observer(
const field: any = useField(); (props) => {
const containerRef = useRef(null); const field: any = useField();
const fieldSchema = useFieldSchema(); const containerRef = useRef(null);
const value = field.value; const fieldSchema = useFieldSchema();
const schema: any = { const value = field.value;
name: fieldSchema.name, const schema: any = {
'x-collection-field': fieldSchema['x-collection-field'], name: fieldSchema.name,
'x-component': 'CollectionField', 'x-collection-field': fieldSchema['x-collection-field'],
'x-read-pretty': true, 'x-component': 'CollectionField',
default: value, 'x-read-pretty': true,
'x-component-props': fieldSchema['x-component-props'], default: value,
}; 'x-component-props': fieldSchema['x-component-props'],
const form = useMemo( };
() => const form = useMemo(
createForm({ () =>
values: { createForm({
[fieldSchema.name]: value, values: {
}, [fieldSchema.name]: value,
}), },
[field.value, fieldSchema['x-component-props']], }),
); [field.value, fieldSchema['x-component-props']],
const getContainer = () => { );
return containerRef.current; const getContainer = () => {
}; return containerRef.current;
};
const modifiedChildren = React.Children.map(props.children, (child) => { const modifiedChildren = React.Children.map(props.children, (child) => {
if (React.isValidElement(child)) { if (React.isValidElement(child)) {
//@ts-ignore //@ts-ignore
return React.cloneElement(child, { getContainer }); return React.cloneElement(child, { getContainer });
} }
return child; return child;
}); });
return ( return (
<FormItem {...props} labelStyle={{ display: 'none' }}> <FormItem {...props} labelStyle={{ display: 'none' }}>
<StablePopover <StablePopover
content={ content={
<div style={{ width: '100%', height: '100%', minWidth: 500 }}> <div style={{ width: '100%', height: '100%', minWidth: 500 }}>
<div ref={containerRef}>{modifiedChildren}</div> <div ref={containerRef}>{modifiedChildren}</div>
</div> </div>
}
trigger="click"
placement={'bottomLeft'}
overlayClassName={css`
padding-top: 0;
.ant-popover-arrow {
display: none;
} }
`} trigger="click"
> placement={'bottomLeft'}
<div style={{ minHeight: 30, padding: '0 8px' }}> overlayClassName={css`
<FormContext.Provider value={form}> padding-top: 0;
<RecursionField schema={schema} name={fieldSchema.name} /> .ant-popover-arrow {
</FormContext.Provider> display: none;
</div> }
</StablePopover> `}
</FormItem> >
); <div style={{ minHeight: 30, padding: '0 8px' }}>
}); <FormContext.Provider value={form}>
<RecursionField schema={schema} name={fieldSchema.name} />
</FormContext.Provider>
</div>
</StablePopover>
</FormItem>
);
},
{ displayName: 'Editable' },
);
export const QuickEdit = observer((props) => { export const QuickEdit = observer(
const field = useField<Field>(); (props) => {
const { getCollectionJoinField } = useCollectionManager_deprecated(); const field = useField<Field>();
const fieldSchema = useFieldSchema(); const { getCollectionJoinField } = useCollectionManager_deprecated();
const collectionField = getCollectionJoinField(fieldSchema['x-collection-field']); const fieldSchema = useFieldSchema();
if (!collectionField) { const collectionField = getCollectionJoinField(fieldSchema['x-collection-field']);
return null; if (!collectionField) {
} return null;
return field.editable ? <Editable {...props} /> : <FormItem {...props} style={{ padding: '0 8px' }} />; }
}); return field.editable ? <Editable {...props} /> : <FormItem {...props} style={{ padding: '0 8px' }} />;
},
{ displayName: 'QuickEdit' },
);

View File

@ -16,6 +16,7 @@ import { useFieldNames } from './useFieldNames';
import { getLabelFormatValue, useLabelUiSchema } from './util'; import { getLabelFormatValue, useLabelUiSchema } from './util';
export const RecordPickerContext = createContext(null); export const RecordPickerContext = createContext(null);
RecordPickerContext.displayName = 'RecordPickerContext';
function flatData(data) { function flatData(data) {
const newArr = []; const newArr = [];

View File

@ -13,6 +13,7 @@ import {
import React, { createContext, useContext, useState } from 'react'; import React, { createContext, useContext, useState } from 'react';
const DataSourceContext = createContext(null); const DataSourceContext = createContext(null);
DataSourceContext.displayName = 'DataSourceContext';
const useSelectedRowKeys = () => { const useSelectedRowKeys = () => {
const ctx = useContext(DataSourceContext); const ctx = useContext(DataSourceContext);

View File

@ -7,6 +7,7 @@ import { RawTextArea } from './RawTextArea';
import { TextArea } from './TextArea'; import { TextArea } from './TextArea';
const VariableScopeContext = createContext([]); const VariableScopeContext = createContext([]);
VariableScopeContext.displayName = 'VariableScopeContext';
export function VariableScopeProvider({ scope = [], children }) { export function VariableScopeProvider({ scope = [], children }) {
return <VariableScopeContext.Provider value={scope}>{children}</VariableScopeContext.Provider>; return <VariableScopeContext.Provider value={scope}>{children}</VariableScopeContext.Provider>;

View File

@ -15,3 +15,4 @@ export const XButton = forwardRef((props: ButtonProps, ref: any) => {
</Button> </Button>
); );
}); });
XButton.displayName = 'XButton';

View File

@ -2,11 +2,13 @@ import { TinyColor } from '@ctrl/tinycolor';
import { useDraggable, useDroppable } from '@dnd-kit/core'; import { useDraggable, useDroppable } from '@dnd-kit/core';
import { cx } from '@emotion/css'; import { cx } from '@emotion/css';
import { Schema, observer, useField, useFieldSchema } from '@formily/react'; import { Schema, observer, useField, useFieldSchema } from '@formily/react';
import React, { HTMLAttributes, createContext, useContext } from 'react'; import React, { HTMLAttributes, createContext, useContext, useMemo } from 'react';
import { useToken } from '../../antd/__builtins__'; import { useToken } from '../../antd/__builtins__';
export const DraggableContext = createContext(null); export const DraggableContext = createContext(null);
DraggableContext.displayName = 'DraggableContext';
export const SortableContext = createContext(null); export const SortableContext = createContext(null);
SortableContext.displayName = 'SortableContext';
export const SortableProvider = (props) => { export const SortableProvider = (props) => {
const { id, data, children } = props; const { id, data, children } = props;
@ -74,15 +76,17 @@ interface SortableItemProps extends HTMLAttributes<HTMLDivElement> {
export const SortableItem: React.FC<SortableItemProps> = observer( export const SortableItem: React.FC<SortableItemProps> = observer(
(props) => { (props) => {
const { schema, id, eid, removeParentsIfNoChildren, ...others } = useSortableItemProps(props); const { schema, id, eid, removeParentsIfNoChildren, ...others } = useSortableItemProps(props);
const data = useMemo(() => {
return {
insertAdjacent: 'afterEnd',
schema: schema,
removeParentsIfNoChildren: removeParentsIfNoChildren ?? true,
};
}, [schema, removeParentsIfNoChildren]);
return ( return (
<SortableProvider <SortableProvider id={id} data={data}>
id={id}
data={{
insertAdjacent: 'afterEnd',
schema: schema,
removeParentsIfNoChildren: removeParentsIfNoChildren ?? true,
}}
>
<Sortable id={eid} {...others}> <Sortable id={eid} {...others}>
{props.children} {props.children}
</Sortable> </Sortable>

View File

@ -2,3 +2,4 @@ import { createContext } from 'react';
import { ISchemaComponentContext } from './types'; import { ISchemaComponentContext } from './types';
export const SchemaComponentContext = createContext<ISchemaComponentContext>({}); export const SchemaComponentContext = createContext<ISchemaComponentContext>({});
SchemaComponentContext.displayName = 'SchemaComponentContext.Provider';

View File

@ -1,5 +1,5 @@
import { ExpressionScope, SchemaComponentsContext, SchemaOptionsContext } from '@formily/react'; import { ExpressionScope, SchemaComponentsContext, SchemaOptionsContext } from '@formily/react';
import React, { useContext } from 'react'; import React, { memo, useContext, useMemo } from 'react';
import { ISchemaComponentOptionsProps } from '../types'; import { ISchemaComponentOptionsProps } from '../types';
export const useSchemaOptionsContext = () => { export const useSchemaOptionsContext = () => {
@ -7,16 +7,28 @@ export const useSchemaOptionsContext = () => {
return options || {}; return options || {};
}; };
export const SchemaComponentOptions: React.FC<ISchemaComponentOptionsProps> = (props) => { export const SchemaComponentOptions: React.FC<ISchemaComponentOptionsProps> = memo((props) => {
const { children } = props; const { children } = props;
const options = useSchemaOptionsContext(); const options = useSchemaOptionsContext();
const components = { ...options.components, ...props.components }; const components = useMemo(() => {
const scope = { ...options.scope, ...props.scope }; return { ...options.components, ...props.components };
}, [options.components, props.components]);
const scope = useMemo(() => {
return { ...options.scope, ...props.scope };
}, [options.scope, props.scope]);
const schemaOptionsContextValue = useMemo(() => {
return { scope, components };
}, [scope, components]);
return ( return (
<SchemaOptionsContext.Provider value={{ scope, components }}> <SchemaOptionsContext.Provider value={schemaOptionsContextValue}>
<SchemaComponentsContext.Provider value={components}> <SchemaComponentsContext.Provider value={components}>
<ExpressionScope value={scope}>{children}</ExpressionScope> <ExpressionScope value={scope}>{children}</ExpressionScope>
</SchemaComponentsContext.Provider> </SchemaComponentsContext.Provider>
</SchemaOptionsContext.Provider> </SchemaOptionsContext.Provider>
); );
}; });
SchemaComponentOptions.displayName = 'SchemaComponentOptions';

View File

@ -44,28 +44,36 @@ Schema.registerCompiler(Registry.compile);
export const SchemaComponentProvider: React.FC<ISchemaComponentProvider> = (props) => { export const SchemaComponentProvider: React.FC<ISchemaComponentProvider> = (props) => {
const { designable, onDesignableChange, components, children } = props; const { designable, onDesignableChange, components, children } = props;
const [, setUid] = useState(uid()); const [uidValue, setUid] = useState(uid());
const [formId, setFormId] = useState(uid()); const [formId, setFormId] = useState(uid());
const form = useMemo(() => props.form || createForm(), [formId]); const form = useMemo(() => props.form || createForm(), [formId]);
const { t } = useTranslation(); const { t } = useTranslation();
const scope = { ...props.scope, t, randomString }; const scope = useMemo(() => {
return { ...props.scope, t, randomString };
}, [props.scope, t]);
const [active, setActive] = useState(designable); const [active, setActive] = useState(designable);
const schemaComponentContextValue = useMemo(
() => ({
scope,
components,
reset: () => setFormId(uid()),
refresh: () => {
setUid(uid());
},
designable: typeof designable === 'boolean' ? designable : active,
setDesignable: (value) => {
if (typeof designable !== 'boolean') {
setActive(value);
}
onDesignableChange?.(value);
},
}),
[uidValue, scope, components, designable, active],
);
return ( return (
<SchemaComponentContext.Provider <SchemaComponentContext.Provider value={schemaComponentContextValue}>
value={{
scope,
components,
reset: () => setFormId(uid()),
refresh: () => setUid(uid()),
designable: typeof designable === 'boolean' ? designable : active,
setDesignable: (value) => {
if (typeof designable !== 'boolean') {
setActive(value);
}
onDesignableChange?.(value);
},
}}
>
<FormProvider form={form}> <FormProvider form={form}>
<SchemaComponentOptions inherit scope={scope} components={components}> <SchemaComponentOptions inherit scope={scope} components={components}>
{children} {children}

View File

@ -36,3 +36,4 @@ export const AsDefaultTemplate = React.forwardRef((props: any, ref) => {
/> />
); );
}); });
AsDefaultTemplate.displayName = 'AsDefaultTemplate';

View File

@ -276,3 +276,4 @@ ArrayCollapse.Copy = React.forwardRef((props: any, ref) => {
/> />
); );
}); });
(ArrayCollapse as any).Copy.displayName = 'ArrayCollapse.Copy';

View File

@ -32,3 +32,4 @@ export const EnableLinkage = React.forwardRef((props: any, ref) => {
/> />
); );
}); });
EnableLinkage.displayName = 'EnableLinkage';

View File

@ -266,3 +266,4 @@ ArrayCollapse.Copy = React.forwardRef((props: any, ref) => {
/> />
); );
}); });
(ArrayCollapse as any).Copy.displayName = 'ArrayCollapse.Copy';

View File

@ -11,5 +11,8 @@ export interface FilterContextProps {
} }
export const RemoveActionContext = createContext(null); export const RemoveActionContext = createContext(null);
RemoveActionContext.displayName = 'RemoveActionContext';
export const FilterContext = createContext<FilterContextProps>(null); export const FilterContext = createContext<FilterContextProps>(null);
FilterContext.displayName = 'FilterContext';
export const LinkageLogicContext = createContext(null); export const LinkageLogicContext = createContext(null);
LinkageLogicContext.displayName = 'LinkageLogicContext';

View File

@ -124,6 +124,7 @@ interface SchemaSettingsContextProps<T = any> {
} }
const SchemaSettingsContext = createContext<SchemaSettingsContextProps>(null); const SchemaSettingsContext = createContext<SchemaSettingsContextProps>(null);
SchemaSettingsContext.displayName = 'SchemaSettingsContext';
export function useSchemaSettings<T = any>() { export function useSchemaSettings<T = any>() {
return useContext(SchemaSettingsContext) as SchemaSettingsContextProps<T>; return useContext(SchemaSettingsContext) as SchemaSettingsContextProps<T>;

View File

@ -5,6 +5,7 @@ import { useSchemaTemplateManager } from './SchemaTemplateManagerProvider';
import { useTemplateBlockContext } from '../block-provider/TemplateBlockProvider'; import { useTemplateBlockContext } from '../block-provider/TemplateBlockProvider';
const BlockTemplateContext = createContext<any>({}); const BlockTemplateContext = createContext<any>({});
BlockTemplateContext.displayName = 'BlockTemplateContext';
export const useBlockTemplateContext = () => { export const useBlockTemplateContext = () => {
return useContext(BlockTemplateContext); return useContext(BlockTemplateContext);

View File

@ -11,6 +11,7 @@ import { BlockTemplate } from './BlockTemplate';
import { DEFAULT_DATA_SOURCE_KEY } from '../data-source'; import { DEFAULT_DATA_SOURCE_KEY } from '../data-source';
export const SchemaTemplateManagerContext = createContext<any>({}); export const SchemaTemplateManagerContext = createContext<any>({});
SchemaTemplateManagerContext.displayName = 'SchemaTemplateManagerContext';
export const SchemaTemplateManagerProvider: React.FC<any> = (props) => { export const SchemaTemplateManagerProvider: React.FC<any> = (props) => {
const { templates, refresh } = props; const { templates, refresh } = props;

View File

@ -4,6 +4,7 @@ import { useRequest } from '../api-client';
import { useAppSpin } from '../application/hooks/useAppSpin'; import { useAppSpin } from '../application/hooks/useAppSpin';
export const SystemSettingsContext = createContext<Result<any, any>>(null); export const SystemSettingsContext = createContext<Result<any, any>>(null);
SystemSettingsContext.displayName = 'SystemSettingsContext';
export const useSystemSettings = () => { export const useSystemSettings = () => {
return useContext(SystemSettingsContext); return useContext(SystemSettingsContext);

View File

@ -162,6 +162,8 @@ export const SettingsMenu: React.FC<{
}; };
export const DropdownVisibleContext = createContext(null); export const DropdownVisibleContext = createContext(null);
DropdownVisibleContext.displayName = 'DropdownVisibleContext';
export const CurrentUser = () => { export const CurrentUser = () => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const { token } = useToken(); const { token } = useToken();

View File

@ -6,6 +6,7 @@ import { useAppSpin } from '../application/hooks/useAppSpin';
import { useCompile } from '../schema-component'; import { useCompile } from '../schema-component';
export const CurrentUserContext = createContext<ReturnTypeOfUseRequest>(null); export const CurrentUserContext = createContext<ReturnTypeOfUseRequest>(null);
CurrentUserContext.displayName = 'CurrentUserContext';
export const useCurrentUserContext = () => { export const useCurrentUserContext = () => {
return useContext(CurrentUserContext); return useContext(CurrentUserContext);

View File

@ -24,6 +24,7 @@ interface OptionsOfAddMenuItem {
type Item = ItemType & { _options?: OptionsOfAddMenuItem }; type Item = ItemType & { _options?: OptionsOfAddMenuItem };
const CurrentUserSettingsMenuContext = createContext<{ menuItems: React.MutableRefObject<Item[]> }>(null); const CurrentUserSettingsMenuContext = createContext<{ menuItems: React.MutableRefObject<Item[]> }>(null);
CurrentUserSettingsMenuContext.displayName = 'CurrentUserSettingsMenuContext';
export const useCurrentUserSettingsMenu = () => { export const useCurrentUserSettingsMenu = () => {
const { menuItems } = useContext(CurrentUserSettingsMenuContext) || {}; const { menuItems } = useContext(CurrentUserSettingsMenuContext) || {};

View File

@ -16,6 +16,7 @@ import { isVariable } from './utils/isVariable';
import { uniq } from './utils/uniq'; import { uniq } from './utils/uniq';
export const VariablesContext = createContext<VariablesContextType>(null); export const VariablesContext = createContext<VariablesContextType>(null);
VariablesContext.displayName = 'VariablesContext';
const variableToCollectionName = {}; const variableToCollectionName = {};

View File

@ -6,3 +6,4 @@ export const RolesManagerContext = createContext<{
}>({ }>({
role: null, role: null,
} as any); } as any);
RolesManagerContext.displayName = 'RolesManagerContext';

View File

@ -3,6 +3,7 @@ import { Spin } from 'antd';
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
const AvailableActionsContext = createContext([]); const AvailableActionsContext = createContext([]);
AvailableActionsContext.displayName = 'AvailableActionsContext';
export const AvailableActionsProvider: React.FC = (props) => { export const AvailableActionsProvider: React.FC = (props) => {
const { data, loading } = useRequest<{ const { data, loading } = useRequest<{

View File

@ -3,6 +3,7 @@ import { Spin } from 'antd';
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
const MenuItemsContext = createContext(null); const MenuItemsContext = createContext(null);
MenuItemsContext.displayName = 'MenuItemsContext';
export const toItems = (properties = {}) => { export const toItems = (properties = {}) => {
const items = []; const items = [];

View File

@ -28,6 +28,7 @@ const toActionMap = (arr: any[]) => {
}; };
export const RoleResourceCollectionContext = createContext<any>({}); export const RoleResourceCollectionContext = createContext<any>({});
RoleResourceCollectionContext.displayName = 'RoleResourceCollectionContext';
export const RolesResourcesActions = connect((props) => { export const RolesResourcesActions = connect((props) => {
const { styles } = useStyles(); const { styles } = useStyles();

View File

@ -4,6 +4,7 @@ import { FormProvider, SchemaComponent } from '@nocobase/client';
import { scopesSchema } from '../schemas/scopes'; import { scopesSchema } from '../schemas/scopes';
const RolesResourcesScopesSelectedRowKeysContext = createContext(null); const RolesResourcesScopesSelectedRowKeysContext = createContext(null);
RolesResourcesScopesSelectedRowKeysContext.displayName = 'RolesResourcesScopesSelectedRowKeysContext';
const RolesResourcesScopesSelectedRowKeysProvider: React.FC = (props) => { const RolesResourcesScopesSelectedRowKeysProvider: React.FC = (props) => {
const [keys, setKeys] = useState([]); const [keys, setKeys] = useState([]);

View File

@ -103,6 +103,7 @@ const Value = observer(
); );
const IsAssociationBlock = createContext(null); const IsAssociationBlock = createContext(null);
IsAssociationBlock.displayName = 'IsAssociationBlock';
export const AuditLogs: any = () => { export const AuditLogs: any = () => {
const isAssoc = useContext(IsAssociationBlock); const isAssoc = useContext(IsAssociationBlock);

View File

@ -12,6 +12,7 @@ export type Authenticator = {
}; };
export const AuthenticatorsContext = createContext<Authenticator[]>([]); export const AuthenticatorsContext = createContext<Authenticator[]>([]);
AuthenticatorsContext.displayName = 'AuthenticatorsContext';
export const useAuthenticator = (name: string) => { export const useAuthenticator = (name: string) => {
const authenticators = useContext(AuthenticatorsContext); const authenticators = useContext(AuthenticatorsContext);

View File

@ -11,6 +11,7 @@ export const SignupPageContext = createContext<{
}>; }>;
}; };
}>({}); }>({});
SignupPageContext.displayName = 'SignupPageContext';
export const SignupPageProvider: React.FC<{ export const SignupPageProvider: React.FC<{
authType: string; authType: string;

View File

@ -34,9 +34,12 @@ export const useAdminSettingsForm = (authType: string) => {
return auth?.components?.AdminSettingsForm; return auth?.components?.AdminSettingsForm;
}; };
export const Options = observer(() => { export const Options = observer(
const form = useForm(); () => {
const record = useRecord(); const form = useForm();
const Component = useAdminSettingsForm(form.values.authType || record.authType); const record = useRecord();
return Component ? <Component /> : null; const Component = useAdminSettingsForm(form.values.authType || record.authType);
}); return Component ? <Component /> : null;
},
{ displayName: 'Options' },
);

View File

@ -3,6 +3,7 @@ import { createContext, useContext } from 'react';
export const AuthTypeContext = createContext<{ export const AuthTypeContext = createContext<{
type: string; type: string;
}>({ type: '' }); }>({ type: '' });
AuthTypeContext.displayName = 'AuthTypeContext';
export const AuthTypesContext = createContext<{ export const AuthTypesContext = createContext<{
types: { types: {
@ -11,6 +12,7 @@ export const AuthTypesContext = createContext<{
value: string; value: string;
}[]; }[];
}>({ types: [] }); }>({ types: [] });
AuthTypesContext.displayName = 'AuthTypesContext';
export const useAuthTypes = () => { export const useAuthTypes = () => {
const { types } = useContext(AuthTypesContext); const { types } = useContext(AuthTypesContext);

View File

@ -2,8 +2,11 @@ import { createContext, useContext } from 'react';
import type { ToolbarProps } from './types'; import type { ToolbarProps } from './types';
export const CalendarToolbarContext = createContext<ToolbarProps>(null); export const CalendarToolbarContext = createContext<ToolbarProps>(null);
CalendarToolbarContext.displayName = 'CalendarToolbarContext';
export const CalendarContext = createContext(null); export const CalendarContext = createContext(null);
CalendarContext.displayName = 'CalendarContext';
export const DeleteEventContext = createContext(null); export const DeleteEventContext = createContext(null);
DeleteEventContext.displayName = 'DeleteEventContext';
export const useDeleteEvent = () => { export const useDeleteEvent = () => {
return useContext(DeleteEventContext); return useContext(DeleteEventContext);

View File

@ -5,6 +5,7 @@ import _ from 'lodash';
import React, { createContext, useContext, useEffect, useMemo } from 'react'; import React, { createContext, useContext, useEffect, useMemo } from 'react';
export const CalendarBlockContext = createContext<any>({}); export const CalendarBlockContext = createContext<any>({});
CalendarBlockContext.displayName = 'CalendarBlockContext';
const InternalCalendarBlockProvider = (props) => { const InternalCalendarBlockProvider = (props) => {
const { fieldNames, showLunar } = props; const { fieldNames, showLunar } = props;

View File

@ -7,6 +7,7 @@ export const ChartQueryMetadataContext = createContext({
refresh: () => {}, refresh: () => {},
data: [] as any[], data: [] as any[],
}); });
ChartQueryMetadataContext.displayName = 'ChartQueryMetadataContext';
export const ChartQueryMetadataProvider: React.FC = (props) => { export const ChartQueryMetadataProvider: React.FC = (props) => {
const api = useAPIClient(); const api = useAPIClient();

View File

@ -3,6 +3,7 @@ import React, { FC, useState, createContext } from 'react';
import * as hooks from './hooks'; import * as hooks from './hooks';
export const DataSourceContext = createContext(null); export const DataSourceContext = createContext(null);
DataSourceContext.displayName = 'DataSourceContext';
export const DatabaseConnectionProvider: FC = (props) => { export const DatabaseConnectionProvider: FC = (props) => {
const [dataSource, setDataSource] = useState(null); const [dataSource, setDataSource] = useState(null);

View File

@ -33,6 +33,7 @@ const RemoteCollectionContext = createContext<{
refreshRM: Function; refreshRM: Function;
titleField: string; titleField: string;
}>({ refreshRM: () => {}, titleField: null, targetCollection: null }); }>({ refreshRM: () => {}, titleField: null, targetCollection: null });
RemoteCollectionContext.displayName = 'RemoteCollectionContext';
export const useRemoteCollectionContext = () => { export const useRemoteCollectionContext = () => {
return useContext(RemoteCollectionContext); return useContext(RemoteCollectionContext);
}; };

View File

@ -4,38 +4,41 @@ import { debounce } from 'lodash';
import React, { useState, useMemo, useEffect } from 'react'; import React, { useState, useMemo, useEffect } from 'react';
import { useRecord } from '@nocobase/client'; import { useRecord } from '@nocobase/client';
export const FieldTitleInput = observer((props: any) => { export const FieldTitleInput = observer(
const { value, handleFieldChange } = props; (props: any) => {
const record = useRecord(); const { value, handleFieldChange } = props;
const [titleValue, setTitleValue] = useState(value); const record = useRecord();
// 实时更新 const [titleValue, setTitleValue] = useState(value);
const handleRealTimeChange = (newValue: string) => { // 实时更新
setTitleValue(newValue); const handleRealTimeChange = (newValue: string) => {
}; setTitleValue(newValue);
};
// 防抖操作 // 防抖操作
const debouncedHandleFieldChange = useMemo(() => { const debouncedHandleFieldChange = useMemo(() => {
return debounce((newTitle: string) => { return debounce((newTitle: string) => {
handleFieldChange( handleFieldChange(
{ {
uiSchema: { uiSchema: {
...record?.uiSchema, ...record?.uiSchema,
title: newTitle, title: newTitle,
},
}, },
}, record.name,
record.name, );
); }, 1000);
}, 1000); }, [handleFieldChange, record]);
}, [handleFieldChange, record]);
// 统一处理函数,实时更新+防抖 // 统一处理函数,实时更新+防抖
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value; const newValue = e.target.value;
handleRealTimeChange(newValue); handleRealTimeChange(newValue);
debouncedHandleFieldChange(newValue); debouncedHandleFieldChange(newValue);
}; };
useEffect(() => { useEffect(() => {
setTitleValue(value); setTitleValue(value);
}, [value]); }, [value]);
return <Input value={titleValue} onChange={handleChange} />; return <Input value={titleValue} onChange={handleChange} />;
}); },
{ displayName: 'FieldTitleInput' },
);

View File

@ -11,6 +11,7 @@ import { dataSourceSchema } from './schemas/dataSourceTable';
import { PermissionProvider } from './PermisionProvider'; import { PermissionProvider } from './PermisionProvider';
const AvailableActionsContext = createContext([]); const AvailableActionsContext = createContext([]);
AvailableActionsContext.displayName = 'AvailableActionsContext';
const AvailableActionsProver: React.FC = (props) => { const AvailableActionsProver: React.FC = (props) => {
const { data, loading } = useRequest<{ const { data, loading } = useRequest<{

Some files were not shown because too many files have changed in this diff Show More