Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-6115 Add dispose to FormState instances #3317

Merged
merged 11 commits into from
Mar 18, 2025
1 change: 1 addition & 0 deletions webapp/packages/core-ui/src/Form/FormPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
await this.load();
}

reset() {

Check warning on line 145 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
this.setState(toJS(this.initialState));
}

Expand All @@ -155,7 +155,7 @@
}
}

protected setInitialState(initialState: TPartState) {

Check warning on line 158 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
this.initialState = initialState;

if (this.isChanged) {
Expand All @@ -165,13 +165,14 @@
this.setState(toJS(this.initialState));
}

protected setState(state: TPartState) {

Check warning on line 168 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
this.state = state;
}

protected format(data: IFormState<TFormState>, contexts: IExecutionContextProvider<IFormState<TFormState>>): void | Promise<void> {}

Check warning on line 172 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'data' is defined but never used

Check warning on line 172 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'contexts' is defined but never used
protected validate(data: IFormState<TFormState>, contexts: IExecutionContextProvider<IFormState<TFormState>>): void | Promise<void> {}

Check warning on line 173 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'data' is defined but never used

Check warning on line 173 in webapp/packages/core-ui/src/Form/FormPart.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'contexts' is defined but never used

protected abstract loader(): Promise<void>;
protected abstract saveChanges(data: IFormState<TFormState>, contexts: IExecutionContextProvider<IFormState<TFormState>>): Promise<void>;
dispose(): void | Promise<void> {}
}
29 changes: 24 additions & 5 deletions webapp/packages/core-ui/src/Form/FormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
statusMessage: string | string[] | null;
statusType: ENotificationType | null;

promise: Promise<any> | null;
savingPromise: Promise<any> | null;

get isDisabled(): boolean {
return this.partsValues.some(part => part.isSaving || part?.isLoading?.());
Expand All @@ -48,6 +48,7 @@
readonly submitTask: IExecutor<IFormState<TState>>;
readonly formatTask: IExecutor<IFormState<TState>>;
readonly validationTask: IExecutor<IFormState<TState>>;
readonly disposeTask: IExecutor<IFormState<TState>>;

constructor(serviceProvider: IServiceProvider, service: FormBaseService<TState, any>, state: TState) {
this.id = uuid();
Expand All @@ -61,7 +62,7 @@
this.statusMessage = null;
this.statusType = null;

this.promise = null;
this.savingPromise = null;

this.formStateTask = new Executor<TState>(state, () => true);
this.formStateTask.addCollection(service.onState).addPostHandler(this.updateFormState.bind(this));
Expand All @@ -78,14 +79,16 @@
this.submitTask = new Executor(this as IFormState<TState>, () => true);
this.submitTask.addCollection(service.onSubmit).before(this.validationTask);

this.disposeTask = new Executor(this as IFormState<TState>, () => true);

this.dataContext.set(DATA_CONTEXT_LOADABLE_STATE, loadableStateContext(), this.id);
this.dataContext.set(DATA_CONTEXT_FORM_STATE, this, this.id);
dataContextAddDIProvider(this.dataContext, serviceProvider, this.id);

makeObservable<this, 'updateFormState'>(this, {
mode: observable,
parts: observable.ref,
promise: observable.ref,
savingPromise: observable.ref,
state: observable,
isSaving: computed,
exception: computed,
Expand All @@ -103,7 +106,7 @@
});
}

get partsValues() {

Check warning on line 109 in webapp/packages/core-ui/src/Form/FormState.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
return Array.from(this.parts.values());
}

Expand Down Expand Up @@ -171,14 +174,18 @@

async save(): Promise<boolean> {
try {
const context = await this.submitTask.execute(this);
this.savingPromise = this.submitTask.execute(this);
const context = await this.savingPromise;

if (ExecutorInterrupter.isInterrupted(context)) {
return false;
}

return true;
} catch (exception: any) {}
} catch (exception: any) {

Check warning on line 185 in webapp/packages/core-ui/src/Form/FormState.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'exception' is defined but never used
} finally {
this.savingPromise = null;
}

return false;
}
Expand All @@ -202,4 +209,16 @@
this.statusMessage = context.statusMessage;
this.statusType = context.statusType;
}

async dispose(): Promise<void> {
if (this.savingPromise) {
await this.savingPromise;
}

for (const part of this.parts.values()) {
await part.dispose();
}

await this.disposeTask.execute(this);
}
}
1 change: 1 addition & 0 deletions webapp/packages/core-ui/src/Form/IFormPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ export interface IFormPart<TState> extends ILoadableState {

load(): Promise<void>;
reset(): void;
dispose(): void | Promise<void>;
}
3 changes: 2 additions & 1 deletion webapp/packages/core-ui/src/Form/IFormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface IFormState<TState> {
readonly isDisabled: boolean;
readonly exception: Error | (Error | null)[] | null;

readonly promise: Promise<any> | null;
readonly savingPromise: Promise<any> | null;

readonly statusMessage: string | string[] | null;
readonly statusType: ENotificationType | null;
Expand All @@ -49,4 +49,5 @@ export interface IFormState<TState> {
save(): Promise<boolean>;
reset(): void;
cancel(): void;
dispose(): void | Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -95,6 +95,7 @@ export class ConfigurationWizardPagesBootstrapService extends Bootstrap {
onLoad: () => {
this.serverConfigurationFormStateManager.create();
},
onDeActivate: this.serverConfigurationFormStateManager.destroy.bind(this.serverConfigurationFormStateManager),
canDeActivate: async configurationWizard => {
const state = this.serverConfigurationFormStateManager.formState;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand All @@ -27,7 +27,7 @@
});
}

create() {

Check warning on line 30 in webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/ServerConfigurationFormStateManager.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
if (this.formState) {
return this.formState;
}
Expand All @@ -38,6 +38,7 @@

destroy() {
if (this.formState) {
this.formState?.dispose();
this.formState = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useRef } from 'react';
import { useEffect, useRef } from 'react';

import { IServiceProvider, useService } from '@cloudbeaver/core-di';

Expand All @@ -18,11 +18,19 @@ export function useTeamsAdministrationFormState(id: string | null, configure?: (
const ref = useRef<null | TeamsAdministrationFormState>(null);

if (ref.current?.state.teamId !== id) {
ref.current?.dispose();
ref.current = new TeamsAdministrationFormState(serviceProvider, service, {
teamId: id,
});
configure?.(ref.current);
}

useEffect(
() => () => {
ref.current?.dispose();
},
[],
);

return ref.current;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,6 +39,7 @@ export class CreateTeamService {
}

fillData(): void {
this.dispose();
this.data = new TeamsAdministrationFormState(this.serviceProvider, this.service, {
teamId: null,
});
Expand All @@ -47,4 +48,9 @@ export class CreateTeamService {
create(): void {
this.teamsAdministrationNavService.navToCreate();
}

dispose() {
this.data?.dispose();
this.data = null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -59,16 +59,12 @@ export class UsersAdministrationService extends Bootstrap {
},
{
name: EUsersAdministrationSub.Users,
onDeActivate: this.cancelCreate.bind(this),
onDeActivate: this.cancelUserCreate.bind(this),
},
{
name: EUsersAdministrationSub.Teams,
onActivate: this.loadTeams.bind(this),
onDeActivate: (param, configurationWizard, outside) => {
if (outside) {
this.teamsResource.cleanNewFlags();
}
},
onDeActivate: this.cancelTeamCreate.bind(this),
},
],
defaultSub: EUsersAdministrationSub.Users,
Expand All @@ -78,7 +74,7 @@ export class UsersAdministrationService extends Bootstrap {
this.userDetailsInfoPlaceholder.add(UserCredentialsList, 0);
}

private async cancelCreate(param: string | null, configurationWizard: boolean, outside: boolean) {
private cancelUserCreate(param: string | null, configurationWizard: boolean, outside: boolean) {
if (param === 'create') {
this.createUserService.close();
}
Expand All @@ -88,7 +84,17 @@ export class UsersAdministrationService extends Bootstrap {
}
}

private async loadTeams(param: string | null) {
private cancelTeamCreate(param: string | null, configurationWizard: boolean, outside: boolean) {
if (param === 'create') {
this.createTeamService.dispose();
}

if (outside) {
this.teamsResource.cleanNewFlags();
}
}

private loadTeams(param: string | null) {
if (param === 'create') {
this.createTeamService.fillData();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -55,6 +55,7 @@ export class CreateUserService {
}

clearUserTemplate(): void {
this.state?.dispose();
this.state = null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useRef } from 'react';

import { useEffect, useRef } from 'react';

import { IServiceProvider, useService } from '@cloudbeaver/core-di';

Expand All @@ -17,12 +18,20 @@ export function useAdministrationUserFormState(id: string | null, configure?: (s
const serviceProvider = useService(IServiceProvider);
const ref = useRef<null | AdministrationUserFormState>(null);

if (ref.current?.id !== id) {
if (ref.current?.state.userId !== id) {
ref.current?.dispose();
ref.current = new AdministrationUserFormState(serviceProvider, service, {
userId: id,
});
configure?.(ref.current);
}

useEffect(
() => () => {
ref.current?.dispose();
},
[],
);

return ref.current;
}
Loading