mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Refactor/cb 3214/suspense (#1530)
* CB-3214 feat: enable strict mode for development * CB-3214 refactor: loaders * CB-3214 fix: NodeManagerUtils.parentsFromPath remove node from parents list * CB-3214 fix: nav tree node preload
This commit is contained in:
@@ -63,7 +63,7 @@ const buttonStyles = css`
|
||||
}
|
||||
|
||||
&[href] {
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -18,6 +18,7 @@ const styles = css`
|
||||
error {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
error-name {
|
||||
@@ -55,6 +56,7 @@ const styles = css`
|
||||
error[|inline] {
|
||||
align-items: center;
|
||||
height: 38px;
|
||||
padding: 0;
|
||||
|
||||
& error-data {
|
||||
display: flex;
|
||||
|
||||
@@ -27,7 +27,7 @@ const styles = css`
|
||||
a[|wrapper] {
|
||||
&, &:hover, &:focus, &:active {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,16 +328,18 @@ export function useResource<
|
||||
// throw refObj.loadingPromise;
|
||||
// }
|
||||
|
||||
if (this.loading) {
|
||||
throw this.resource.waitLoad();
|
||||
}
|
||||
if (!this.isLoaded()) {
|
||||
if (this.loading) {
|
||||
throw this.resource.waitLoad();
|
||||
}
|
||||
|
||||
if (this.canLoad) {
|
||||
throw refObj.load();
|
||||
}
|
||||
if (this.canLoad) {
|
||||
throw refObj.load();
|
||||
}
|
||||
|
||||
if (this.isError()) {
|
||||
throw this.exception;
|
||||
if (this.isError()) {
|
||||
throw this.exception;
|
||||
}
|
||||
}
|
||||
//---------------------
|
||||
|
||||
@@ -358,7 +360,7 @@ export function useResource<
|
||||
}
|
||||
|
||||
if (this.isError()) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.resource.isLoaded(propertiesRef.key, propertiesRef.includes);
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import {
|
||||
GraphQLService, CachedMapResource, ResourceKey, isResourceKeyList, resourceKeyList, ResourceKeyUtils, ResourceKeyList
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
import { ExecutorInterrupter } from '@cloudbeaver/core-executor';
|
||||
import { GraphQLService, CachedMapResource, ResourceKey, isResourceKeyList, resourceKeyList, ResourceKeyUtils, ResourceKeyList, DetailsError } from '@cloudbeaver/core-sdk';
|
||||
import { flat } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { DBObject } from './EntityTypes';
|
||||
import { NavNodeInfoResource } from './NavNodeInfoResource';
|
||||
@@ -39,6 +39,29 @@ export class DBObjectResource extends CachedMapResource<string, DBObject> {
|
||||
this.navNodeInfoResource.outdateResource(this);
|
||||
this.navNodeInfoResource.deleteInResource(this);
|
||||
this.navNodeInfoResource.onDataOutdated.addHandler(this.outdateChildren.bind(this));
|
||||
this.beforeLoad.addHandler(async (originalKey, context) => {
|
||||
await this.navTreeResource.waitLoad();
|
||||
if (isDBObjectParentKey(originalKey)) {
|
||||
await this.navTreeResource.load(originalKey.mark);
|
||||
return;
|
||||
}
|
||||
|
||||
const key = this.transformParam(originalKey);
|
||||
const parents = [...new Set(ResourceKeyUtils
|
||||
.mapArray(key, nodeId => this.navNodeInfoResource.get(nodeId)?.parentId)
|
||||
.filter<string>((nodeId): nodeId is string => nodeId !== undefined))];
|
||||
|
||||
const children = await this.navTreeResource.load(resourceKeyList(parents));
|
||||
|
||||
if (
|
||||
ResourceKeyUtils.count(key) > 0
|
||||
&& !ResourceKeyUtils.includes(resourceKeyList(flat(children)), key)
|
||||
) {
|
||||
ExecutorInterrupter.interrupt(context);
|
||||
const cause = new DetailsError(`Entity not found: ${key.toString()}`);
|
||||
throw this.markDataError(cause, key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected async loader(originalKey: ResourceKey<string>): Promise<Map<string, DBObject>> {
|
||||
|
||||
@@ -81,8 +81,10 @@ export class NavNodeInfoResource extends CachedMapResource<string, NavNode> {
|
||||
});
|
||||
|
||||
if (keyList.length > 0) {
|
||||
this.set(resourceKeyList(keyList), values);
|
||||
const keyListKey = resourceKeyList(keyList);
|
||||
this.set(keyListKey, values);
|
||||
this.markUpdated(key);
|
||||
this.cleanError(ResourceKeyUtils.join(keyListKey, key));
|
||||
this.onItemAdd.execute(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { action, computed, makeObservable, observable, runInAction } from 'mobx'
|
||||
import { CoreSettingsService } from '@cloudbeaver/core-app';
|
||||
import { AppAuthService, UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { Executor, ExecutorInterrupter, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { Executor, ExecutorInterrupter, IExecutionContext, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { SessionDataResource } from '@cloudbeaver/core-root';
|
||||
import {
|
||||
@@ -141,8 +141,13 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
if (parent !== undefined && !children.includes(next)) {
|
||||
return false;
|
||||
}
|
||||
await this.scheduler.waitRelease(next);
|
||||
|
||||
children = await this.load(next);
|
||||
if (this.isLoadable(next)) {
|
||||
children = await this.load(next);
|
||||
} else {
|
||||
children = this.get(next) || [];
|
||||
}
|
||||
parent = next;
|
||||
}
|
||||
|
||||
@@ -374,6 +379,7 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
const children = this.data.get(key) || [];
|
||||
childrenToRemove.push(...children.filter(navNodeId => !value.includes(navNodeId)));
|
||||
this.dataSet(key, value);
|
||||
this.cleanError(resourceKeyList(value));
|
||||
});
|
||||
|
||||
this.delete(resourceKeyList(childrenToRemove));
|
||||
@@ -405,9 +411,9 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
}
|
||||
|
||||
protected async preLoadData(
|
||||
key: ResourceKey<string>
|
||||
key: ResourceKey<string>,
|
||||
contexts: IExecutionContext<ResourceKey<string>>
|
||||
): Promise<void> {
|
||||
// this.performUpdate(key, undefined, async key => {
|
||||
await ResourceKeyUtils.forEachAsync(key, async nodeId => {
|
||||
if (!this.navNodeInfoResource.has(nodeId) && nodeId !== ROOT_NODE_PATH) {
|
||||
await this.navNodeInfoResource.loadNodeParents(nodeId);
|
||||
@@ -416,10 +422,11 @@ export class NavTreeResource extends CachedMapResource<string, string[]> {
|
||||
|
||||
if (!preloaded) {
|
||||
const cause = new DetailsError(`Entity not found: ${nodeId}`);
|
||||
throw new ResourceError(this, key, undefined, 'Entity not found', { cause });
|
||||
const error = new ResourceError(this, key, undefined, 'Entity not found', { cause });
|
||||
ExecutorInterrupter.interrupt(contexts);
|
||||
throw this.markDataError(error, key);
|
||||
}
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
protected async loader(key: ResourceKey<string>): Promise<Map<string, string[]>> {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import { observable, toJS } from 'mobx';
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { Executor, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { Executor, IExecutionContext, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { DataSynchronizationService, ServerEventId } from '@cloudbeaver/core-root';
|
||||
import { CachedMapResource, CachedResourceIncludeArgs, GetResourceListQueryVariables, GraphQLService, ICachedMapResourceMetadata, isResourceKeyList, ResourceKey, resourceKeyList, ResourceKeyUtils, RmResource } from '@cloudbeaver/core-sdk';
|
||||
@@ -255,6 +255,7 @@ export class ResourceManagerResource
|
||||
|
||||
protected async preLoadData(
|
||||
key: ResourceKey<IResourceManagerParams>,
|
||||
contexts: IExecutionContext<ResourceKey<IResourceManagerParams>>,
|
||||
refresh: boolean,
|
||||
includes: CachedResourceIncludeArgs<RmResourceInfo, ResourceInfoIncludes>
|
||||
): Promise<void> {
|
||||
|
||||
@@ -79,7 +79,6 @@ export abstract class CachedDataResource<
|
||||
param: TParam,
|
||||
context?: T
|
||||
): Promise<CachedResourceValueIncludes<TData, T>> {
|
||||
await this.preLoadData(param, false, context);
|
||||
await this.loadData(param, true, context);
|
||||
return this.data as CachedResourceValueIncludes<TData, T>;
|
||||
}
|
||||
@@ -88,7 +87,6 @@ export abstract class CachedDataResource<
|
||||
param: TParam,
|
||||
context?: T
|
||||
): Promise<CachedResourceValueIncludes<TData, T>> {
|
||||
await this.preLoadData(param, false, context);
|
||||
await this.loadData(param, false, context);
|
||||
return this.data as CachedResourceValueIncludes<TData, T>;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ export abstract class CachedMapResource<
|
||||
exception: Error,
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: CachedResourceIncludeArgs<TValue, TContext>
|
||||
): void {
|
||||
): ResourceError {
|
||||
if (this.isAlias(key) && !this.isAliasLoaded(key)) {
|
||||
this.loadedKeys.push(key);
|
||||
}
|
||||
@@ -256,6 +256,7 @@ export abstract class CachedMapResource<
|
||||
});
|
||||
|
||||
this.onDataError.execute({ param: key, exception });
|
||||
return exception as ResourceError;
|
||||
}
|
||||
|
||||
markOutdated(): void;
|
||||
@@ -405,7 +406,6 @@ export abstract class CachedMapResource<
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>> {
|
||||
await this.preLoadData(key, false, includes);
|
||||
await this.loadData(key, true, includes);
|
||||
return this.get(key) as Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>;
|
||||
}
|
||||
@@ -426,7 +426,6 @@ export abstract class CachedMapResource<
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: T
|
||||
): Promise<Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>> {
|
||||
await this.preLoadData(key, false, includes);
|
||||
await this.loadData(key, false, includes);
|
||||
return this.get(key) as Array<CachedResourceValueIncludes<TValue, T>> | CachedResourceValueIncludes<TValue, T>;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import { observable, makeObservable, action, computed, toJS } from 'mobx';
|
||||
|
||||
import { Dependency } from '@cloudbeaver/core-di';
|
||||
import { Executor, ExecutorInterrupter, IExecutor, IExecutorHandler, ISyncExecutor, SyncExecutor, TaskScheduler } from '@cloudbeaver/core-executor';
|
||||
import { ExecutionContext, Executor, ExecutorInterrupter, IExecutor, IExecutorHandler, IExecutionContextProvider, ISyncExecutor, SyncExecutor, TaskScheduler } from '@cloudbeaver/core-executor';
|
||||
import { MetadataMap, uuid } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { ResourceError } from './ResourceError';
|
||||
@@ -336,6 +336,10 @@ export abstract class CachedResource<
|
||||
|
||||
abstract isLoaded(param: TParam, context?: TContext): boolean;
|
||||
|
||||
isLoadable(param: TParam, context?: TContext): boolean {
|
||||
return !this.isLoaded(param, context) || this.isOutdated(param);
|
||||
}
|
||||
|
||||
isAlias(key: TParam): boolean {
|
||||
return this.paramAliases.some(alias => {
|
||||
if ('isEqual' in alias && alias.isEqual) {
|
||||
@@ -425,7 +429,7 @@ export abstract class CachedResource<
|
||||
});
|
||||
}
|
||||
|
||||
markDataError(exception: Error, param: TParam, context?: TContext): void {
|
||||
markDataError(exception: Error, param: TParam, context?: TContext): ResourceError {
|
||||
if (this.isAlias(param) && !this.isAliasLoaded(param)) {
|
||||
this.loadedKeys.push(param);
|
||||
}
|
||||
@@ -437,6 +441,7 @@ export abstract class CachedResource<
|
||||
metadata.outdated = false;
|
||||
});
|
||||
this.onDataError.execute({ param, exception });
|
||||
return exception as ResourceError;
|
||||
}
|
||||
|
||||
cleanError(param: TParam): void {
|
||||
@@ -532,13 +537,11 @@ export abstract class CachedResource<
|
||||
}
|
||||
|
||||
async refresh(param: TParam, context?: TContext): Promise<any> {
|
||||
await this.preLoadData(param, false, context);
|
||||
await this.loadData(param, true, context);
|
||||
return this.data;
|
||||
}
|
||||
|
||||
async load(param: TParam, context?: TContext): Promise<any> {
|
||||
await this.preLoadData(param, false, context);
|
||||
await this.loadData(param, false, context);
|
||||
return this.data;
|
||||
}
|
||||
@@ -585,7 +588,6 @@ export abstract class CachedResource<
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected setData(data: TData): void {
|
||||
@@ -721,8 +723,9 @@ export abstract class CachedResource<
|
||||
|
||||
protected async preLoadData(
|
||||
param: TParam,
|
||||
contexts: IExecutionContextProvider<TParam>,
|
||||
refresh: boolean,
|
||||
context?: TContext
|
||||
context?: TContext,
|
||||
): Promise<void> { }
|
||||
|
||||
protected async loadData(
|
||||
@@ -730,15 +733,17 @@ export abstract class CachedResource<
|
||||
refresh: boolean,
|
||||
context?: TContext
|
||||
): Promise<void> {
|
||||
const contexts = new ExecutionContext(param);
|
||||
await this.preLoadData(param, contexts, refresh, context);
|
||||
if (!refresh) {
|
||||
await this.scheduler.waitRelease(param);
|
||||
|
||||
if (this.isLoaded(param, context) && !this.isOutdated(param)) {
|
||||
if (!this.isLoadable(param, context)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const contexts = await this.beforeLoad.execute(param);
|
||||
await this.beforeLoad.execute(param, contexts);
|
||||
|
||||
if (ExecutorInterrupter.isInterrupted(contexts) && !refresh) {
|
||||
return;
|
||||
@@ -749,7 +754,7 @@ export abstract class CachedResource<
|
||||
param,
|
||||
async () => {
|
||||
// repeated because previous task maybe has been load requested data
|
||||
if (this.isLoaded(param, context) && !this.isOutdated(param)) {
|
||||
if (!this.isLoadable(param, context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user