fix(core-blocks): CB-1054 data loaders flickering

This commit is contained in:
Wroud
2021-06-14 14:37:15 +03:00
parent 2ccd35d470
commit f3971c9e2f
6 changed files with 59 additions and 17 deletions
@@ -11,25 +11,35 @@ import { useState, useEffect } from 'react';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
export interface ComplexLoaderProps<T> {
interface IComplexLoaderData<T> {
promise: Promise<T> | undefined;
data: T | undefined;
error: Error | undefined;
loader: () => Promise<T>;
}
export interface ComplexLoaderProps<T> {
loader: IComplexLoaderData<T>;
placeholder: React.ReactElement;
keepLoading?: boolean;
children: (content: T) => JSX.Element;
}
export const ComplexLoader: React.FC<ComplexLoaderProps<any>> = function ComplexLoader(props) {
const [content, setContent] = useState<unknown | null>(null);
const [content, setContent] = useState<unknown | null>(props.loader.data);
const notificationService = useService(NotificationService);
useEffect(() => {
let unmounted = false;
if (!content) {
props
.loader
.loader()
.then(value => !unmounted && setContent(value))
.catch(exception => !unmounted && notificationService.logException(exception, 'Can\'t load resource'));
}
return () => {
unmounted = true;
};
@@ -41,3 +51,35 @@ export const ComplexLoader: React.FC<ComplexLoaderProps<any>> = function Complex
return props.children(content);
};
export function createComplexLoader<T>(loader: () => Promise<T>): IComplexLoaderData<T> {
return {
promise: undefined,
data: undefined,
error: undefined,
async loader() {
if (this.data !== undefined) {
return this.data;
}
if (this.error) {
throw this.error;
}
if (this.promise) {
return await this.promise;
}
this.promise = loader();
try {
this.data = await this.promise;
return this.data;
} catch (exception) {
this.error = exception;
throw exception;
}
},
};
}
@@ -6,12 +6,12 @@
* you may not use this file except in compliance with the License.
*/
import { ComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
async function loader() {
const loader = createComplexLoader(async function loader() {
const { ReactSanitizedHTML } = await import('./ReactSanitizedHTML');
return { ReactSanitizedHTML };
}
});
interface Props {
html: string;
@@ -6,14 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import { ComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import type { ICodeEditorProps } from './ICodeEditorProps';
async function loader() {
const loader = createComplexLoader(async function loader() {
const { CodeEditor } = await import('./CodeEditor');
return { CodeEditor };
}
});
export const CodeEditorLoader: React.FC<ICodeEditorProps> = function CodeEditorLoader(props) {
return (
@@ -8,7 +8,7 @@
import { observer } from 'mobx-react-lite';
import { ComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer';
interface Props {
@@ -17,10 +17,10 @@ interface Props {
className?: string;
}
async function loader() {
const loader = createComplexLoader(async function loader() {
const { DataGridTable } = await import('./DataGridTable');
return { DataGridTable };
}
});
export const DataGridLoader: React.FC<Props> = observer(function DataGridLoader({
tableModel, resultIndex, className,
@@ -6,14 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import type { TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { createComplexLoader, TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { ComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import type { IDataValuePanelProps, IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer';
async function loader() {
const loader = createComplexLoader(async function loader() {
const { GISValuePresentation } = await import('./GISValuePresentation');
return { GISValuePresentation };
}
});
export const GISViewer: TabContainerPanelComponent<IDataValuePanelProps<any, IDatabaseResultSet>> = function GISViewer({ model, resultIndex }) {
return (
@@ -8,15 +8,15 @@
import { observer } from 'mobx-react-lite';
import { ComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
import type { ISQLCodeEditorProps } from './ISQLCodeEditorProps';
import type { SQLCodeEditorController } from './SQLCodeEditorController';
async function loader() {
const loader = createComplexLoader(async function loader() {
const { SQLCodeEditor } = await import('./SQLCodeEditor');
return { SQLCodeEditor };
}
});
export const SQLCodeEditorLoader = observer<ISQLCodeEditorProps, SQLCodeEditorController>(function SQLCodeEditorLoader(props, ref) {
return (