fix: collection undefined (#1169)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: daoyoucloud/tachybase#1169
This commit is contained in:
parent
0cf4a450de
commit
6fc13dd14f
@ -1,8 +1,8 @@
|
||||
import React, { FC, ReactNode, createContext, useContext, useMemo } from 'react';
|
||||
import React, { createContext, FC, ReactNode, useContext, useMemo } from 'react';
|
||||
|
||||
import { useCollectionManager } from './CollectionManagerProvider';
|
||||
import { CollectionDeletedPlaceholder } from '../components/CollectionDeletedPlaceholder';
|
||||
import type { CollectionOptions, Collection, GetCollectionFieldPredicate } from './Collection';
|
||||
import type { Collection, CollectionOptions, GetCollectionFieldPredicate } from './Collection';
|
||||
import { useCollectionManager } from './CollectionManagerProvider';
|
||||
|
||||
export const CollectionContext = createContext<Collection>(null);
|
||||
CollectionContext.displayName = 'CollectionContext';
|
||||
|
@ -6,7 +6,6 @@ import { useFilterActionProps } from './filter/useFilterActionProps';
|
||||
import { formV1Settings } from './form';
|
||||
import { filterFormItemSettings, formItemSettings } from './form-item';
|
||||
import { formDetailsSettings, formSettings, readPrettyFormSettings } from './form-v2';
|
||||
import { requestChartData } from './g2plot/requestChartData';
|
||||
import { pageSettings, pageTabSettings } from './page';
|
||||
|
||||
export class AntdSchemaComponentPlugin extends Plugin {
|
||||
@ -25,7 +24,6 @@ export class AntdSchemaComponentPlugin extends Plugin {
|
||||
|
||||
addScopes() {
|
||||
this.app.addScopes({
|
||||
requestChartData,
|
||||
useFilterActionProps,
|
||||
});
|
||||
}
|
||||
|
@ -22,16 +22,16 @@ export const useGetAriaLabelOfBlockItem = (defaultName?: string) => {
|
||||
const collection = useCollection();
|
||||
const name = defaultName || blockName;
|
||||
|
||||
const title = compile(fieldSchema['title']) || compile(collection.getField(fieldSchema.name)?.uiSchema?.title);
|
||||
const title = compile(fieldSchema['title']) || compile(collection?.getField(fieldSchema.name)?.uiSchema?.title);
|
||||
|
||||
const getAriaLabel = useCallback(
|
||||
(postfix?: string) => {
|
||||
postfix = postfix ? `-${postfix}` : '';
|
||||
return ['block-item', component, collection.name, name, collectionField, title, postfix]
|
||||
return ['block-item', component, collection?.name, name, collectionField, title, postfix]
|
||||
.filter(Boolean)
|
||||
.join('-');
|
||||
},
|
||||
[component, collection.name, name, collectionField, title],
|
||||
[component, collection?.name, name, collectionField, title],
|
||||
);
|
||||
|
||||
return {
|
||||
|
@ -1,183 +0,0 @@
|
||||
import {
|
||||
Area,
|
||||
Bar,
|
||||
BidirectionalBar,
|
||||
Box,
|
||||
Bullet,
|
||||
Chord,
|
||||
CirclePacking,
|
||||
Column,
|
||||
DualAxes,
|
||||
Facet,
|
||||
Funnel,
|
||||
Gauge,
|
||||
Heatmap,
|
||||
Histogram,
|
||||
Line,
|
||||
Liquid,
|
||||
Mix,
|
||||
Pie,
|
||||
Progress,
|
||||
Radar,
|
||||
RadialBar,
|
||||
RingProgress,
|
||||
Rose,
|
||||
Sankey,
|
||||
Scatter,
|
||||
Stock,
|
||||
Sunburst,
|
||||
TinyArea,
|
||||
TinyColumn,
|
||||
TinyLine,
|
||||
Treemap,
|
||||
Venn,
|
||||
Violin,
|
||||
Waterfall,
|
||||
WordCloud,
|
||||
} from '@antv/g2plot';
|
||||
import { Field } from '@tachybase/schema';
|
||||
import { observer, useField } from '@tachybase/schema';
|
||||
import { Spin } from 'antd';
|
||||
import cls from 'classnames';
|
||||
import React, { forwardRef, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAPIClient } from '../../../api-client';
|
||||
import { G2PlotDesigner } from './G2PlotDesigner';
|
||||
|
||||
export type ReactG2PlotProps<O> = {
|
||||
readonly className?: string;
|
||||
readonly plot: any;
|
||||
readonly config: O;
|
||||
};
|
||||
|
||||
const plots = {
|
||||
Line,
|
||||
Area,
|
||||
Column,
|
||||
Bar,
|
||||
Pie,
|
||||
Rose,
|
||||
WordCloud,
|
||||
Scatter,
|
||||
Radar,
|
||||
DualAxes,
|
||||
TinyLine,
|
||||
TinyColumn,
|
||||
TinyArea,
|
||||
Histogram,
|
||||
Progress,
|
||||
RingProgress,
|
||||
Heatmap,
|
||||
Box,
|
||||
Violin,
|
||||
Venn,
|
||||
Stock,
|
||||
Funnel,
|
||||
Liquid,
|
||||
Bullet,
|
||||
Sunburst,
|
||||
Gauge,
|
||||
Waterfall,
|
||||
RadialBar,
|
||||
BidirectionalBar,
|
||||
Treemap,
|
||||
Sankey,
|
||||
Chord,
|
||||
CirclePacking,
|
||||
Mix,
|
||||
Facet,
|
||||
};
|
||||
|
||||
export const G2PlotRenderer = forwardRef(function <O = any>(props: ReactG2PlotProps<O>, ref: any) {
|
||||
const { className, plot, config } = props;
|
||||
const containerRef = useRef(undefined);
|
||||
const plotRef = useRef(undefined);
|
||||
|
||||
function syncRef(source, target) {
|
||||
if (typeof target === 'function') {
|
||||
target(source.current);
|
||||
} else if (target) {
|
||||
target.current = source.current;
|
||||
}
|
||||
}
|
||||
|
||||
function renderPlot() {
|
||||
if (plotRef.current) {
|
||||
plotRef.current.update(config);
|
||||
} else {
|
||||
plotRef.current = new plot(containerRef.current, config);
|
||||
plotRef?.current?.render();
|
||||
}
|
||||
|
||||
syncRef(plotRef, ref);
|
||||
}
|
||||
|
||||
function destoryPlot() {
|
||||
if (plotRef.current) {
|
||||
plotRef.current.destroy();
|
||||
plotRef.current = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
renderPlot();
|
||||
return () => destoryPlot();
|
||||
}, [config, plot]);
|
||||
|
||||
return <div className={cls(['g2plot', className])} ref={containerRef} />;
|
||||
});
|
||||
G2PlotRenderer.displayName = 'G2PlotRenderer';
|
||||
|
||||
export const G2Plot: any = observer(
|
||||
(props: any) => {
|
||||
const { plot, config } = props;
|
||||
const field = useField<Field>();
|
||||
const { t } = useTranslation();
|
||||
const api = useAPIClient();
|
||||
useEffect(() => {
|
||||
field.data = field.data || {};
|
||||
field.data.loading = true;
|
||||
const fn = config?.data;
|
||||
if (typeof fn === 'function') {
|
||||
const result = fn.bind({ api })();
|
||||
if (result?.then) {
|
||||
result
|
||||
.then((data) => {
|
||||
if (Array.isArray(data)) {
|
||||
field.componentProps.config.data = data;
|
||||
}
|
||||
field.data.loading = false;
|
||||
})
|
||||
.catch(console.error);
|
||||
} else {
|
||||
field.data.loading = false;
|
||||
}
|
||||
} else {
|
||||
field.data.loading = false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (!plot || !config) {
|
||||
return <div style={{ opacity: 0.3 }}>{t('In configuration')}...</div>;
|
||||
}
|
||||
if (field?.data?.loading !== false) {
|
||||
return <Spin />;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{field.title && <h2>{field.title}</h2>}
|
||||
<G2PlotRenderer
|
||||
plot={plots[plot]}
|
||||
config={{
|
||||
...config,
|
||||
data: Array.isArray(config?.data) ? config.data : [],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
{ displayName: 'G2Plot' },
|
||||
);
|
||||
|
||||
G2Plot.Designer = G2PlotDesigner;
|
||||
G2Plot.plots = plots;
|
@ -1,120 +0,0 @@
|
||||
import { ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAPIClient } from '../../../api-client';
|
||||
import {
|
||||
GeneralSchemaDesigner,
|
||||
SchemaSettingsDivider,
|
||||
SchemaSettingsModalItem,
|
||||
SchemaSettingsRemove,
|
||||
} from '../../../schema-settings';
|
||||
import { useCompile, useDesignable } from '../../hooks';
|
||||
import _ from 'lodash';
|
||||
|
||||
const validateJSON = {
|
||||
validator: `{{(value, rule)=> {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
const val = JSON.parse(value);
|
||||
if(!isNaN(val)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch(error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
}}}`,
|
||||
message: '{{t("Invalid JSON format")}}',
|
||||
};
|
||||
|
||||
export const G2PlotDesigner = () => {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const compile = useCompile();
|
||||
const api = useAPIClient();
|
||||
return (
|
||||
<GeneralSchemaDesigner>
|
||||
<SchemaSettingsModalItem
|
||||
title={t('Edit chart')}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
title: t('Edit chart'),
|
||||
properties: {
|
||||
title: {
|
||||
title: t('Chart title'),
|
||||
type: 'string',
|
||||
default: fieldSchema.title,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
plot: {
|
||||
title: t('Chart type'),
|
||||
type: 'string',
|
||||
default: fieldSchema?.['x-component-props']?.plot,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-disabled': !!fieldSchema?.['x-component-props']?.plot,
|
||||
},
|
||||
config: {
|
||||
title: t('Chart config'),
|
||||
type: 'string',
|
||||
default: JSON.stringify(fieldSchema?.['x-component-props']?.config, null, 2),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {
|
||||
autoSize: { minRows: 8, maxRows: 16 },
|
||||
},
|
||||
'x-validator': validateJSON,
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
// {{ fetchData(api, { url: 'chartData:get' }) }}
|
||||
onSubmit={async ({ plot, title, config }) => {
|
||||
field.title = compile(title);
|
||||
field.componentProps.plot = plot;
|
||||
const conf = compile(JSON.parse(config));
|
||||
const fn = conf?.data;
|
||||
if (typeof fn === 'function') {
|
||||
const result = fn.bind({ api })();
|
||||
if (result?.then) {
|
||||
result
|
||||
.then((data) => {
|
||||
if (Array.isArray(data)) {
|
||||
field.componentProps.config.data = data;
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
} else {
|
||||
field.componentProps.config = conf;
|
||||
}
|
||||
_.set(fieldSchema, 'title', title);
|
||||
_.set(fieldSchema, 'x-component-props.plot', plot);
|
||||
_.set(fieldSchema, 'x-component-props.config', JSON.parse(config));
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
title,
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
'x-component-props': fieldSchema['x-component-props'],
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
<SchemaSettingsDivider />
|
||||
<SchemaSettingsRemove
|
||||
removeParentsIfNoChildren
|
||||
breakRemoveOn={{
|
||||
'x-component': 'Grid',
|
||||
}}
|
||||
/>
|
||||
</GeneralSchemaDesigner>
|
||||
);
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
import { render, waitFor } from '@tachybase/test/client';
|
||||
import React from 'react';
|
||||
import App1 from '../demos/demo1';
|
||||
|
||||
// jsdom does not support canvas, so we need to skip this test
|
||||
describe.skip('G2Plot', () => {
|
||||
it('basic', async () => {
|
||||
render(<App1 />);
|
||||
|
||||
await waitFor(() => {
|
||||
const g2plot = document.querySelector('.g2plot') as HTMLDivElement;
|
||||
expect(g2plot).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,91 +0,0 @@
|
||||
import {
|
||||
APIClient,
|
||||
APIClientProvider,
|
||||
CardItem,
|
||||
G2Plot,
|
||||
SchemaComponent,
|
||||
SchemaComponentProvider,
|
||||
} from '@tachybase/client';
|
||||
import React from 'react';
|
||||
import { mockAPIClient } from '../../../../testUtils';
|
||||
|
||||
const { apiClient, mockRequest } = mockAPIClient();
|
||||
|
||||
mockRequest.onGet('/test').reply(200, {
|
||||
data: [
|
||||
{
|
||||
Date: '2010-01',
|
||||
scales: 1998,
|
||||
},
|
||||
{
|
||||
Date: '2010-02',
|
||||
scales: 1850,
|
||||
},
|
||||
{
|
||||
Date: '2010-03',
|
||||
scales: 1720,
|
||||
},
|
||||
{
|
||||
Date: '2010-04',
|
||||
scales: 1818,
|
||||
},
|
||||
{
|
||||
Date: '2010-05',
|
||||
scales: 1920,
|
||||
},
|
||||
{
|
||||
Date: '2010-06',
|
||||
scales: 1802,
|
||||
},
|
||||
{
|
||||
Date: '2010-07',
|
||||
scales: 1945,
|
||||
},
|
||||
{
|
||||
Date: '2010-08',
|
||||
scales: 1856,
|
||||
},
|
||||
{
|
||||
Date: '2010-09',
|
||||
scales: 2107,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const requestChartData = (options) => {
|
||||
return async function (this: { api: APIClient }) {
|
||||
const response = await this.api.request(options);
|
||||
return response?.data?.data;
|
||||
};
|
||||
};
|
||||
|
||||
const schema = {
|
||||
type: 'void',
|
||||
name: 'line',
|
||||
'x-designer': 'G2Plot.Designer',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'G2Plot',
|
||||
'x-component-props': {
|
||||
plot: 'Line',
|
||||
config: {
|
||||
data: '{{ requestChartData({ url: "/test" }) }}',
|
||||
padding: 'auto',
|
||||
xField: 'Date',
|
||||
yField: 'scales',
|
||||
xAxis: {
|
||||
// type: 'timeCat',
|
||||
tickCount: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<APIClientProvider apiClient={apiClient}>
|
||||
<SchemaComponentProvider components={{ G2Plot, CardItem }} scope={{ requestChartData }}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</SchemaComponentProvider>
|
||||
</APIClientProvider>
|
||||
);
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
---
|
||||
group:
|
||||
title: Schema Components
|
||||
order: 3
|
||||
---
|
||||
|
||||
# G2Plot
|
||||
|
||||
<code src="./demos/demo1.tsx"></code>
|
@ -1 +0,0 @@
|
||||
export * from './G2Plot';
|
@ -1,12 +0,0 @@
|
||||
import { APIClient } from '../../../api-client';
|
||||
|
||||
export const requestChartData = (options) => {
|
||||
return async function (this: { api: APIClient }) {
|
||||
try {
|
||||
const response = await this.api.request(options);
|
||||
return response?.data?.data;
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
};
|
@ -23,7 +23,6 @@ export * from './form';
|
||||
export * from './form-dialog';
|
||||
export * from './form-item';
|
||||
export * from './form-v2';
|
||||
export * from './g2plot';
|
||||
export * from './grid';
|
||||
export * from './grid-card';
|
||||
export * from './icon-picker';
|
||||
|
Loading…
Reference in New Issue
Block a user