mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-13 07:47:05 +08:00
Merge branch 'devel' into CB-4356-create-smart-tabs-switchingng-for-forms
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
<resource name="drivers/postgresql"/>
|
||||
<resource name="drivers/clickhouse"/>
|
||||
<resource name="drivers/clickhouse_com"/>
|
||||
<resource name="drivers/derby"/>
|
||||
<resource name="drivers/jaybird"/>
|
||||
<resource name="drivers/h2"/>
|
||||
<resource name="drivers/h2_v2"/>
|
||||
@@ -29,7 +28,6 @@
|
||||
<bundle id="drivers.postgresql" label="PostgreSQL drivers"/>
|
||||
<bundle id="drivers.clickhouse" label="Clickhouse (legacy) drivers"/>
|
||||
<bundle id="drivers.clickhouse_com" label="Clickhouse drivers"/>
|
||||
<bundle id="drivers.derby" label="Derby drivers"/>
|
||||
<bundle id="drivers.firebird" label="Firebird drivers"/>
|
||||
<bundle id="drivers.h2" label="H2 drivers"/>
|
||||
<bundle id="drivers.h2_v2" label="H2 v2 drivers"/>
|
||||
@@ -49,7 +47,6 @@
|
||||
<driver id="jaybird:jaybird"/>
|
||||
<driver id="clickhouse:yandex_clickhouse"/>
|
||||
<driver id="clickhouse:com_clickhouse"/>
|
||||
<driver id="generic:derby_server"/>
|
||||
<driver id="h2:h2_embedded"/>
|
||||
<driver id="h2:h2_embedded_v2"/>
|
||||
<driver id="sqlite:sqlite_jdbc"/>
|
||||
|
||||
@@ -95,6 +95,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
|
||||
* In configuration mode sessions expire after a week
|
||||
*/
|
||||
private static final long CONFIGURATION_MODE_SESSION_IDLE_TIME = 60 * 60 * 1000 * 24 * 7;
|
||||
public static final String HOST_LOCALHOST = "localhost";
|
||||
public static final String HOST_127_0_0_1 = "127.0.0.1";
|
||||
|
||||
|
||||
static {
|
||||
@@ -262,9 +264,9 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
|
||||
if (CommonUtils.isEmpty(localHostAddress)) {
|
||||
localHostAddress = System.getProperty(CBConstants.VAR_CB_LOCAL_HOST_ADDR);
|
||||
}
|
||||
if (CommonUtils.isEmpty(localHostAddress) || "127.0.0.1".equals(localHostAddress) || "::0".equals(
|
||||
if (CommonUtils.isEmpty(localHostAddress) || HOST_127_0_0_1.equals(localHostAddress) || "::0".equals(
|
||||
localHostAddress)) {
|
||||
localHostAddress = "localhost";
|
||||
localHostAddress = HOST_LOCALHOST;
|
||||
}
|
||||
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
@@ -563,7 +565,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
log.debug("Error resolving localhost address: " + e.getMessage());
|
||||
hostName = "localhost";
|
||||
hostName = HOST_LOCALHOST;
|
||||
}
|
||||
}
|
||||
serverURL = "http://" + hostName + ":" + serverPort;
|
||||
@@ -611,7 +613,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
|
||||
}
|
||||
}
|
||||
parseAdditionalConfiguration(configProps);
|
||||
} catch (DBException e) {
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error parsing server configuration", e);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,4 +25,8 @@ public class CBPlatformUI extends ConsoleUserInterface {
|
||||
|
||||
public static final CBPlatformUI INSTANCE = new CBPlatformUI();
|
||||
|
||||
protected void initialize() {
|
||||
// just a placeholder for injection
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -465,6 +465,7 @@ public class CBDatabase {
|
||||
} catch (UnknownHostException e) {
|
||||
hostName = "localhost";
|
||||
}
|
||||
|
||||
byte[] hardwareAddress = RuntimeUtils.getLocalMacAddress();
|
||||
String macAddress = CommonUtils.toHexString(hardwareAddress);
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>drivers.derby</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<parent>
|
||||
<groupId>io.cloudbeaver</groupId>
|
||||
<artifactId>drivers</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<deps.output.dir>derby</deps.output.dir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
<version>10.15.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbytools</artifactId>
|
||||
<version>10.15.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbyshared</artifactId>
|
||||
<version>10.15.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbyclient</artifactId>
|
||||
<version>10.15.1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -15,7 +15,6 @@
|
||||
<module>clickhouse_com</module>
|
||||
<module>db2</module>
|
||||
<module>db2-jt400</module>
|
||||
<module>derby</module>
|
||||
<module>h2</module>
|
||||
<module>h2_v2</module>
|
||||
<module>jaybird</module>
|
||||
|
||||
+12
-12
@@ -16,17 +16,17 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/dom": "^9.3.3",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/react": "^18.2.25",
|
||||
"@types/react-dom": "^18.2.11",
|
||||
"concurrently": "^8.2.1",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/react": "^18.2.42",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"concurrently": "^8.2.2",
|
||||
"lerna": "5.5.4",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"msw": "^1.3.2",
|
||||
"msw": "^2.0.10",
|
||||
"path-browserify": "~1.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
"react": "^18.2.0",
|
||||
@@ -34,9 +34,9 @@
|
||||
"reakit": "~1.3.11",
|
||||
"reflect-metadata": "~0.1.13",
|
||||
"reshadow": "^0.0.1",
|
||||
"rimraf": "~5.0.1",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"rimraf": "~5.0.5",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
},
|
||||
"dependencies": {},
|
||||
"prettier": "@cloudbeaver/prettier-config"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
@@ -46,8 +46,8 @@
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -45,9 +45,9 @@
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"msw": "~1.x.x",
|
||||
"typescript": "^5.2.2"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"msw": "~2.x.x",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -5,18 +5,18 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import type { GraphQLContext, GraphQLRequest, ResponseComposition } from 'msw';
|
||||
import { GraphQLResolverExtras, GraphQLResponseBody, HttpResponse, ResponseResolver } from 'msw';
|
||||
|
||||
import type { GetActiveUserQuery, GetActiveUserQueryVariables } from '@cloudbeaver/core-sdk';
|
||||
|
||||
export function mockGetActiveUser(
|
||||
req: GraphQLRequest<GetActiveUserQueryVariables>,
|
||||
res: ResponseComposition<GetActiveUserQuery>,
|
||||
ctx: GraphQLContext<GetActiveUserQuery>,
|
||||
): ReturnType<ResponseComposition<GetActiveUserQuery>> {
|
||||
return res(
|
||||
ctx.data({
|
||||
export const mockGetActiveUser: ResponseResolver<
|
||||
GraphQLResolverExtras<GetActiveUserQueryVariables>,
|
||||
null,
|
||||
GraphQLResponseBody<GetActiveUserQuery>
|
||||
> = function mockGetActiveUser() {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
user: null as unknown as undefined,
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"go-split": "^3.4.1",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reakit": "~1.x.x",
|
||||
@@ -49,12 +49,12 @@
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/react": "^18.2.25",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/react": "^18.2.42",
|
||||
"react": "^18.2.0",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,13 @@ import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { getComputed } from '../getComputed';
|
||||
|
||||
export interface IAutoLoadable extends ILoadableState {
|
||||
load: () => void;
|
||||
}
|
||||
|
||||
export function useAutoLoad(component: { name: string }, state: IAutoLoadable | IAutoLoadable[], enabled = true, lazy = false) {
|
||||
export function useAutoLoad(component: { name: string }, state: ILoadableState | ILoadableState[], enabled = true, lazy = false) {
|
||||
const [loadFunctionName] = useState(`${component.name}.useAutoLoad(...)` as const);
|
||||
if (!Array.isArray(state)) {
|
||||
state = [state];
|
||||
}
|
||||
|
||||
for (const loader of state as IAutoLoadable[]) {
|
||||
for (const loader of state as ILoadableState[]) {
|
||||
getComputed(
|
||||
// activate mobx subscriptions
|
||||
() => (!loader.isLoaded() || loader.isOutdated?.() === true) && !loader.isError(),
|
||||
@@ -29,18 +25,20 @@ export function useAutoLoad(component: { name: string }, state: IAutoLoadable |
|
||||
}
|
||||
|
||||
const obj = {
|
||||
[loadFunctionName]: () => {
|
||||
[loadFunctionName]: async () => {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const loader of state as IAutoLoadable[]) {
|
||||
for (const loader of state as ILoadableState[]) {
|
||||
if (loader.isError() || (loader.lazy === true && !lazy)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!loader.isLoaded() || loader.isOutdated?.() === true) {
|
||||
loader.load();
|
||||
try {
|
||||
await loader.load();
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -45,14 +45,14 @@
|
||||
"@cloudbeaver/core-version": "~0.1.0",
|
||||
"@cloudbeaver/core-version-update": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,6 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ const path = require('path');
|
||||
|
||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
testEnvironment: 'jsdom',
|
||||
testEnvironment: require.resolve('../tests/test.environment.js'),
|
||||
rootDir: path.resolve('./dist'),
|
||||
moduleFileExtensions: ['js', 'jsx', 'json'],
|
||||
testMatch: ['**/?(*.)+(spec|test).js?(x)'],
|
||||
@@ -28,4 +28,9 @@ module.exports = {
|
||||
transform: {
|
||||
'\\.jsx?$': ['babel-jest', { configFile: require.resolve('./jest.babel.config.js') }],
|
||||
},
|
||||
testEnvironmentOptions: {
|
||||
// This will force JSDOM to use the default export condition when importing msw/node, resulting in correct imports.
|
||||
// https://mswjs.io/docs/migrations/1.x-to-2.x#cannot-find-module-mswnode-jsdom
|
||||
customExportConditions: [''],
|
||||
},
|
||||
};
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
declare module '*.scss?raw' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.json5' {
|
||||
const json: any;
|
||||
export default json;
|
||||
}
|
||||
|
||||
declare module '*.scss' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.m.css' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.css?raw' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
Vendored
+2
-82
@@ -1,84 +1,4 @@
|
||||
/* eslint-disable */
|
||||
/// <reference path="../../node_modules/reshadow/elements.d.ts" />
|
||||
|
||||
declare module '*.scss?raw' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.json5' {
|
||||
const json: any;
|
||||
export default json;
|
||||
}
|
||||
|
||||
declare module '*.scss' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.m.css' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.css?raw' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module 'reshadow' {
|
||||
import { createElement, Component } from 'react';
|
||||
|
||||
type StylesMap = { [key: string]: any };
|
||||
|
||||
type IdFunction = <A extends JSX.Element>(node: A) => A;
|
||||
|
||||
declare function taggedStyled(strs: TemplateStringsArray, ...values: any[]): IdFunction;
|
||||
declare function taggedStyled<A extends JSX.Element>(node: A): A;
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated use css-modules instead
|
||||
*/
|
||||
declare function styled(...styles: StylesMap[]): typeof taggedStyled;
|
||||
/**
|
||||
*
|
||||
* @deprecated use css-modules instead
|
||||
*/
|
||||
declare function styled(strs: TemplateStringsArray, ...values: any[]): IdFunction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated use css-modules instead
|
||||
*/
|
||||
export declare var use: ((value: StylesMap) => {}) & {
|
||||
[key: string]: typeof Component;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated use css-modules instead
|
||||
*/
|
||||
export declare function css(strs: TemplateStringsArray, ...values: any[]): StylesMap;
|
||||
export declare function keyframes(strs: TemplateStringsArray, ...values: any[]): string;
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated use css-modules instead
|
||||
*/
|
||||
export declare function create(styles: StylesMap[]): StylesMap;
|
||||
|
||||
declare var jsx: typeof createElement;
|
||||
|
||||
export default styled;
|
||||
}
|
||||
/// <reference path="./msw.d.ts" />
|
||||
/// <reference path="./css-modules.d.ts" />
|
||||
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 { GraphQLError } from 'graphql';
|
||||
import { DefaultBodyType, GraphQLVariables } from 'msw';
|
||||
|
||||
// types are not exported: https://github.com/mswjs/msw/pull/1826
|
||||
declare module 'msw' {
|
||||
export type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
|
||||
query: string;
|
||||
operationName: string;
|
||||
variables: Variables;
|
||||
cookies: Record<string, string>;
|
||||
};
|
||||
|
||||
export interface GraphQLResponseBody<BodyType extends DefaultBodyType> {
|
||||
data?: BodyType | null;
|
||||
errors?: readonly Partial<GraphQLError>[] | null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
const Environment = require('jest-environment-jsdom').default;
|
||||
|
||||
/**
|
||||
JSDOM does not have an implementation for TextDecoder / TextEncoder present on their globals
|
||||
and therefore not only are they not found, but you can't add them without access to their global context inside the VM.
|
||||
MSW 2.0 related issue.
|
||||
*/
|
||||
module.exports = class CustomTestEnvironment extends Environment {
|
||||
async setup() {
|
||||
await super.setup();
|
||||
this.global.TextEncoder = TextEncoder;
|
||||
this.global.TextDecoder = TextDecoder;
|
||||
this.global.Response = Response;
|
||||
this.global.Request = Request;
|
||||
}
|
||||
};
|
||||
@@ -33,11 +33,11 @@
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-executor": "~0.1.0",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify": "^6.0.2",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"@types/jest": "^29.5.5"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"@types/jest": "^29.5.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-localization": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"@cloudbeaver/core-plugin": "~0.1.0",
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -32,8 +32,8 @@
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,8 +194,6 @@ export class NotificationService {
|
||||
isSilent: silent,
|
||||
});
|
||||
}
|
||||
|
||||
console.error(exception);
|
||||
}
|
||||
|
||||
throwSilently(exception: Error | GQLError | undefined | null): void {
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
"update-ts-references": "rimraf --glob dist && typescript-resolve-references"
|
||||
},
|
||||
"dependencies": {
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"dependencies": {},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -37,8 +37,8 @@
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ export default [
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
['ui_disable', 'Disable'],
|
||||
['ui_readonly', 'Read-only'],
|
||||
['ui_test', 'Test'],
|
||||
|
||||
['root_permission_denied', "You don't have permissions"],
|
||||
|
||||
@@ -92,6 +92,7 @@ export default [
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
['ui_disable', 'Disable'],
|
||||
['ui_readonly', 'In sola lettura'],
|
||||
['ui_test', 'Test'],
|
||||
|
||||
['root_permission_denied', 'Non hai i permessi'],
|
||||
|
||||
@@ -104,6 +104,7 @@ export default [
|
||||
['ui_upload_file_fail', 'Не удалось загрузить файл'],
|
||||
['ui_filter', 'Фильтр'],
|
||||
['ui_disable', 'Отключить'],
|
||||
['ui_readonly', 'Доступно только для чтения'],
|
||||
['ui_test', 'Проверить'],
|
||||
|
||||
['root_permission_denied', 'Отказано в доступе'],
|
||||
|
||||
@@ -105,6 +105,7 @@ export default [
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
['ui_disable', 'Disable'],
|
||||
['ui_readonly', '只读'],
|
||||
['ui_test', 'Test'],
|
||||
|
||||
['root_permission_denied', '您没有权限'],
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-ui": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -51,8 +51,8 @@
|
||||
"@cloudbeaver/core-ui": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "~0.1.0",
|
||||
"@cloudbeaver/core-events": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reakit": "~1.x.x",
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-ui": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-executor": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.5",
|
||||
"mobx": "^6.10.2",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/jest": "^29.5.10",
|
||||
"mobx": "^6.12.0",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@cloudbeaver/core-sdk": "~0.1.0",
|
||||
"@types/jest": "^29.5.5",
|
||||
"msw": "~1.x.x",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/jest": "^29.5.10",
|
||||
"msw": "~2.x.x",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,8 @@
|
||||
*/
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { Executor, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { EServerErrorCode, GQLError, GraphQLService } from '@cloudbeaver/core-sdk';
|
||||
import { EServerErrorCode, GQLError, GraphQLService, SessionError } from '@cloudbeaver/core-sdk';
|
||||
import { errorOf } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { SessionError } from './SessionError';
|
||||
|
||||
@injectable()
|
||||
export class SessionExpireService extends Bootstrap {
|
||||
expired = false;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { rest } from 'msw';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
// TODO: use new msw API https://github.com/mswjs/msw/issues/156
|
||||
export function createWebsocketEndpoint(): ReturnType<typeof rest.get> {
|
||||
return rest.get('http://localhost/api/ws', (req, res, ctx) => res(ctx.status(404)));
|
||||
export function createWebsocketEndpoint(): ReturnType<typeof http.get> {
|
||||
return http.get('http://localhost/api/ws', () => new HttpResponse(null, { status: 404 }));
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import type { GraphQLRequest, RequestHandler } from 'msw';
|
||||
import type { GraphQLHandler } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
import { createWebsocketEndpoint } from './createWebsocketEndpoint';
|
||||
|
||||
export function mockGraphQL(...requestHandlers: RequestHandler<any, GraphQLRequest<any>, any, GraphQLRequest<any>>[]) {
|
||||
export function mockGraphQL(...requestHandlers: GraphQLHandler[]) {
|
||||
const server = setupServer(...requestHandlers, createWebsocketEndpoint());
|
||||
|
||||
beforeAll(() => server.listen());
|
||||
|
||||
@@ -5,27 +5,28 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import type { GraphQLContext, GraphQLRequest, ResponseComposition } from 'msw';
|
||||
import { GraphQLResolverExtras, GraphQLResponseBody, HttpResponse, ResponseResolver } from 'msw';
|
||||
|
||||
import type { OpenSessionMutation, OpenSessionMutationVariables } from '@cloudbeaver/core-sdk';
|
||||
|
||||
export function mockOpenSession(
|
||||
req: GraphQLRequest<OpenSessionMutationVariables>,
|
||||
res: ResponseComposition<OpenSessionMutation>,
|
||||
ctx: GraphQLContext<OpenSessionMutation>,
|
||||
) {
|
||||
export const mockOpenSession: ResponseResolver<
|
||||
GraphQLResolverExtras<OpenSessionMutationVariables>,
|
||||
null,
|
||||
GraphQLResponseBody<OpenSessionMutation>
|
||||
> = function mockOpenSession(info) {
|
||||
const date = new Date().toISOString();
|
||||
return res(
|
||||
ctx.data({
|
||||
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
session: {
|
||||
valid: true,
|
||||
remainingTime: 0,
|
||||
createTime: date,
|
||||
lastAccessTime: date,
|
||||
cacheExpired: false,
|
||||
locale: req.variables.defaultLocale ?? 'en',
|
||||
locale: info.variables.defaultLocale ?? 'en',
|
||||
actionParameters: null,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -5,18 +5,16 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import type { GraphQLContext, GraphQLRequest, ResponseComposition } from 'msw';
|
||||
import { GraphQLResolverExtras, GraphQLResponseBody, HttpResponse, ResponseResolver } from 'msw';
|
||||
|
||||
import type { ServerConfigQuery, ServerConfigQueryVariables } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { defaultServerConfig } from '../data/defaultServerConfig';
|
||||
|
||||
export function mockServerConfig(productConfiguration?: Record<string, any>) {
|
||||
return function mockServerConfig(
|
||||
req: GraphQLRequest<ServerConfigQueryVariables>,
|
||||
res: ResponseComposition<ServerConfigQuery>,
|
||||
ctx: GraphQLContext<ServerConfigQuery>,
|
||||
) {
|
||||
return res(ctx.data(defaultServerConfig(productConfiguration)));
|
||||
export function mockServerConfig(
|
||||
productConfiguration?: Record<string, any>,
|
||||
): ResponseResolver<GraphQLResolverExtras<ServerConfigQueryVariables>, null, GraphQLResponseBody<ServerConfigQuery>> {
|
||||
return function mockServerConfig() {
|
||||
return HttpResponse.json({ data: defaultServerConfig(productConfiguration) });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-executor": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"router5": "^8.0.1",
|
||||
"router5-plugin-browser": "^8.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,21 +23,21 @@
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"axios": "^1.6.0",
|
||||
"axios": "^1.6.2",
|
||||
"graphql-request": "^6.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "~5.0.0",
|
||||
"@graphql-codegen/cli": "~5.0.0",
|
||||
"@graphql-codegen/near-operation-file-preset": "~2.5.0",
|
||||
"@graphql-codegen/near-operation-file-preset": "~3.0.0",
|
||||
"@graphql-codegen/typescript": "~4.0.1",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "~2.2.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "~5.0.0",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "~3.0.0",
|
||||
"@graphql-codegen/typescript-graphql-request": "~6.0.1",
|
||||
"@graphql-codegen/typescript-operations": "~4.0.1",
|
||||
"@parcel/watcher": "~2.3.0",
|
||||
"graphql": "^16.8.1",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ export * from './isObjectPropertyInfoStateEqual';
|
||||
export * from './sdk';
|
||||
export * from './ServerInternalError';
|
||||
export * from './ServiceError';
|
||||
export * from './SessionError';
|
||||
export * from './manifest';
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-executor": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
"dependencies": {
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"@cloudbeaver/core-executor": "~0.1.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@cloudbeaver/core-plugin": "~0.1.0",
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-settings": "~0.1.0",
|
||||
"mobx": "^6.10.2"
|
||||
"mobx": "^6.12.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -48,9 +48,9 @@
|
||||
"@material/switch": "~4.0.0",
|
||||
"@material/theme": "~4.0.0",
|
||||
"@material/typography": "~4.0.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
@@ -39,8 +39,8 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,20 @@
|
||||
"update-ts-references": "rimraf --glob dist && typescript-resolve-references"
|
||||
},
|
||||
"dependencies": {
|
||||
"@timohausmann/quadtree-ts": "^2.0.0-beta.1",
|
||||
"@timohausmann/quadtree-ts": "2.0.0-beta.1",
|
||||
"clsx": "^2.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"md5": "^2.3.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"underscore": "^1.13.6",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/md5": "~2.3.2",
|
||||
"@types/uuid": "~9.0.3",
|
||||
"@types/underscore": "^1.11.9",
|
||||
"typescript": "^5.2.2",
|
||||
"@types/jest": "^29.5.5"
|
||||
"@types/md5": "~2.3.5",
|
||||
"@types/uuid": "~9.0.7",
|
||||
"@types/underscore": "^1.11.15",
|
||||
"typescript": "^5.3.2",
|
||||
"@types/jest": "^29.5.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
"@cloudbeaver/core-di": "~0.1.0",
|
||||
"@cloudbeaver/core-localization": "~0.1.0",
|
||||
"@cloudbeaver/core-version": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/semver": "~7.5.1",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/semver": "~7.5.6",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
"@cloudbeaver/core-resource": "~0.1.0",
|
||||
"@cloudbeaver/core-root": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@cloudbeaver/core-localization": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"react-hotkeys-hook": "^4.4.1",
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
],
|
||||
"type": "commonjs",
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "~6.7.2",
|
||||
"@typescript-eslint/parser": "~6.7.2",
|
||||
"eslint": "~8.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "~6.13.2",
|
||||
"@typescript-eslint/parser": "~6.13.2",
|
||||
"eslint": "~8.55.0",
|
||||
"eslint-config-airbnb-base": "~15.0.0",
|
||||
"eslint-config-airbnb-typescript": "~17.1.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-import": "~2.28.1",
|
||||
"eslint-plugin-jest": "~27.4.0",
|
||||
"eslint-plugin-jsx-a11y": "~6.7.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "~2.29.0",
|
||||
"eslint-plugin-jest": "~27.6.0",
|
||||
"eslint-plugin-jsx-a11y": "~6.8.0",
|
||||
"eslint-plugin-node": "~11.1.0",
|
||||
"eslint-plugin-promise": "~6.1.1",
|
||||
"eslint-plugin-react": "~7.33.2",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "~0.1.0",
|
||||
"@cloudbeaver/plugin-top-app-bar": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1",
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,15 +36,15 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-administration": "~0.1.0",
|
||||
"@cloudbeaver/plugin-authentication": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,15 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-administration": "~0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import { AuthProviderForm } from './AuthProviderForm/AuthProviderForm';
|
||||
import { ConfigurationsList } from './AuthProviderForm/ConfigurationsList';
|
||||
import { FEDERATED_AUTH } from './FEDERATED_AUTH';
|
||||
import { getAuthProviderTabId, useAuthDialogState } from './useAuthDialogState';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
|
||||
export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function AuthDialog({
|
||||
payload: { providerId, configurationId, linkUser = false, accessRequest = false },
|
||||
@@ -49,6 +50,7 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
|
||||
const authenticationService = useService(AuthenticationService);
|
||||
const userInfo = useService(UserInfoResource);
|
||||
const commonDialogService = useService(CommonDialogService);
|
||||
const notificationService = useService(NotificationService);
|
||||
const translate = useTranslate();
|
||||
const state = dialogData.state;
|
||||
|
||||
@@ -86,8 +88,10 @@ export const AuthDialog: DialogComponent<IAuthOptions, null> = observer(function
|
||||
}
|
||||
|
||||
async function login(linkUser: boolean, provider?: AuthProvider, configuration?: AuthProviderConfiguration) {
|
||||
await dialogData.login(linkUser, provider, configuration);
|
||||
rejectDialog();
|
||||
try {
|
||||
await dialogData.login(linkUser, provider, configuration);
|
||||
rejectDialog();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function navToSettings() {
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
"@cloudbeaver/core-blocks": "~0.1.0",
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@codemirror/autocomplete": "6.9.0",
|
||||
"@codemirror/commands": "6.2.5",
|
||||
"@codemirror/lang-html": "6.4.6",
|
||||
"@codemirror/autocomplete": "6.11.1",
|
||||
"@codemirror/commands": "6.3.2",
|
||||
"@codemirror/lang-html": "6.4.7",
|
||||
"@codemirror/lang-javascript": "6.2.1",
|
||||
"@codemirror/lang-json": "6.0.1",
|
||||
"@codemirror/lang-sql": "6.5.4",
|
||||
"@codemirror/lang-xml": "6.0.2",
|
||||
"@codemirror/language": "6.9.0",
|
||||
"@codemirror/merge": "6.1.2",
|
||||
"@codemirror/search": "6.5.2",
|
||||
"@codemirror/state": "6.2.1",
|
||||
"@codemirror/view": "6.18.0",
|
||||
"@lezer/highlight": "^1.1.6",
|
||||
"@codemirror/language": "6.9.3",
|
||||
"@codemirror/merge": "6.3.1",
|
||||
"@codemirror/search": "6.5.5",
|
||||
"@codemirror/state": "6.3.3",
|
||||
"@codemirror/view": "6.22.1",
|
||||
"@lezer/highlight": "^1.2.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -41,8 +41,8 @@
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@cloudbeaver/core-theming": "~0.1.0",
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { forwardRef } from 'react';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { clsx } from '@cloudbeaver/core-utils';
|
||||
import { s, useS } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import type { IEditorProps } from './IEditorProps';
|
||||
import type { IEditorRef } from './IEditorRef';
|
||||
@@ -41,9 +40,9 @@ export const Editor = observer<IEditorProps & IDefaultExtensions, IEditorRef>(
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
useS(EDITOR_BASE_STYLES);
|
||||
extensions = useCodemirrorExtensions(extensions);
|
||||
|
||||
|
||||
const defaultExtensions = useEditorDefaultExtensions({
|
||||
lineNumbers,
|
||||
tooltips,
|
||||
@@ -64,10 +63,11 @@ export const Editor = observer<IEditorProps & IDefaultExtensions, IEditorRef>(
|
||||
|
||||
extensions.set(...defaultExtensions);
|
||||
|
||||
return styled(EDITOR_BASE_STYLES)(
|
||||
<wrapper className={clsx('editor', rest.className)}>
|
||||
return (
|
||||
// all styles is global scoped so we can't get them from module
|
||||
<div className={s({ editor: 'editor' }, { editor: true }, rest.className)}>
|
||||
<ReactCodemirror {...rest} ref={ref} extensions={extensions} />
|
||||
</wrapper>,
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 { RangeSet, RangeValue } from '@codemirror/state';
|
||||
|
||||
import type { IHyperlinkInfo } from './IHyperlinkInfo';
|
||||
|
||||
export const enum HyperlinkState {
|
||||
Inactive,
|
||||
Pending,
|
||||
Result,
|
||||
}
|
||||
|
||||
export type HyperlinkSet = RangeSet<Hyperlink>;
|
||||
|
||||
export class Hyperlink extends RangeValue {
|
||||
hyperlink: IHyperlinkInfo | null;
|
||||
state: HyperlinkState;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.hyperlink = null;
|
||||
this.state = HyperlinkState.Inactive;
|
||||
}
|
||||
|
||||
static create() {
|
||||
return new Hyperlink();
|
||||
}
|
||||
|
||||
static get none(): HyperlinkSet {
|
||||
return RangeSet.of<Hyperlink>([]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 type { SelectionRange } from '@codemirror/state';
|
||||
|
||||
import type { IHyperlinkInfo } from './IHyperlinkInfo';
|
||||
|
||||
export type HyperlinkLoader = (pos: SelectionRange) => Promise<IHyperlinkInfo | null>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export interface IHyperlinkInfo {
|
||||
tooltip?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 { combineConfig, Compartment, EditorState, Extension, Facet, Range, SelectionRange, StateEffect, StateField } from '@codemirror/state';
|
||||
import { Decoration, EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view';
|
||||
|
||||
import { Hyperlink, HyperlinkState } from './Hyperlink';
|
||||
import type { HyperlinkLoader } from './HyperlinkLoader';
|
||||
import type { IHyperlinkInfo } from './IHyperlinkInfo';
|
||||
|
||||
export interface HyperlinksConfig {
|
||||
loadLinkInfo: HyperlinkLoader;
|
||||
}
|
||||
|
||||
export const hyperlinksConfig = Facet.define<HyperlinksConfig, Required<HyperlinksConfig>>({
|
||||
combine(configs) {
|
||||
return combineConfig<Required<HyperlinksConfig>>(configs, {
|
||||
loadLinkInfo: () => Promise.resolve(null),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const metaKeyStateEffect = StateEffect.define<boolean>();
|
||||
const hoverPositionEffect = StateEffect.define<number | null>();
|
||||
const addHyperlinkEffect = StateEffect.define<Range<Hyperlink>>();
|
||||
const updateHyperlinkEffect = StateEffect.define<[Hyperlink, IHyperlinkInfo | null]>();
|
||||
|
||||
const modKeyState = StateField.define<boolean>({
|
||||
create: () => false,
|
||||
update(value, tr) {
|
||||
for (const effect of tr.effects) {
|
||||
if (effect.is(metaKeyStateEffect)) {
|
||||
return effect.value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
});
|
||||
|
||||
const hoverPositionState = StateField.define<number | null>({
|
||||
create: () => null,
|
||||
update(value, tr) {
|
||||
for (const effect of tr.effects) {
|
||||
if (effect.is(hoverPositionEffect)) {
|
||||
return effect.value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
});
|
||||
|
||||
const linksState = StateField.define({
|
||||
create: () => Hyperlink.none,
|
||||
update(hyperlinks, tr) {
|
||||
hyperlinks = hyperlinks.map(tr.changes);
|
||||
const isMetaKey = tr.state.field(modKeyState);
|
||||
|
||||
if (!isMetaKey) {
|
||||
return hyperlinks.size === 0 ? hyperlinks : Hyperlink.none;
|
||||
}
|
||||
|
||||
for (const effect of tr.effects) {
|
||||
if (effect.is(addHyperlinkEffect)) {
|
||||
return hyperlinks.update({
|
||||
add: [effect.value],
|
||||
});
|
||||
}
|
||||
|
||||
if (effect.is(updateHyperlinkEffect)) {
|
||||
return hyperlinks.update({
|
||||
filter: (from, to, hyperlink) => {
|
||||
if (hyperlink === effect.value[0]) {
|
||||
hyperlink.state = HyperlinkState.Result;
|
||||
hyperlink.hyperlink = effect.value[1];
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return hyperlinks;
|
||||
},
|
||||
provide: linksState =>
|
||||
EditorView.decorations.compute([linksState, hoverPositionState], state => {
|
||||
const hoverCursor = state.field(hoverPositionState);
|
||||
const hyperlinks = state.field(linksState).update({ filter: (from, to) => !!hoverCursor && from <= hoverCursor && hoverCursor <= to });
|
||||
|
||||
const iter = hyperlinks.iter();
|
||||
const decorations = [];
|
||||
|
||||
while (iter.value) {
|
||||
const hyperlink = iter.value;
|
||||
const link = hyperlink.hyperlink;
|
||||
|
||||
if (link) {
|
||||
decorations.push(
|
||||
Decoration.mark({
|
||||
class: 'cm-link cm-link-loaded',
|
||||
attributes: { title: link.tooltip || '' },
|
||||
link,
|
||||
}).range(iter.from, iter.to),
|
||||
);
|
||||
} else {
|
||||
decorations.push(
|
||||
Decoration.mark({
|
||||
class: 'cm-link cm-link-loading',
|
||||
}).range(iter.from, iter.to),
|
||||
);
|
||||
}
|
||||
|
||||
iter.next();
|
||||
}
|
||||
|
||||
return Decoration.set(decorations);
|
||||
}),
|
||||
});
|
||||
|
||||
const hyperlinkPlugin = ViewPlugin.fromClass(
|
||||
class {
|
||||
private pendingUpdate: ReturnType<typeof setTimeout> | null = null;
|
||||
constructor(public view: EditorView) {}
|
||||
|
||||
update(update: ViewUpdate) {
|
||||
const isMetaKey = update.state.field(modKeyState);
|
||||
|
||||
if (isMetaKey) {
|
||||
this.scheduleLinkInfoLoad();
|
||||
} else {
|
||||
this.resetLinkInfoLoad();
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleLinkInfoLoad() {
|
||||
this.resetLinkInfoLoad();
|
||||
|
||||
this.pendingUpdate = setTimeout(() => {
|
||||
this.pendingUpdate = null;
|
||||
|
||||
const position = this.getHoveredWordPosition(this.view.state);
|
||||
|
||||
if (position === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const links = this.view.state.field(linksState);
|
||||
const config = this.view.state.facet(hyperlinksConfig);
|
||||
|
||||
let hyperlink: Hyperlink | null = null;
|
||||
links.between(position.from, position.to, (from, to, h) => {
|
||||
if (from === position.from && to === position.to) {
|
||||
hyperlink = h;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hyperlink) {
|
||||
hyperlink = Hyperlink.create();
|
||||
this.view.dispatch({ effects: addHyperlinkEffect.of(hyperlink!.range(position.from, position.to)) });
|
||||
}
|
||||
|
||||
if (hyperlink.state === HyperlinkState.Inactive) {
|
||||
hyperlink.state = HyperlinkState.Pending;
|
||||
|
||||
config
|
||||
.loadLinkInfo(position)
|
||||
.then(link => {
|
||||
this.view.dispatch({ effects: updateHyperlinkEffect.of([hyperlink!, link]) });
|
||||
})
|
||||
.catch(() => {
|
||||
this.view.dispatch({ effects: updateHyperlinkEffect.of([hyperlink!, null]) });
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private resetLinkInfoLoad() {
|
||||
if (this.pendingUpdate) {
|
||||
clearTimeout(this.pendingUpdate);
|
||||
this.pendingUpdate = null;
|
||||
}
|
||||
}
|
||||
|
||||
private getHoveredWordPosition(state: EditorState): SelectionRange | null {
|
||||
const position = state.field(hoverPositionState);
|
||||
|
||||
if (position === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return state.wordAt(position);
|
||||
}
|
||||
},
|
||||
{
|
||||
eventHandlers: {
|
||||
keydown: (event, view) => {
|
||||
if (event.key === 'Meta') {
|
||||
view.dispatch({ effects: [metaKeyStateEffect.of(true)] });
|
||||
}
|
||||
},
|
||||
keyup: (event, view) => {
|
||||
if (event.key === 'Meta') {
|
||||
view.dispatch({ effects: metaKeyStateEffect.of(false) });
|
||||
}
|
||||
},
|
||||
mousedown(event, view) {
|
||||
try {
|
||||
const linksSet = view.state.field(linksState);
|
||||
const target = event.target as HTMLElement;
|
||||
const pos = view.posAtDOM(target);
|
||||
|
||||
const iterator = linksSet.iter(pos);
|
||||
const hyperlink = iterator.value;
|
||||
|
||||
if (hyperlink) {
|
||||
const link = hyperlink.hyperlink;
|
||||
|
||||
if (link) {
|
||||
link.onClick();
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
},
|
||||
mousemove: (event, view) => {
|
||||
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
||||
view.dispatch({ effects: [hoverPositionEffect.of(pos), metaKeyStateEffect.of(event.metaKey)] });
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const EDITOR_AUTOCOMPLETION_COMPARTMENT = new Compartment();
|
||||
export function useHyperlink(config: HyperlinksConfig): [Compartment, Extension] {
|
||||
return [EDITOR_AUTOCOMPLETION_COMPARTMENT, [hyperlinkPlugin, modKeyState, hoverPositionState, linksState, hyperlinksConfig.of(config)]];
|
||||
}
|
||||
@@ -8,6 +8,10 @@ export * from './useEditorDefaultExtensions';
|
||||
export * from './useEditorAutocompletion';
|
||||
export * from './useCodemirrorExtensions';
|
||||
|
||||
export * from './Hyperlink/HyperlinkLoader';
|
||||
export * from './Hyperlink/IHyperlinkInfo';
|
||||
export * from './Hyperlink/useHyperlink';
|
||||
|
||||
export * from '@codemirror/view';
|
||||
export * from '@codemirror/state';
|
||||
export * from '@codemirror/autocomplete';
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
border-left-color: $cursor;
|
||||
}
|
||||
|
||||
.editor .cm-link {
|
||||
&.cm-link-loaded {
|
||||
@include mdc-theme-prop(color, primary, false);
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.editor .cm-dropCursor {
|
||||
border-left: 1.2px solid $cursor;
|
||||
}
|
||||
|
||||
@@ -7,17 +7,20 @@
|
||||
*/
|
||||
import type { ThemeSelector } from '@cloudbeaver/core-theming';
|
||||
|
||||
import type Dark from './dark.module.scss';
|
||||
import type Light from './light.module.scss';
|
||||
|
||||
export const EDITOR_BASE_STYLES: ThemeSelector = async theme => {
|
||||
let styles: any;
|
||||
let styles: typeof Light & typeof Dark;
|
||||
|
||||
switch (theme) {
|
||||
case 'dark':
|
||||
styles = await import('./dark.module.scss');
|
||||
styles = (await import('./dark.module.scss')).default;
|
||||
break;
|
||||
default:
|
||||
styles = await import('./light.module.scss');
|
||||
styles = (await import('./light.module.scss')).default;
|
||||
break;
|
||||
}
|
||||
|
||||
return styles.default;
|
||||
return styles;
|
||||
};
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-connections": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
"@cloudbeaver/core-ui": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-connections": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-connections": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
-267
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 { computed, makeObservable, observable } from 'mobx';
|
||||
|
||||
import { ErrorDetailsDialog } from '@cloudbeaver/core-blocks';
|
||||
import {
|
||||
Connection,
|
||||
ConnectionInfoProjectKey,
|
||||
ConnectionInfoResource,
|
||||
ConnectionInitConfig,
|
||||
createConnectionParam,
|
||||
DatabaseAuthModelsResource,
|
||||
DBDriver,
|
||||
DBDriverResource,
|
||||
USER_NAME_PROPERTY_ID,
|
||||
} from '@cloudbeaver/core-connections';
|
||||
import { IDestructibleController, IInitializableController, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
|
||||
import { DatabaseAuthModel, DetailsError, NetworkHandlerAuthType } from '@cloudbeaver/core-sdk';
|
||||
import { errorOf, getUniqueName } from '@cloudbeaver/core-utils';
|
||||
import type { IConnectionAuthenticationConfig } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { TemplateConnectionsResource } from '../TemplateConnectionsResource';
|
||||
import { TemplateConnectionsService } from '../TemplateConnectionsService';
|
||||
|
||||
export enum ConnectionStep {
|
||||
ConnectionTemplateSelect,
|
||||
Connection,
|
||||
}
|
||||
|
||||
export interface IConnectionController {
|
||||
template: Connection | null;
|
||||
config: IConnectionAuthenticationConfig;
|
||||
isConnecting: boolean;
|
||||
onConnect: () => void;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ConnectionController implements IInitializableController, IDestructibleController, IConnectionController {
|
||||
step = ConnectionStep.ConnectionTemplateSelect;
|
||||
isLoading = true;
|
||||
isConnecting = false;
|
||||
template: Connection | null = null;
|
||||
authModel?: DatabaseAuthModel;
|
||||
config: IConnectionAuthenticationConfig = {
|
||||
credentials: {},
|
||||
networkHandlersConfig: [],
|
||||
saveCredentials: false,
|
||||
};
|
||||
|
||||
hasDetails = false;
|
||||
responseMessage: string | null = null;
|
||||
|
||||
private exception: DetailsError | null = null;
|
||||
private onClose!: () => void;
|
||||
private isDistructed = false;
|
||||
|
||||
get templateConnections(): Connection[] {
|
||||
return this.templateConnectionsService.projectTemplates;
|
||||
}
|
||||
|
||||
get dbDrivers(): Map<string, DBDriver> {
|
||||
return this.dbDriverResource.data;
|
||||
}
|
||||
|
||||
get dbDriver(): DBDriver | undefined {
|
||||
if (!this.template) {
|
||||
return undefined;
|
||||
}
|
||||
return this.dbDrivers.get(this.template.driverId);
|
||||
}
|
||||
|
||||
get networkHandlers(): string[] {
|
||||
if (!this.template?.networkHandlersConfig) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.template.networkHandlersConfig.filter(handler => handler.enabled && !handler.savePassword).map(handler => handler.id);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly dbDriverResource: DBDriverResource,
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
private readonly templateConnectionsResource: TemplateConnectionsResource,
|
||||
private readonly templateConnectionsService: TemplateConnectionsService,
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
private readonly dbAuthModelsResource: DatabaseAuthModelsResource,
|
||||
private readonly projectsService: ProjectsService,
|
||||
) {
|
||||
this.authModel = undefined;
|
||||
|
||||
makeObservable(this, {
|
||||
step: observable,
|
||||
isLoading: observable,
|
||||
isConnecting: observable,
|
||||
template: observable,
|
||||
authModel: observable,
|
||||
config: observable,
|
||||
hasDetails: observable,
|
||||
responseMessage: observable,
|
||||
networkHandlers: computed,
|
||||
});
|
||||
}
|
||||
|
||||
init(onClose: () => void): void {
|
||||
this.onClose = onClose;
|
||||
this.loadTemplateConnections();
|
||||
}
|
||||
|
||||
destruct(): void {
|
||||
this.isDistructed = true;
|
||||
}
|
||||
|
||||
onStep = (step: ConnectionStep): void => {
|
||||
this.step = step;
|
||||
this.clearError();
|
||||
|
||||
if (step === ConnectionStep.ConnectionTemplateSelect) {
|
||||
this.template = null;
|
||||
}
|
||||
};
|
||||
|
||||
onConnect = async (): Promise<void> => {
|
||||
if (!this.template || !this.projectsService.userProject) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isConnecting = true;
|
||||
this.clearError();
|
||||
try {
|
||||
const connections = await this.connectionInfoResource.load(ConnectionInfoProjectKey(this.projectsService.userProject.id));
|
||||
const connectionNames = connections.map(connection => connection.name);
|
||||
|
||||
const uniqueConnectionName = getUniqueName(this.template.name || 'Template connection', connectionNames);
|
||||
const connection = await this.connectionInfoResource.createFromTemplate(this.template.projectId, this.template.id, uniqueConnectionName);
|
||||
|
||||
try {
|
||||
await this.connectionInfoResource.init(this.getConfig(connection.projectId, connection.id));
|
||||
|
||||
this.notificationService.logSuccess({ title: 'Connection is established', message: connection.name });
|
||||
this.onClose();
|
||||
} catch (exception: any) {
|
||||
this.showError(exception, 'Failed to establish connection');
|
||||
await this.connectionInfoResource.deleteConnection(createConnectionParam(connection));
|
||||
}
|
||||
} catch (exception: any) {
|
||||
this.showError(exception, 'Failed to establish connection');
|
||||
} finally {
|
||||
this.isConnecting = false;
|
||||
}
|
||||
};
|
||||
|
||||
onTemplateSelect = async (templateId: string): Promise<void> => {
|
||||
this.template = this.templateConnections.find(template => template.id === templateId)!;
|
||||
|
||||
await this.loadAuthModel();
|
||||
this.clearError();
|
||||
this.config = {
|
||||
credentials: {},
|
||||
networkHandlersConfig: [],
|
||||
saveCredentials: false,
|
||||
};
|
||||
|
||||
if (this.template.authNeeded) {
|
||||
const property = this.template.authProperties?.find(property => property.id === USER_NAME_PROPERTY_ID);
|
||||
|
||||
if (property?.value) {
|
||||
this.config.credentials[USER_NAME_PROPERTY_ID] = property.value;
|
||||
}
|
||||
}
|
||||
|
||||
for (const id of this.networkHandlers) {
|
||||
const handler = this.template.networkHandlersConfig?.find(handler => handler.id === id);
|
||||
|
||||
if (handler && (handler.userName || handler.authType !== NetworkHandlerAuthType.Password)) {
|
||||
this.config.networkHandlersConfig.push({
|
||||
id: handler.id,
|
||||
authType: handler.authType,
|
||||
userName: handler.userName,
|
||||
password: handler.password,
|
||||
savePassword: handler.savePassword,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.step = ConnectionStep.Connection;
|
||||
if (!this.authModel) {
|
||||
this.onConnect();
|
||||
}
|
||||
};
|
||||
|
||||
onShowDetails = (): void => {
|
||||
if (this.exception) {
|
||||
this.commonDialogService.open(ErrorDetailsDialog, this.exception);
|
||||
}
|
||||
};
|
||||
|
||||
private getConfig(projectId: string, connectionId: string) {
|
||||
const config: ConnectionInitConfig = {
|
||||
projectId,
|
||||
connectionId,
|
||||
};
|
||||
|
||||
if (Object.keys(this.config.credentials).length > 0) {
|
||||
config.credentials = this.config.credentials;
|
||||
config.saveCredentials = this.config.saveCredentials;
|
||||
}
|
||||
|
||||
if (this.config.networkHandlersConfig.length > 0) {
|
||||
config.networkCredentials = this.config.networkHandlersConfig;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
private clearError() {
|
||||
this.responseMessage = null;
|
||||
this.hasDetails = false;
|
||||
this.exception = null;
|
||||
}
|
||||
|
||||
private showError(exception: Error, message: string) {
|
||||
const detailsError = errorOf(exception, DetailsError);
|
||||
if (detailsError && !this.isDistructed) {
|
||||
this.responseMessage = detailsError.message;
|
||||
this.hasDetails = detailsError.hasDetails();
|
||||
this.exception = detailsError;
|
||||
} else {
|
||||
this.notificationService.logException(exception, message);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadTemplateConnections() {
|
||||
try {
|
||||
await this.templateConnectionsResource.load();
|
||||
await this.dbDriverResource.load(CachedMapAllKey);
|
||||
} catch (exception: any) {
|
||||
this.notificationService.logException(exception, "Can't load database sources");
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async loadAuthModel() {
|
||||
if (!this.dbDriver || this.dbDriver.anonymousAccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
this.authModel = await this.dbAuthModelsResource.load(this.dbDriver.defaultAuthModel);
|
||||
} catch (exception: any) {
|
||||
this.notificationService.logException(exception, "Can't load driver auth model");
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
-39
@@ -14,85 +14,76 @@ import {
|
||||
CommonDialogWrapper,
|
||||
ErrorMessage,
|
||||
Form,
|
||||
Loader,
|
||||
s,
|
||||
useAdministrationSettings,
|
||||
useErrorDetails,
|
||||
useFocus,
|
||||
useS,
|
||||
useTranslate,
|
||||
} from '@cloudbeaver/core-blocks';
|
||||
import { useController } from '@cloudbeaver/core-di';
|
||||
import type { DialogComponent } from '@cloudbeaver/core-dialogs';
|
||||
import { ConnectionAuthenticationFormLoader } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { ConnectionController, ConnectionStep } from './ConnectionController';
|
||||
import style from './ConnectionDialog.m.css';
|
||||
import { ConnectionDialogFooter } from './ConnectionDialogFooter';
|
||||
import { ConnectionStep } from './EConnectionStep';
|
||||
import { TemplateConnectionSelector } from './TemplateConnectionSelector/TemplateConnectionSelector';
|
||||
import { useConnectionDialog } from './useConnectionDialog';
|
||||
|
||||
export const ConnectionDialog: DialogComponent<null, null> = observer(function ConnectionDialog({ rejectDialog }) {
|
||||
const styles = useS(style);
|
||||
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
|
||||
const controller = useController(ConnectionController, rejectDialog);
|
||||
const translate = useTranslate();
|
||||
const [focusedRef] = useFocus<HTMLFormElement>({ focusFirstChild: true });
|
||||
const { credentialsSavingEnabled } = useAdministrationSettings();
|
||||
const dialog = useConnectionDialog(rejectDialog);
|
||||
const errorDetails = useErrorDetails(dialog.connectException);
|
||||
|
||||
let subtitle: string | undefined;
|
||||
|
||||
if (controller.step === ConnectionStep.Connection && controller.template?.name) {
|
||||
subtitle = controller.template.name;
|
||||
}
|
||||
const subTitle = dialog.step === ConnectionStep.Connection ? dialog.template?.name : undefined;
|
||||
|
||||
return (
|
||||
<CommonDialogWrapper size="large" fixedSize>
|
||||
<CommonDialogWrapper size="large" fixedSize={dialog.step === ConnectionStep.ConnectionTemplateSelect}>
|
||||
<CommonDialogHeader
|
||||
title="basicConnection_connectionDialog_newConnection"
|
||||
subTitle={subtitle}
|
||||
icon={controller.dbDriver?.icon}
|
||||
subTitle={subTitle}
|
||||
icon={dialog.driver?.icon}
|
||||
onReject={rejectDialog}
|
||||
/>
|
||||
<CommonDialogBody noBodyPadding={controller.step === ConnectionStep.ConnectionTemplateSelect} noOverflow>
|
||||
{controller.isLoading && <Loader />}
|
||||
{!controller.isLoading && controller.step === ConnectionStep.ConnectionTemplateSelect && (
|
||||
<TemplateConnectionSelector
|
||||
templateConnections={controller.templateConnections}
|
||||
dbDrivers={controller.dbDrivers}
|
||||
onSelect={controller.onTemplateSelect}
|
||||
/>
|
||||
)}
|
||||
{controller.step === ConnectionStep.Connection &&
|
||||
(!controller.authModel ? (
|
||||
<CommonDialogBody noBodyPadding={dialog.step === ConnectionStep.ConnectionTemplateSelect} noOverflow>
|
||||
{dialog.step === ConnectionStep.ConnectionTemplateSelect && <TemplateConnectionSelector onSelect={dialog.selectTemplate} />}
|
||||
{dialog.step === ConnectionStep.Connection &&
|
||||
(!dialog.authModelId ? (
|
||||
<center className={s(styles, { center: true })}>
|
||||
{controller.isConnecting && translate('basicConnection_connectionDialog_connecting_message')}
|
||||
{dialog.processing && translate('basicConnection_connectionDialog_connecting_message')}
|
||||
</center>
|
||||
) : (
|
||||
<Form ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={controller.onConnect}>
|
||||
<Form ref={focusedRef} className={s(styles, { submittingForm: true })} onSubmit={dialog.connect}>
|
||||
<ConnectionAuthenticationFormLoader
|
||||
config={controller.config}
|
||||
authModelId={controller.authModel.id}
|
||||
networkHandlers={controller.networkHandlers}
|
||||
formId={controller.template?.id}
|
||||
config={dialog.config}
|
||||
authModelId={dialog.authModelId}
|
||||
networkHandlers={dialog.networkHandlers}
|
||||
formId={dialog.template?.id}
|
||||
allowSaveCredentials={credentialsSavingEnabled}
|
||||
disabled={controller.isConnecting}
|
||||
disabled={dialog.processing}
|
||||
hideFeatures={['nonSecuredProperty']}
|
||||
className={s(styles, { connectionAuthenticationFormLoader: true })}
|
||||
/>
|
||||
</Form>
|
||||
))}
|
||||
</CommonDialogBody>
|
||||
{controller.step === ConnectionStep.Connection && (
|
||||
{dialog.step === ConnectionStep.Connection && (
|
||||
<CommonDialogFooter>
|
||||
{controller.responseMessage && (
|
||||
{dialog.connectException && (
|
||||
<ErrorMessage
|
||||
text={controller.responseMessage}
|
||||
text={errorDetails.message ?? translate('core_blocks_exception_message_error_message')}
|
||||
hasDetails={errorDetails.hasDetails}
|
||||
className={s(styles, { errorMessage: true })}
|
||||
hasDetails={controller.hasDetails}
|
||||
onShowDetails={controller.onShowDetails}
|
||||
onShowDetails={errorDetails.open}
|
||||
/>
|
||||
)}
|
||||
<ConnectionDialogFooter
|
||||
isConnecting={controller.isConnecting}
|
||||
onBack={() => controller.onStep(ConnectionStep.ConnectionTemplateSelect)}
|
||||
onConnect={controller.onConnect}
|
||||
isConnecting={dialog.processing}
|
||||
onBack={() => dialog.setStep(ConnectionStep.ConnectionTemplateSelect)}
|
||||
onConnect={dialog.connect}
|
||||
/>
|
||||
</CommonDialogFooter>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
export enum ConnectionStep {
|
||||
ConnectionTemplateSelect,
|
||||
Connection,
|
||||
}
|
||||
+21
-11
@@ -8,24 +8,29 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { ItemList, ItemListSearch } from '@cloudbeaver/core-blocks';
|
||||
import type { Connection, DBDriver } from '@cloudbeaver/core-connections';
|
||||
import { ItemList, ItemListSearch, useResource } from '@cloudbeaver/core-blocks';
|
||||
import { DBDriverResource } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
|
||||
|
||||
import { TemplateConnectionsResource } from '../../TemplateConnectionsResource';
|
||||
import { TemplateConnectionsService } from '../../TemplateConnectionsService';
|
||||
import { TemplateConnectionItem } from './TemplateConnectionItem';
|
||||
|
||||
interface Props {
|
||||
templateConnections: Connection[];
|
||||
dbDrivers: Map<string, DBDriver>;
|
||||
className?: string;
|
||||
onSelect: (dbSourceId: string) => void;
|
||||
}
|
||||
|
||||
export const TemplateConnectionSelector = observer<Props>(function TemplateConnectionSelector({
|
||||
templateConnections,
|
||||
dbDrivers,
|
||||
className,
|
||||
onSelect,
|
||||
}) {
|
||||
export const TemplateConnectionSelector = observer<Props>(function TemplateConnectionSelector({ className, onSelect }) {
|
||||
useResource(TemplateConnectionSelector, ProjectInfoResource, CachedMapAllKey, { forceSuspense: true });
|
||||
useResource(TemplateConnectionSelector, TemplateConnectionsResource, undefined, { forceSuspense: true });
|
||||
const dbDriverResource = useResource(TemplateConnectionSelector, DBDriverResource, CachedMapAllKey);
|
||||
const templateConnectionsService = useService(TemplateConnectionsService);
|
||||
|
||||
const templateConnections = templateConnectionsService.projectTemplates;
|
||||
|
||||
const [search, setSearch] = useState('');
|
||||
const filteredTemplateConnections = useMemo(() => {
|
||||
if (!search) {
|
||||
@@ -39,7 +44,12 @@ export const TemplateConnectionSelector = observer<Props>(function TemplateConne
|
||||
<ItemListSearch onChange={setSearch} />
|
||||
<ItemList className={className}>
|
||||
{filteredTemplateConnections.map(template => (
|
||||
<TemplateConnectionItem key={template.id} template={template} dbDriver={dbDrivers.get(template.driverId)} onSelect={onSelect} />
|
||||
<TemplateConnectionItem
|
||||
key={template.id}
|
||||
template={template}
|
||||
dbDriver={dbDriverResource.resource.get(template.driverId)}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
))}
|
||||
</ItemList>
|
||||
</>
|
||||
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2023 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 { action, computed, observable } from 'mobx';
|
||||
|
||||
import { AuthProviderService } from '@cloudbeaver/core-authentication';
|
||||
import { useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import {
|
||||
Connection,
|
||||
ConnectionInfoProjectKey,
|
||||
ConnectionInfoResource,
|
||||
ConnectionInitConfig,
|
||||
createConnectionParam,
|
||||
DBDriver,
|
||||
DBDriverResource,
|
||||
USER_NAME_PROPERTY_ID,
|
||||
} from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { NetworkHandlerAuthType } from '@cloudbeaver/core-sdk';
|
||||
import { getUniqueName } from '@cloudbeaver/core-utils';
|
||||
import type { IConnectionAuthenticationConfig } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { TemplateConnectionsService } from '../TemplateConnectionsService';
|
||||
import { ConnectionStep } from './EConnectionStep';
|
||||
|
||||
interface IState {
|
||||
readonly networkHandlers: string[];
|
||||
readonly authModelId: string | null;
|
||||
step: ConnectionStep;
|
||||
driver: DBDriver | null;
|
||||
template: Connection | null;
|
||||
config: IConnectionAuthenticationConfig;
|
||||
processing: boolean;
|
||||
connectException: Error | null;
|
||||
connect: () => Promise<void>;
|
||||
setStep: (step: ConnectionStep) => void;
|
||||
getConfig: (projectId: string, connectionId: string) => ConnectionInitConfig;
|
||||
selectTemplate: (templateId: string) => Promise<void>;
|
||||
}
|
||||
|
||||
function getDefaultConfig(): IConnectionAuthenticationConfig {
|
||||
return {
|
||||
credentials: {},
|
||||
networkHandlersConfig: [],
|
||||
saveCredentials: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function useConnectionDialog(onConnect?: () => void) {
|
||||
const notificationService = useService(NotificationService);
|
||||
const connectionInfoResource = useService(ConnectionInfoResource);
|
||||
const templateConnectionsService = useService(TemplateConnectionsService);
|
||||
const projectsService = useService(ProjectsService);
|
||||
const authProviderService = useService(AuthProviderService);
|
||||
const dbDriverResource = useService(DBDriverResource);
|
||||
|
||||
const state: IState = useObservableRef(
|
||||
() => ({
|
||||
get networkHandlers() {
|
||||
return this.template?.networkHandlersConfig?.filter(handler => handler.enabled && !handler.savePassword).map(handler => handler.id) || [];
|
||||
},
|
||||
get authModelId() {
|
||||
if (this.template?.authNeeded === false || this.driver?.anonymousAccess === true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.template?.authModel || this.driver?.defaultAuthModel || null;
|
||||
},
|
||||
step: ConnectionStep.ConnectionTemplateSelect,
|
||||
template: null as Connection | null,
|
||||
driver: null as DBDriver | null,
|
||||
processing: false,
|
||||
connectException: null,
|
||||
config: getDefaultConfig(),
|
||||
async connect() {
|
||||
if (this.processing || !this.template || !this.projectsService.userProject) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.connectException = null;
|
||||
this.processing = true;
|
||||
|
||||
const connections = await this.connectionInfoResource.load(ConnectionInfoProjectKey(this.projectsService.userProject.id));
|
||||
const connectionNames = connections.map(connection => connection.name);
|
||||
|
||||
const uniqueConnectionName = getUniqueName(this.template.name || 'Template connection', connectionNames);
|
||||
const connection = await this.connectionInfoResource.createFromTemplate(this.template.projectId, this.template.id, uniqueConnectionName);
|
||||
|
||||
if (connection.requiredAuth) {
|
||||
const state = await this.authProviderService.requireProvider(connection.requiredAuth);
|
||||
|
||||
if (!state) {
|
||||
this.setStep(ConnectionStep.ConnectionTemplateSelect);
|
||||
await this.connectionInfoResource.deleteConnection(createConnectionParam(connection));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.connectionInfoResource.init(this.getConfig(connection.projectId, connection.id));
|
||||
this.notificationService.logSuccess({ title: 'plugin_connection_template_connect_success', message: connection.name });
|
||||
this.onConnect?.();
|
||||
} catch (exception: any) {
|
||||
this.connectException = exception;
|
||||
await this.connectionInfoResource.deleteConnection(createConnectionParam(connection));
|
||||
}
|
||||
} catch (exception: any) {
|
||||
this.connectException = exception;
|
||||
} finally {
|
||||
this.processing = false;
|
||||
}
|
||||
},
|
||||
getConfig(projectId: string, connectionId: string) {
|
||||
const config: ConnectionInitConfig = {
|
||||
projectId,
|
||||
connectionId,
|
||||
};
|
||||
|
||||
if (this.authModelId) {
|
||||
if (Object.keys(this.config.credentials).length > 0) {
|
||||
config.credentials = this.config.credentials;
|
||||
}
|
||||
|
||||
config.saveCredentials = this.config.saveCredentials;
|
||||
}
|
||||
|
||||
if (this.config.networkHandlersConfig.length > 0) {
|
||||
config.networkCredentials = this.config.networkHandlersConfig;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
async selectTemplate(templateId: string) {
|
||||
this.template = this.templateConnectionsService.projectTemplates.find(template => template.id === templateId)!;
|
||||
this.driver = await this.dbDriverResource.load(this.template.driverId);
|
||||
this.config = getDefaultConfig();
|
||||
|
||||
if (this.template.authNeeded) {
|
||||
const property = this.template.authProperties?.find(property => property.id === USER_NAME_PROPERTY_ID);
|
||||
|
||||
if (property?.value) {
|
||||
this.config.credentials[USER_NAME_PROPERTY_ID] = property.value;
|
||||
}
|
||||
}
|
||||
|
||||
for (const id of this.networkHandlers) {
|
||||
const handler = this.template.networkHandlersConfig?.find(handler => handler.id === id);
|
||||
|
||||
if (handler && (handler.userName || handler.authType !== NetworkHandlerAuthType.Password)) {
|
||||
this.config.networkHandlersConfig.push({
|
||||
id: handler.id,
|
||||
authType: handler.authType,
|
||||
userName: handler.userName,
|
||||
password: handler.password,
|
||||
savePassword: handler.savePassword,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.setStep(ConnectionStep.Connection);
|
||||
|
||||
if (!this.authModelId) {
|
||||
this.connect();
|
||||
}
|
||||
},
|
||||
setStep(step: ConnectionStep) {
|
||||
this.step = step;
|
||||
this.connectException = null;
|
||||
|
||||
if (step === ConnectionStep.ConnectionTemplateSelect) {
|
||||
this.template = null;
|
||||
this.driver = null;
|
||||
}
|
||||
},
|
||||
}),
|
||||
{
|
||||
step: observable.ref,
|
||||
config: observable,
|
||||
template: observable.ref,
|
||||
driver: observable.ref,
|
||||
processing: observable.ref,
|
||||
connectException: observable.ref,
|
||||
networkHandlers: computed,
|
||||
authModelId: computed,
|
||||
connect: action.bound,
|
||||
selectTemplate: action.bound,
|
||||
setStep: action.bound,
|
||||
},
|
||||
{
|
||||
templateConnectionsService,
|
||||
projectsService,
|
||||
notificationService,
|
||||
authProviderService,
|
||||
connectionInfoResource,
|
||||
dbDriverResource,
|
||||
onConnect,
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
@@ -31,10 +31,28 @@ export class TemplateConnectionsResource extends CachedDataResource<Connection[]
|
||||
this.markOutdated();
|
||||
}
|
||||
});
|
||||
connectionInfoResource.onItemDelete.addHandler(list => {
|
||||
const isAnyTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template);
|
||||
|
||||
if (isAnyTemplate) {
|
||||
connectionInfoResource.onDataOutdated.addHandler(key => {
|
||||
const keyData = connectionInfoResource.get(key);
|
||||
const connections = Array.isArray(keyData) ? keyData : [keyData];
|
||||
|
||||
if (connections.some(connection => connection?.template)) {
|
||||
this.markOutdated();
|
||||
}
|
||||
});
|
||||
|
||||
connectionInfoResource.onItemUpdate.addHandler(list => {
|
||||
const includesTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template);
|
||||
|
||||
if (includesTemplate) {
|
||||
this.markOutdated();
|
||||
}
|
||||
});
|
||||
|
||||
connectionInfoResource.onItemDelete.addHandler(list => {
|
||||
const includesTemplate = connectionInfoResource.get(ResourceKeyUtils.toList(list)).some(connection => connection?.template);
|
||||
|
||||
if (includesTemplate) {
|
||||
this.markOutdated();
|
||||
}
|
||||
});
|
||||
@@ -46,7 +64,7 @@ export class TemplateConnectionsResource extends CachedDataResource<Connection[]
|
||||
customIncludeOriginDetails: false,
|
||||
includeAuthProperties: true,
|
||||
includeOrigin: false,
|
||||
includeAuthNeeded: false,
|
||||
includeAuthNeeded: true,
|
||||
includeCredentialsSaved: false,
|
||||
includeProperties: false,
|
||||
includeProviderProperties: false,
|
||||
|
||||
@@ -8,5 +8,6 @@ export default [
|
||||
['basicConnection_connectionDialog_passwordPlaceholder', 'password'],
|
||||
['basicConnection_connectionDialog_connecting', 'Connecting...'],
|
||||
['basicConnection_connectionDialog_connecting_message', 'Connecting to database...'],
|
||||
['plugin_connection_template_connect_success', 'Connection is established'],
|
||||
['plugin_connection_template_action_connection_template_label', 'From a Template'],
|
||||
];
|
||||
|
||||
@@ -8,5 +8,6 @@ export default [
|
||||
['basicConnection_connectionDialog_passwordPlaceholder', 'password'],
|
||||
['basicConnection_connectionDialog_connecting', 'Collegamento...'],
|
||||
['basicConnection_connectionDialog_connecting_message', 'Collegamento al database...'],
|
||||
['plugin_connection_template_connect_success', 'Connection is established'],
|
||||
['plugin_connection_template_action_connection_template_label', 'Dal Template'],
|
||||
];
|
||||
|
||||
@@ -8,5 +8,6 @@ export default [
|
||||
['basicConnection_connectionDialog_passwordPlaceholder', 'password'],
|
||||
['basicConnection_connectionDialog_connecting', 'Подключение...'],
|
||||
['basicConnection_connectionDialog_connecting_message', 'Подключение к базе...'],
|
||||
['plugin_connection_template_connect_success', 'Подключение установлено'],
|
||||
['plugin_connection_template_action_connection_template_label', 'Из шаблона'],
|
||||
];
|
||||
|
||||
@@ -8,5 +8,6 @@ export default [
|
||||
['basicConnection_connectionDialog_passwordPlaceholder', '密码'],
|
||||
['basicConnection_connectionDialog_connecting', '连接中...'],
|
||||
['basicConnection_connectionDialog_connecting_message', '连接数据库...'],
|
||||
['plugin_connection_template_connect_success', 'Connection is established'],
|
||||
['plugin_connection_template_action_connection_template_label', '从模板创建'],
|
||||
];
|
||||
|
||||
@@ -33,15 +33,15 @@
|
||||
"@cloudbeaver/core-ui": "~0.1.0",
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@cloudbeaver/plugin-connections": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import styled, { css } from 'reshadow';
|
||||
import { Icon, IconButton, Loader, StaticImage, useResource, useStyles, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { DBDriverResource } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { BASE_TAB_STYLES, TabList, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
|
||||
import { BASE_TAB_STYLES, TabPanelList, TabsState, UNDERLINE_TAB_STYLES } from '@cloudbeaver/core-ui';
|
||||
import { ConnectionFormLoader } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { CreateConnectionService } from '../CreateConnectionService';
|
||||
|
||||
+3
-3
@@ -7,17 +7,17 @@
|
||||
*/
|
||||
import { action, computed, observable } from 'mobx';
|
||||
|
||||
import { IAutoLoadable, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import type { DatabaseConnectionFragment } from '@cloudbeaver/core-sdk';
|
||||
import { useTabState } from '@cloudbeaver/core-ui';
|
||||
import { isArraysEqual, isContainsException } from '@cloudbeaver/core-utils';
|
||||
import { ILoadableState, isArraysEqual, isContainsException } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IConnectionAccessTabState } from './IConnectionAccessTabState';
|
||||
|
||||
interface State extends IAutoLoadable {
|
||||
interface State extends ILoadableState {
|
||||
state: IConnectionAccessTabState;
|
||||
changed: boolean;
|
||||
edit: () => void;
|
||||
|
||||
@@ -40,15 +40,15 @@
|
||||
"@cloudbeaver/plugin-navigation-tree": "~0.1.0",
|
||||
"@cloudbeaver/plugin-projects": "~0.1.0",
|
||||
"@cloudbeaver/plugin-top-app-bar": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
"d3-drag": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-drag": "^3.0.3",
|
||||
"typescript": "^5.2.2"
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/d3-drag": "^3.0.7",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-data-viewer": "~0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1",
|
||||
@@ -67,10 +67,10 @@
|
||||
"@cloudbeaver/plugin-navigation-tree": "~0.1.0",
|
||||
"@cloudbeaver/plugin-object-viewer": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@cloudbeaver/plugin-data-viewer": "~0.1.0",
|
||||
"@cloudbeaver/plugin-react-data-grid": "~0.1.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -68,10 +68,10 @@
|
||||
"@cloudbeaver/plugin-navigation-tree": "~0.1.0",
|
||||
"@cloudbeaver/plugin-object-viewer": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-data-viewer": "~0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"@cloudbeaver/plugin-codemirror6": "~0.1.0",
|
||||
"@cloudbeaver/plugin-navigation-tabs": "~0.1.0",
|
||||
"@cloudbeaver/plugin-object-viewer": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0",
|
||||
"reshadow": "^0.0.1",
|
||||
@@ -72,10 +72,10 @@
|
||||
"@cloudbeaver/plugin-navigation-tree": "~0.1.0",
|
||||
"@cloudbeaver/plugin-object-viewer": "~0.1.0",
|
||||
"@cloudbeaver/tests-runner": "~0.1.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ServerErrorType, ServerInternalError } from '@cloudbeaver/core-sdk';
|
||||
import { errorOf } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const style = css`
|
||||
error {
|
||||
@@ -110,11 +111,6 @@ export const TableError = observer<Props>(function TableError({ model, loading,
|
||||
false,
|
||||
);
|
||||
|
||||
if (errorInfo.error !== model.source.error) {
|
||||
errorInfo.error = model.source.error || null;
|
||||
errorInfo.display = !!model.source.error;
|
||||
}
|
||||
|
||||
const internalServerError = errorOf(model.source.error, ServerInternalError);
|
||||
const error = useErrorDetails(model.source.error);
|
||||
const animated = useStateDelay(!!errorInfo.error && !loading, 1);
|
||||
@@ -139,6 +135,15 @@ export const TableError = observer<Props>(function TableError({ model, loading,
|
||||
};
|
||||
}
|
||||
|
||||
// keep it like this or remove error another way:
|
||||
// console goes with error that we cannot modify ref value in render method.
|
||||
useEffect(() => {
|
||||
if (errorInfo.error !== model.source.error) {
|
||||
errorInfo.error = model.source.error || null;
|
||||
errorInfo.display = !!model.source.error;
|
||||
}
|
||||
}, [errorInfo, model.source.error]);
|
||||
|
||||
return styled(style)(
|
||||
<error {...use({ animated, collapsed: !errorInfo.display, errorHidden })} className={className}>
|
||||
<error-body>
|
||||
|
||||
@@ -31,14 +31,14 @@
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-navigation-tabs": "~0.1.0",
|
||||
"@cloudbeaver/plugin-top-app-bar": "~0.1.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx": "^6.12.0",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.25",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-plugin-css-modules": "^5.0.1"
|
||||
"@types/react": "^18.2.42",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@
|
||||
{
|
||||
"path": "../core-resource/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../core-theming/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../core-ui/tsconfig.json"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user