Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/CB-4767-generate-domains-using-d…
Browse files Browse the repository at this point in the history
…eployment-manager' into fix/cb-4776/input-default-value-handling
  • Loading branch information
Wroud committed Mar 28, 2024
2 parents 74f37e2 + 1105f13 commit a328617
Show file tree
Hide file tree
Showing 36 changed files with 219 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,15 @@ import { Executor, IExecutor } from '@cloudbeaver/core-executor';
import { EAdminPermission, PermissionsService, ServerConfigResource, SessionPermissionsResource } from '@cloudbeaver/core-root';
import { RouterState, ScreenService } from '@cloudbeaver/core-routing';
import { StorageService } from '@cloudbeaver/core-storage';
import { GlobalConstants } from '@cloudbeaver/core-utils';
import { DefaultValueGetter, GlobalConstants, MetadataMap, schema } from '@cloudbeaver/core-utils';

import { AdministrationItemService } from '../AdministrationItem/AdministrationItemService';
import type { IAdministrationItemRoute } from '../AdministrationItem/IAdministrationItemRoute';
import type { IRouteParams } from '../AdministrationItem/IRouteParams';
import { ADMINISTRATION_SCREEN_STATE_SCHEMA, type IAdministrationScreenInfo } from './IAdministrationScreenState';

const ADMINISTRATION_ITEMS_STATE = 'administration_items_state';
const ADMINISTRATION_INFO = 'administration_info';

interface IAdministrationScreenInfo {
workspaceId: string;
version: string;
serverVersion: string;
configurationMode: boolean;
}

@injectable()
export class AdministrationScreenService {
static screenName = 'administration';
Expand All @@ -41,9 +34,8 @@ export class AdministrationScreenService {
static setupItemSubRouteName = 'setup.item.sub';
static setupItemSubParamRouteName = 'setup.item.sub.param';

info: IAdministrationScreenInfo;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
itemState: Map<string, any>;
readonly info: IAdministrationScreenInfo;
readonly itemState: MetadataMap<string, any>;

get isAdministrationPageActive(): boolean {
return this.isAdministrationRouteActive(this.screenService.routerService.state.name);
Expand All @@ -64,6 +56,8 @@ export class AdministrationScreenService {
readonly ensurePermissions: IExecutor;
readonly activationEvent: IExecutor<boolean>;

private itemsStateSync: Array<[string, any]>;

constructor(
private readonly permissionsResource: SessionPermissionsResource,
private readonly permissionsService: PermissionsService,
Expand All @@ -74,18 +68,46 @@ export class AdministrationScreenService {
private readonly notificationService: NotificationService,
) {
this.info = getDefaultAdministrationScreenInfo();
this.itemState = new Map();
this.itemState = new MetadataMap();
this.activationEvent = new Executor();
this.ensurePermissions = new Executor();
this.itemsStateSync = [];

makeObservable(this, {
makeObservable<this, 'itemsStateSync'>(this, {
info: observable,
itemState: observable,
itemsStateSync: observable,
activeScreen: computed,
});

this.storageService.registerSettings(ADMINISTRATION_ITEMS_STATE, this.itemState, () => new Map());
this.storageService.registerSettings(ADMINISTRATION_INFO, this.info, getDefaultAdministrationScreenInfo);
this.storageService.registerSettings(
ADMINISTRATION_INFO,
this.info,
getDefaultAdministrationScreenInfo,
data => {
const parsed = ADMINISTRATION_SCREEN_STATE_SCHEMA.safeParse(data);

if (
!parsed.success ||
parsed.data.workspaceId !== this.serverConfigResource.workspaceId ||
parsed.data.configurationMode !== this.isConfigurationMode ||
parsed.data.serverVersion !== this.serverConfigResource.serverVersion ||
parsed.data.version !== GlobalConstants.version
) {
return {
workspaceId: this.serverConfigResource.workspaceId,
configurationMode: this.isConfigurationMode,
serverVersion: this.serverConfigResource.serverVersion,
version: GlobalConstants.version || '',
itemsState: observable([], { deep: true }),
};
}

return { ...parsed.data, itemsState: observable(parsed.data.itemsState, { deep: true }) };
},
() => {
this.itemState.sync(this.itemsStateSync);
},
);
this.permissionsResource.onDataUpdate.addPostHandler(() => {
this.checkPermissions(this.screenService.routerService.state);
});
Expand Down Expand Up @@ -153,26 +175,13 @@ export class AdministrationScreenService {
}

getItemState<T>(name: string): T | undefined;
getItemState<T>(name: string, defaultState: () => T, update?: boolean, validate?: (state: T) => boolean): T;
getItemState<T>(name: string, defaultState?: () => T, update?: boolean, validate?: (state: T) => boolean): T | undefined {
getItemState<T>(name: string, defaultState: DefaultValueGetter<string, T>, schema?: schema.AnyZodObject): T;
getItemState<T>(name: string, defaultState?: DefaultValueGetter<string, T>, schema?: schema.AnyZodObject): T | undefined {
if (!this.serverConfigResource.isLoaded()) {
throw new Error('Administration screen getItemState can be used only after server configuration loaded');
}
this.validateState();

if (defaultState) {
if (!this.itemState.has(name) || update) {
this.itemState.set(name, defaultState());
} else if (validate) {
const state = this.itemState.get(name)!;

if (!validate(state)) {
this.itemState.set(name, defaultState());
}
}
}

return this.itemState.get(name);
return this.itemState.get(name, defaultState, schema);
}

clearItemsState(): void {
Expand Down Expand Up @@ -246,21 +255,6 @@ export class AdministrationScreenService {
}
}

private validateState() {
if (
this.info.workspaceId !== this.serverConfigResource.workspaceId ||
this.info.configurationMode !== this.isConfigurationMode ||
this.info.serverVersion !== this.serverConfigResource.serverVersion ||
this.info.version !== GlobalConstants.version
) {
this.clearItemsState();
this.info.workspaceId = this.serverConfigResource.workspaceId;
this.info.configurationMode = this.isConfigurationMode;
this.info.serverVersion = this.serverConfigResource.serverVersion;
this.info.version = GlobalConstants.version || '';
}
}

private async checkPermissions(state: RouterState): Promise<boolean> {
if (!this.isAdministrationRouteActive(state.name)) {
return false;
Expand Down Expand Up @@ -307,5 +301,6 @@ function getDefaultAdministrationScreenInfo(): IAdministrationScreenInfo {
version: GlobalConstants.version || '',
serverVersion: '',
configurationMode: false,
itemsState: [],
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { schema } from '@cloudbeaver/core-utils';

export const ADMINISTRATION_SCREEN_STATE_SCHEMA = schema.object({
workspaceId: schema.string(),
version: schema.string(),
serverVersion: schema.string(),
configurationMode: schema.boolean(),
itemsState: schema.array(schema.tuple([schema.string(), schema.any()])),
});

export type IAdministrationScreenInfo = schema.infer<typeof ADMINISTRATION_SCREEN_STATE_SCHEMA>;
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
display: flex;
position: absolute;
right: 24px;
z-index: 1;
margin-right: 0 !important;
}
12 changes: 5 additions & 7 deletions webapp/packages/core-blocks/src/FormControls/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ export const Form = forwardRef<HTMLFormElement, FormDetailedProps>(function Form
const formContext = useForm({
disableEnterSubmit,
parent: context,
onSubmit(event) {
const result = onSubmit?.(event);

if (result instanceof Promise) {
async onSubmit(event) {
try {
setDisabledLocal(true);
result.finally(() => {
setDisabledLocal(false);
});
await onSubmit?.(event);
} finally {
setDisabledLocal(false);
}
},
onChange,
Expand Down
4 changes: 2 additions & 2 deletions webapp/packages/core-blocks/src/FormControls/FormContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface IChangeData {
export interface IFormContext {
ref: HTMLFormElement | null;
onValidate: SyncExecutor;
onSubmit: SyncExecutor<SubmitEvent | undefined>;
onSubmit: IExecutor<SubmitEvent | undefined>;
onChange: IExecutor<IChangeData>;
parent: IFormContext | null;
disableEnterSubmit: boolean;
Expand All @@ -30,7 +30,7 @@ export interface IFormContext {
keyDown: KeyHandler;
validate: () => boolean;
reportValidity: () => boolean;
submit: (event?: SubmitEvent) => void;
submit: (event?: SubmitEvent) => Promise<void>;
}

export const FormContext = createContext<IFormContext | null>(null);
10 changes: 5 additions & 5 deletions webapp/packages/core-blocks/src/FormControls/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { FormChangeHandler, FormContext, type IChangeData, type IFormContext } f
interface IOptions {
parent?: IFormContext;
disableEnterSubmit?: boolean;
onSubmit?: (event?: SubmitEvent | undefined) => void;
onSubmit?: (event?: SubmitEvent | undefined) => Promise<void> | void;
onChange?: FormChangeHandler;
}

export function useForm(options?: IOptions): IFormContext {
let parentForm = useContext(FormContext);
const [submittingExecutor] = useState(() => new SyncExecutor<SubmitEvent | undefined>());
const [submittingExecutor] = useState(() => new Executor<SubmitEvent | undefined>());
const [validationExecutor] = useState(() => new SyncExecutor());
const [changeExecutor] = useState(() => new Executor<IChangeData>());

Expand Down Expand Up @@ -86,14 +86,14 @@ export function useForm(options?: IOptions): IFormContext {
this.submit();
}
},
submit(event) {
async submit(event) {
if (this.parent) {
this.parent.submit(event);
await this.parent.submit(event);
} else {
event?.preventDefault();

if (this.validate()) {
this.onSubmit.execute(event);
await this.onSubmit.execute(event);
}
}
},
Expand Down
21 changes: 19 additions & 2 deletions webapp/packages/core-blocks/src/Loader/useAutoLoad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
*/
import { useEffect, useState } from 'react';

import type { ILoadableState } from '@cloudbeaver/core-utils';
import { type ILoadableState, isContainsException } from '@cloudbeaver/core-utils';

import { getComputed } from '../getComputed';

export function useAutoLoad(component: { name: string }, state: ILoadableState | ReadonlyArray<ILoadableState>, enabled = true, lazy = false) {
export function useAutoLoad(
component: { name: string },
state: ILoadableState | ReadonlyArray<ILoadableState>,
enabled = true,
lazy = false,
throwExceptions = false,
) {
const [loadFunctionName] = useState(`${component.name}.useAutoLoad(...)` as const);
if (!Array.isArray(state)) {
state = [state] as ReadonlyArray<ILoadableState>;
Expand Down Expand Up @@ -50,6 +56,17 @@ export function useAutoLoad(component: { name: string }, state: ILoadableState |
throw Promise.all(promises);
}

if (throwExceptions) {
const exceptions = state
.map(loader => loader.exception)
.filter(isContainsException)
.flat();

if (exceptions.length > 0) {
throw exceptions[0];
}
}

useEffect(() => {
obj[loadFunctionName]();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ module.exports = (env, argv) => {
removeEmptyChunks: false,
splitChunks: false,
},
infrastructureLogging: {
level: 'warn',
},
devServer: {
allowedHosts: 'all',
host: 'localhost',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
*/
import type { IDataContextProvider } from './IDataContextProvider';

export type DataContextGetter<T> = (provider: IDataContextProvider) => T;
export type DataContextGetter<T> = {
(provider: IDataContextProvider): T;
id: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { uuid } from '@cloudbeaver/core-utils';

import type { DataContextGetter } from './DataContextGetter';
import type { IDataContextProvider } from './IDataContextProvider';

Expand All @@ -18,5 +20,6 @@ export function createDataContext<T>(
return defaultValue?.(context) as T;
},
};
return obj[name];
Object.defineProperty(obj[name], 'id', { value: uuid() });
return obj[name] as DataContextGetter<T>;
}
6 changes: 6 additions & 0 deletions webapp/packages/core-di/src/useController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ import type { ExtractInitArgs, IDestructibleController, IInitializableController
* @deprecated use hooks instead
*/
export function useController<T extends IInitializableController>(ctor: IServiceConstructor<T>, ...args: ExtractInitArgs<T>): T;
/**
* @deprecated use hooks instead
*/
export function useController<T>(ctor: IServiceConstructor<T>): T;
/**
* @deprecated use hooks instead
*/
export function useController<T>(ctor: IServiceConstructor<T>, ...args: any[]): T {
const app = useContext(appContext);
const controllerRef = useRef<T>();
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default [
['ui_processing_save', 'Save'],
['ui_processing_saved', 'Saved'],
['ui_processing_stop', 'Stop'],
['ui_processing_skip', 'Skip'],
['ui_second_first_form', '{arg:interval} second'],
['ui_second_second_form', '{arg:interval} seconds'],
['ui_second_third_form', '{arg:interval} seconds'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default [
['ui_processing_save', 'Salva'],
['ui_processing_saved', 'Saved'],
['ui_processing_stop', 'Stop'],
['ui_processing_skip', 'Skip'],
['ui_second_first_form', '{arg:interval} second'],
['ui_second_second_form', '{arg:interval} seconds'],
['ui_second_third_form', '{arg:interval} seconds'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default [
['ui_processing_save', 'Сохранить'],
['ui_processing_saved', 'Сохранено'],
['ui_processing_stop', 'Остановить'],
['ui_processing_skip', 'Пропустить'],
['ui_second_first_form', '{arg:interval} секунда'],
['ui_second_second_form', '{arg:interval} секунды'],
['ui_second_third_form', '{arg:interval} секунд'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default [
['ui_processing_save', '保存'],
['ui_processing_saved', 'Saved'],
['ui_processing_stop', 'Stop'],
['ui_processing_skip', 'Skip'],
['ui_second_first_form', '{arg:interval} second'],
['ui_second_second_form', '{arg:interval} seconds'],
['ui_second_third_form', '{arg:interval} seconds'],
Expand Down
6 changes: 6 additions & 0 deletions webapp/packages/core-resource/src/Resource/CachedResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SyncExecutor,
TaskScheduler,
} from '@cloudbeaver/core-executor';
import { getFirstException, isContainsException } from '@cloudbeaver/core-utils';

import {
CachedResourceOffsetPageKey,
Expand Down Expand Up @@ -684,6 +685,11 @@ export abstract class CachedResource<
}
const contexts = new ExecutionContext(key);
if (!refresh) {
const exception = this.getException(key);
if (isContainsException(exception)) {
throw getFirstException(exception);
}

if (!this.isLoadable(key, include)) {
return;
}
Expand Down
Loading

0 comments on commit a328617

Please sign in to comment.