From 669ad9cb66e09aff151917173a782744da70e97c Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:57:21 +0100 Subject: [PATCH 1/9] CB-4328 get updated rows info only using key identifier attributes (#2193) * CB-4328 get updated rows info only using key identifier attributes * CB-4328 do not refresh row for nosql db --- .../service/sql/WebSQLResultsInfo.java | 12 ++++++--- .../service/sql/WebSQLProcessor.java | 27 ++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java index 3fd68da3c2..77a3aeae1b 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/sql/WebSQLResultsInfo.java @@ -22,9 +22,7 @@ import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.data.DBDRowIdentifier; -import org.jkiss.dbeaver.model.struct.DBSAttributeBase; -import org.jkiss.dbeaver.model.struct.DBSDataContainer; -import org.jkiss.dbeaver.model.struct.DBSTypedObject; +import org.jkiss.dbeaver.model.struct.*; import java.util.HashSet; import java.util.List; @@ -126,4 +124,12 @@ public class WebSQLResultsInfo { return null; } + public boolean canRefreshResults() { + DBSEntity entity = getDefaultRowIdentifier().getEntity(); + // FIXME: do not refresh documents for now. Can be solved by extracting document ID attributes + // FIXME: but it will require to provide dynamic document metadata. + return entity == null || entity.getDataSource() == null || + (!(entity instanceof DBSDocumentContainer) && !entity.getDataSource().getInfo().isDynamicMetadata()); + } + } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java index eef4bc19f6..c58d93e43a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLProcessor.java @@ -58,6 +58,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * Web SQL processor. @@ -417,13 +418,22 @@ public class WebSQLProcessor implements WebSessionProvider { DBCExecutionPurpose.UTIL, "Refresh row(s) after insert/update") ) { + boolean canRefreshResults = resultsInfo.canRefreshResults(); for (Object[] row : newResultSetRows) { if (row.length == 0) { continue; } + if (!canRefreshResults) { + makeWebCellRow(resultsInfo, row, dataFormat); + continue; + } List constraints = new ArrayList<>(); boolean hasKey = true; - for (DBDAttributeBinding attr : resultsInfo.getAttributes()) { + // get attributes only from row identifiers + Set idAttributes = resultsInfo.getRowIdentifiers().stream() + .flatMap(r -> r.getAttributes().stream()) + .collect(Collectors.toSet()); + for (DBDAttributeBinding attr : idAttributes) { if (attr.getRowIdentifier() == null) { continue; } @@ -439,6 +449,7 @@ public class WebSQLProcessor implements WebSessionProvider { } if (!hasKey) { // No key value for this row + makeWebCellRow(resultsInfo, row, dataFormat); continue; } DBDDataFilter filter = new DBDDataFilter(constraints); @@ -457,6 +468,20 @@ public class WebSQLProcessor implements WebSessionProvider { } } + private void makeWebCellRow( + @NotNull WebSQLResultsInfo resultsInfo, + @NotNull Object[] row, + @Nullable WebDataFormat dataFormat + ) throws DBCException { + for (int i = 0; i < row.length; i++) { + row[i] = WebSQLUtils.makeWebCellValue( + webSession, + resultsInfo.getAttributeByPosition(i), + row[i], + dataFormat); + } + } + public String generateResultsDataUpdateScript( @NotNull DBRProgressMonitor monitor, @NotNull WebSQLContextInfo contextInfo, From b83cd0d8830d1196ddb5f6494f53173c3573ea8f Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 6 Dec 2023 09:54:51 +0300 Subject: [PATCH 2/9] CB-4060 feat: remove data-testid attribute (#2166) Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> --- .../src/FormControls/Checkboxes/Switch.tsx | 15 +-- .../core-blocks/src/FormControls/Combobox.tsx | 12 +- .../src/FormControls/InputField.tsx | 6 +- .../SnackbarMarkups/SnackbarBody.tsx | 10 +- .../SnackbarMarkups/SnackbarContent.tsx | 6 +- .../SnackbarMarkups/SnackbarFooter.tsx | 10 +- .../SnackbarMarkups/SnackbarStatus.tsx | 2 +- .../SnackbarMarkups/SnackbarWrapper.tsx | 2 +- .../packages/core-cli/configs/babel.config.js | 4 +- webapp/packages/core-cli/package.json | 3 - .../src/babel-plugins/TestingAttributes.ts | 122 ------------------ webapp/packages/core-cli/tsconfig.eslint.json | 10 -- webapp/packages/core-cli/tsconfig.json | 13 -- .../elementsTreeLimitRenderer.tsx | 2 +- 14 files changed, 23 insertions(+), 194 deletions(-) delete mode 100644 webapp/packages/core-cli/src/babel-plugins/TestingAttributes.ts delete mode 100644 webapp/packages/core-cli/tsconfig.eslint.json delete mode 100644 webapp/packages/core-cli/tsconfig.json diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index 53eff392f7..f2d0428593 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -72,12 +72,12 @@ export const Switch: SwitchType = observer(function Switch({ } return ( - -
-
-
-
-
+ +
+
+
+
+
- + {children}
diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index da3dfedde8..6de6b05ef0 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -293,13 +293,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ - + {!filteredItems.length ? ( {translate('combobox_no_results_placeholder')} @@ -322,11 +316,11 @@ export const Combobox: ComboboxType = observer(function Combobox({ onClick={event => handleSelect(event.currentTarget.id)} > {iconSelector && ( -
+
{icon && typeof icon === 'string' ? : icon}
)} -
{valueSelector(item)}
+
{valueSelector(item)}
); }) diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index d539a096b8..38c8ac28ee 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -192,11 +192,7 @@ export const InputField: InputFieldType = observer
)} - {icon && ( -
- {icon} -
- )} + {icon &&
{icon}
}
{(description || passwordType) && {description}} diff --git a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarBody.tsx b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarBody.tsx index f1e3b6e82d..f0143e9d0c 100644 --- a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarBody.tsx +++ b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarBody.tsx @@ -17,14 +17,12 @@ interface Props { export const SnackbarBody: React.FC> = function SnackbarBody({ title, className, children }) { const styles = useS(style); return ( -
-
-

+
+
+

{title}

-
- {children} -
+
{children}
); diff --git a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarContent.tsx b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarContent.tsx index 2fcfa97835..a03a41b53f 100644 --- a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarContent.tsx +++ b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarContent.tsx @@ -15,9 +15,5 @@ interface Props { export const SnackbarContent: React.FC> = function SnackbarContent({ children, className }) { const styles = useS(style); - return ( -
- {children} -
- ); + return
{children}
; }; diff --git a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarFooter.tsx b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarFooter.tsx index b21d7b9258..9e12c1aa2a 100644 --- a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarFooter.tsx +++ b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarFooter.tsx @@ -19,13 +19,9 @@ export const SnackbarFooter: React.FC> = function const timeStringFromTimestamp = new Date(timestamp).toLocaleTimeString(); return ( -
- - {timeStringFromTimestamp} - -
- {children} -
+
+ {timeStringFromTimestamp} +
{children}
); }; diff --git a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarStatus.tsx b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarStatus.tsx index 5a8280c6d2..7cf0d70937 100644 --- a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarStatus.tsx +++ b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarStatus.tsx @@ -21,7 +21,7 @@ interface SnackbarStatusProps { export const SnackbarStatus: React.FC = function SnackbarStatus({ status, className }) { const styles = useS(style); return status === ENotificationType.Loading ? ( -
+
) : ( diff --git a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarWrapper.tsx b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarWrapper.tsx index 9ec5395fd7..55a5ec3e22 100644 --- a/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarWrapper.tsx +++ b/webapp/packages/core-blocks/src/Snackbars/SnackbarMarkups/SnackbarWrapper.tsx @@ -34,7 +34,7 @@ export const SnackbarWrapper: React.FC> = functio }, []); return ( -
+
{children} {!persistent && onClose && ( diff --git a/webapp/packages/core-cli/configs/babel.config.js b/webapp/packages/core-cli/configs/babel.config.js index e62889387d..6643caab6f 100644 --- a/webapp/packages/core-cli/configs/babel.config.js +++ b/webapp/packages/core-cli/configs/babel.config.js @@ -5,8 +5,6 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -/* eslint-disable @typescript-eslint/no-var-requires */ -const testingAttributes = require('../dist/babel-plugins/TestingAttributes.js'); module.exports = api => { const devMode = !api.env('production'); @@ -28,6 +26,6 @@ module.exports = api => { }, ], ], - plugins: [[testingAttributes, {}], [require('@reshadow/babel'), {}], devMode && require.resolve('react-refresh/babel')].filter(Boolean), + plugins: [[require('@reshadow/babel'), {}], devMode && require.resolve('react-refresh/babel')].filter(Boolean), }; }; diff --git a/webapp/packages/core-cli/package.json b/webapp/packages/core-cli/package.json index d162469a1c..af5cf68f37 100644 --- a/webapp/packages/core-cli/package.json +++ b/webapp/packages/core-cli/package.json @@ -21,9 +21,6 @@ "core-cli-validate-dependencies": "./bin/validate-dependencies.js", "typescript-resolve-references": "./bin/typescript-resolve-references.js" }, - "scripts": { - "install": "tsc" - }, "engines": { "node": ">=16.0.0" }, diff --git a/webapp/packages/core-cli/src/babel-plugins/TestingAttributes.ts b/webapp/packages/core-cli/src/babel-plugins/TestingAttributes.ts deleted file mode 100644 index d5a814d96e..0000000000 --- a/webapp/packages/core-cli/src/babel-plugins/TestingAttributes.ts +++ /dev/null @@ -1,122 +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. - */ - -/** - * Based on https://github.com/akameco/babel-plugin-react-data-testid - */ -import type { NodePath, PluginObj, Visitor } from '@babel/core'; -import syntaxJsx from '@babel/plugin-syntax-jsx'; -import * as t from '@babel/types'; - -type FunctionType = t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression; - -function addTestIdAttribute(node: t.JSXOpeningElement, name: string): void { - if ( - t.isJSXIdentifier(node.name) && - node.name.name !== 'Fragment' && - node.name.name !== '_Fragment' && - !hasDataAttribute(node, DEFAULT_DATA_TESTID) - ) { - const dataAttribute = createDataAttribute(name, DEFAULT_DATA_TESTID); - const indexOf = node.attributes.findIndex(attribute => t.isJSXSpreadAttribute(attribute)); - if (indexOf !== -1) { - node.attributes.splice(indexOf, 0, dataAttribute); - } else { - node.attributes.push(dataAttribute); - } - } -} - -function nameForReactComponent(path: NodePath): t.Identifier | null { - const { parentPath } = path; - if (!t.isArrowFunctionExpression(path.node) && t.isIdentifier(path.node.id)) { - return path.node.id; - } - if (t.isVariableDeclarator(parentPath.node)) { - // @ts-expect-error expected - return parentPath.node.id; - } - return null; -} - -const DEFAULT_DATA_TESTID = 'data-testid'; - -function createDataAttribute(name: string, attributeName: string) { - return t.jsxAttribute(t.jsxIdentifier(attributeName), t.stringLiteral(name)); -} - -function hasDataAttribute(node: t.JSXOpeningElement, attributeName: string): boolean { - return node.attributes.some(attribute => t.isJSXAttribute(attribute) && t.isJSXIdentifier(attribute.name, { name: attributeName })); -} - -type VisitorState = { name: string }; - -const returnStatementVisitor: Visitor = { - JSXFragment(path) { - path.skip(); - }, - JSXElement(path, { name }) { - const openingElement = path.get('openingElement'); - - path.skip(); - - addTestIdAttribute(openingElement.node, name); - }, -}; - -const functionVisitor: Visitor = { - ReturnStatement(path, state) { - const arg = path.get('argument'); - if (!arg.isIdentifier()) { - path.traverse(returnStatementVisitor, state); - } - }, -}; - -function getElementName(node: t.JSXOpeningElement['name']): string { - if (t.isJSXNamespacedName(node)) { - return [getElementName(node.namespace), getElementName(node.name)].join(':'); - } - - if (t.isJSXIdentifier(node)) { - return node.name; - } - - return [getElementName(node.object), getElementName(node.property)].join('.'); -} - -export default function plugin(): PluginObj { - return { - name: 'cloudbeaver-data-testid', - inherits: syntaxJsx, - visitor: { - 'FunctionExpression|ArrowFunctionExpression|FunctionDeclaration': (p: NodePath) => { - const identifier = nameForReactComponent(p); - if (!identifier) { - return; - } - - if (p.isArrowFunctionExpression()) { - p.traverse(returnStatementVisitor, { name: identifier.name }); - } else { - p.traverse(functionVisitor, { name: identifier.name }); - } - }, - CallExpression(p) { - p.traverse({ - JSXOpeningElement({ node }) { - if (t.isJSXOpeningFragment(node)) { - return; - } - addTestIdAttribute(node, getElementName(node.name)); - }, - }); - }, - }, - } as PluginObj; -} diff --git a/webapp/packages/core-cli/tsconfig.eslint.json b/webapp/packages/core-cli/tsconfig.eslint.json deleted file mode 100644 index 8fdecd8c25..0000000000 --- a/webapp/packages/core-cli/tsconfig.eslint.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "src", - "tests", - "bin", - "configs" - ], - "exclude": ["**/node_modules", "**/lib"] -} \ No newline at end of file diff --git a/webapp/packages/core-cli/tsconfig.json b/webapp/packages/core-cli/tsconfig.json deleted file mode 100644 index 008f4e3574..0000000000 --- a/webapp/packages/core-cli/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "rootDir": "src", - "module": "CommonJS", - "outDir": "dist", - "moduleResolution": "node", - "esModuleInterop": true, - "emitDeclarationOnly": false, - "skipLibCheck": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules/**/*", "dist/**/*", "tests/**/*"] -} diff --git a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/NavTreeLimitFilter/elementsTreeLimitRenderer.tsx b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/NavTreeLimitFilter/elementsTreeLimitRenderer.tsx index 68742c71cc..373403a62f 100644 --- a/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/NavTreeLimitFilter/elementsTreeLimitRenderer.tsx +++ b/webapp/packages/plugin-navigation-tree/src/NavigationTree/ElementsTree/NavTreeLimitFilter/elementsTreeLimitRenderer.tsx @@ -38,7 +38,7 @@ const NavTreeLimitMessage: NavigationNodeRendererComponent = observer(function N } return ( -
+
{translate('ui_load_more')} From bb3ee1d82212944e6dfc7a53b4c0a3037cf3573c Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 6 Dec 2023 20:36:05 +0300 Subject: [PATCH 3/9] CB-4317 fix: require authentication to load connection origin details (#2189) * CB-4317 fix: require authentication to load connection origin details * CB-4317 fix: ensure user loaded and up to date --------- Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- .../core-ui/src/AuthenticationProvider.tsx | 31 ++++++-------- .../ConnectionForm/OriginInfo/OriginInfo.tsx | 42 +++++++++++++------ 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/webapp/packages/core-ui/src/AuthenticationProvider.tsx b/webapp/packages/core-ui/src/AuthenticationProvider.tsx index eb4eb0d3f3..955a306948 100644 --- a/webapp/packages/core-ui/src/AuthenticationProvider.tsx +++ b/webapp/packages/core-ui/src/AuthenticationProvider.tsx @@ -6,19 +6,11 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; -import styled, { css } from 'reshadow'; -import { Button, Container, GroupItem, useStyles, useTranslate } from '@cloudbeaver/core-blocks'; +import { Button, Container, useTranslate } from '@cloudbeaver/core-blocks'; import { useAuthenticationAction } from './useAuthenticationAction'; -const styles = css` - Container { - justify-content: center; - align-items: center; - } -`; - export type Props = { providerId: string; className?: string; @@ -29,21 +21,22 @@ export type Props = { export const AuthenticationProvider = observer(function AuthenticationProvider(props) { const translate = useTranslate(); - const style = useStyles(styles); const action = useAuthenticationAction(props); if (action.authorized) { return (props.children?.() as null) || null; } - return styled(style)( - - {translate('authentication_request_token')} - - - - , + return ( + + + {translate('authentication_request_token')} + + + + + ); }); diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx index a073ceecbc..15cb5587f7 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/OriginInfo/OriginInfo.tsx @@ -9,6 +9,7 @@ import { runInAction } from 'mobx'; import { observer } from 'mobx-react-lite'; import styled, { css } from 'reshadow'; +import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource, UserInfoResource } from '@cloudbeaver/core-authentication'; import { ColoredContainer, ExceptionMessage, @@ -20,7 +21,7 @@ import { useStyles, useTranslate, } from '@cloudbeaver/core-blocks'; -import { createConnectionParam } from '@cloudbeaver/core-connections'; +import { createConnectionParam, DatabaseAuthModelsResource, DBDriverResource } from '@cloudbeaver/core-connections'; import { TabContainerPanelComponent, useTab, useTabState } from '@cloudbeaver/core-ui'; import type { IConnectionFormProps } from '../IConnectionFormProps'; @@ -38,12 +39,25 @@ const style = css` } `; -export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ tabId, state: { info, resource } }) { +export const OriginInfo: TabContainerPanelComponent = observer(function OriginInfo({ + tabId, + state: { info, resource, config }, +}) { const tab = useTab(tabId); const translate = useTranslate(); - // const userInfoService = useService(UserInfoResource); + const userInfoLoader = useResource(OriginInfo, UserInfoResource, undefined); const state = useTabState>(); const styles = useStyles(style); + const driverLoader = useResource(OriginInfo, DBDriverResource, config.driverId ?? null); + const authModeLoader = useResource( + OriginInfo, + DatabaseAuthModelsResource, + config.authModelId ?? info?.authModel ?? driverLoader.data?.defaultAuthModel ?? null, + ); + + const providerId = authModeLoader.data?.requiredAuth ?? info?.requiredAuth ?? AUTH_PROVIDER_LOCAL_ID; + const isAuthenticated = userInfoLoader.resource.hasToken(providerId); + const providerLoader = useResource(OriginInfo, AuthProvidersResource, providerId); const connection = useResource( OriginInfo, @@ -53,7 +67,7 @@ export const OriginInfo: TabContainerPanelComponent = obse includes: ['includeOrigin', 'customIncludeOriginDetails'] as const, }, { - // isActive: () => !info?.origin || userInfoService.hasOrigin(info.origin), + active: isAuthenticated, onData: connection => { runInAction(() => { if (!connection.origin.details) { @@ -89,15 +103,17 @@ export const OriginInfo: TabContainerPanelComponent = obse ); } - // const authorized = !info?.origin || userInfoService.hasOrigin(info.origin); - - // if (!authorized && info?.origin) { - // return styled(styles)( - // - // - // - // ); - // } + if (!isAuthenticated) { + return styled(styles)( + + + {translate('connections_public_connection_cloud_auth_required', undefined, { + providerLabel: providerLoader.data?.label, + })} + + , + ); + } if (!connection.data?.origin.details || connection.data.origin.details.length === 0) { return styled(styles)( From f58f2a3c90b87c2823504a9acde0bfe9314e4a3b Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Wed, 6 Dec 2023 20:58:33 +0100 Subject: [PATCH 4/9] Update frontend.yml (#2205) --- .github/workflows/frontend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 9273521a9e..80f2da0cfb 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: "18" + node-version: "20" - name: Get yarn cache directory path id: yarn-cache-dir-path From 1220e4ba38d4a382128373ee9dfcc45ed5ec536c Mon Sep 17 00:00:00 2001 From: serge-rider Date: Thu, 7 Dec 2023 10:07:41 +0300 Subject: [PATCH 5/9] Logging and code style --- .../service/security/CBEmbeddedSecurityController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java index 2ff796f239..09e794f9c9 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java @@ -2222,12 +2222,12 @@ public class CBEmbeddedSecurityController dbStat.setString(1, token); try (var dbResult = dbStat.executeQuery()) { if (!dbResult.next()) { - throw new SMException("Invalid token"); + throw new SMException("Error reading permissions: input token not recognized."); } userId = dbResult.getString(1); var expiredDate = dbResult.getTimestamp(2); if (application.isMultiNode() && isTokenExpired(expiredDate)) { - throw new SMAccessTokenExpiredException("Token expired"); + throw new SMAccessTokenExpiredException("Error reading permissions: token has expired"); } sessionId = dbResult.getString(3); authRole = dbResult.getString(4); @@ -2296,7 +2296,7 @@ public class CBEmbeddedSecurityController dbStat.setString(6, sessionId); if (dbStat.executeUpdate() <= 0) { - throw new DBCException("Session not exists in database"); + throw new DBCException("Session '" + sessionId + "' not found in database"); } } } catch (SQLException e) { @@ -2700,12 +2700,12 @@ public class CBEmbeddedSecurityController dbStat.setString(1, smAccessToken); try (var dbResult = dbStat.executeQuery()) { if (!dbResult.next()) { - throw new SMException("Invalid token"); + throw new SMException("Error reading subject role: input token not recognized."); } return dbResult.getString(1); } } catch (SQLException e) { - throw new DBCException("Error reading lm role in database", e); + throw new DBCException("Error reading subject role in database", e); } } From 36061a03c4bf0bdde5c341c96f893dae91645281 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:26:34 +0100 Subject: [PATCH 6/9] CB-4314 add test locale (#2209) Co-authored-by: naumov --- webapp/packages/core-localization/src/locales/en.ts | 1 + webapp/packages/core-localization/src/locales/it.ts | 1 + webapp/packages/core-localization/src/locales/ru.ts | 1 + webapp/packages/core-localization/src/locales/zh.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/webapp/packages/core-localization/src/locales/en.ts b/webapp/packages/core-localization/src/locales/en.ts index c600d1aaa3..74aa073a79 100644 --- a/webapp/packages/core-localization/src/locales/en.ts +++ b/webapp/packages/core-localization/src/locales/en.ts @@ -107,6 +107,7 @@ export default [ ['ui_upload_file_fail', 'Failed to upload file'], ['ui_filter', 'Filter'], ['ui_disable', 'Disable'], + ['ui_test', 'Test'], ['root_permission_denied', "You don't have permissions"], ['root_permission_no_permission', "You don't have permission for this action"], diff --git a/webapp/packages/core-localization/src/locales/it.ts b/webapp/packages/core-localization/src/locales/it.ts index 438cc03d53..4e8f19f0a4 100644 --- a/webapp/packages/core-localization/src/locales/it.ts +++ b/webapp/packages/core-localization/src/locales/it.ts @@ -91,6 +91,7 @@ export default [ ['ui_upload_file_fail', 'Failed to upload file'], ['ui_filter', 'Filter'], ['ui_disable', 'Disable'], + ['ui_test', 'Test'], ['root_permission_denied', 'Non hai i permessi'], ['app_root_session_expire_warning_title', 'La sessione sta per scadere'], diff --git a/webapp/packages/core-localization/src/locales/ru.ts b/webapp/packages/core-localization/src/locales/ru.ts index 358a6cbf15..79b3ad46f7 100644 --- a/webapp/packages/core-localization/src/locales/ru.ts +++ b/webapp/packages/core-localization/src/locales/ru.ts @@ -103,6 +103,7 @@ export default [ ['ui_upload_file_fail', 'Не удалось загрузить файл'], ['ui_filter', 'Фильтр'], ['ui_disable', 'Отключить'], + ['ui_test', 'Проверить'], ['root_permission_denied', 'Отказано в доступе'], ['root_permission_no_permission', 'У вас нет разрешения на это действие'], diff --git a/webapp/packages/core-localization/src/locales/zh.ts b/webapp/packages/core-localization/src/locales/zh.ts index 7b6344b13f..7b06e38bdf 100644 --- a/webapp/packages/core-localization/src/locales/zh.ts +++ b/webapp/packages/core-localization/src/locales/zh.ts @@ -104,6 +104,7 @@ export default [ ['ui_upload_file_fail', 'Failed to upload file'], ['ui_filter', 'Filter'], ['ui_disable', 'Disable'], + ['ui_test', 'Test'], ['root_permission_denied', '您没有权限'], ['root_permission_no_permission', '您没有权限执行此操作'], From 96a163c50e4777d2bcee4d2386cf61e9cd623ee2 Mon Sep 17 00:00:00 2001 From: serge-rider Date: Fri, 8 Dec 2023 07:47:35 +0300 Subject: [PATCH 7/9] dbeaver/pro#2176 Localhost domain name resolve fix --- .../src/io/cloudbeaver/server/CBApplication.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index 1490f29247..e6ecc6f754 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -557,7 +557,12 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut } else if (serverURL == null) { String hostName = serverHost; if (CommonUtils.isEmpty(hostName)) { - hostName = InetAddress.getLocalHost().getHostName(); + try { + hostName = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + log.debug("Error resolving localhost address: " + e.getMessage()); + hostName = "localhost"; + } } serverURL = "http://" + hostName + ":" + serverPort; } @@ -604,7 +609,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut } } parseAdditionalConfiguration(configProps); - } catch (IOException | DBException e) { + } catch (DBException e) { throw new DBException("Error parsing server configuration", e); } From 43f50f2ff3bc1ff18b03bc2710fbdbd4607c0dbe Mon Sep 17 00:00:00 2001 From: serge-rider Date: Fri, 8 Dec 2023 13:35:52 +0300 Subject: [PATCH 8/9] dbeaver/pro#2176 Localhost IP resolve fix --- .../io/cloudbeaver/service/security/db/CBDatabase.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java index 778b52cd13..5c7f2933bf 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabase.java @@ -57,6 +57,7 @@ import org.jkiss.utils.SecurityUtils; import java.io.*; import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.sql.*; import java.util.*; @@ -458,8 +459,12 @@ public class CBDatabase { } private void checkInstanceRecord(Connection connection) throws SQLException, IOException { - InetAddress localHost = InetAddress.getLocalHost(); - String hostName = localHost.getHostName(); + String hostName; + try { + hostName = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + hostName = "localhost"; + } byte[] hardwareAddress = RuntimeUtils.getLocalMacAddress(); String macAddress = CommonUtils.toHexString(hardwareAddress); From 21a9e78381c2cf80e9d63c9cc04dbfd1a2f109f9 Mon Sep 17 00:00:00 2001 From: serge-rider Date: Sat, 9 Dec 2023 17:19:08 +0300 Subject: [PATCH 9/9] Code style --- .../model/session/WebAuthInfo.java | 3 +- .../cloudbeaver/model/session/WebSession.java | 30 +++++++------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java index eefd83a59d..5202eca26e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebAuthInfo.java @@ -54,7 +54,8 @@ public class WebAuthInfo implements SMSessionPrincipal { @NotNull WebAuthProviderDescriptor authProvider, @NotNull DBWUserIdentity userIdentity, @NotNull SMSession authSession, - @NotNull OffsetDateTime loginTime) { + @NotNull OffsetDateTime loginTime + ) { this.session = session; this.user = user; this.authProvider = authProvider; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index ff50e74320..928551b057 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -273,28 +273,22 @@ public class WebSession extends BaseWebSession continue; } switch (type) { - case DATASOURCE_CREATED: { + case DATASOURCE_CREATED -> { WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds); this.connections.put(connectionInfo.getId(), connectionInfo); sendDataSourceUpdatedEvent = true; - break; } - case DATASOURCE_UPDATED: { - // if settings were changed we need to send event + case DATASOURCE_UPDATED -> // if settings were changed we need to send event sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId)); - break; - } - case DATASOURCE_DELETED: { + case DATASOURCE_DELETED -> { WebDataSourceUtils.disconnectDataSource(this, ds); - if (registry instanceof DBPDataSourceRegistryCache) { - ((DBPDataSourceRegistryCache) registry).removeDataSourceFromList(ds); + if (registry instanceof DBPDataSourceRegistryCache dsrc) { + dsrc.removeDataSourceFromList(ds); } this.connections.remove(ds.getId()); sendDataSourceUpdatedEvent = true; - break; } - default: { - break; + default -> { } } } @@ -764,8 +758,8 @@ public class WebSession extends BaseWebSession public T getAttribute(String name) { synchronized (attributes) { Object value = attributes.get(name); - if (value instanceof PersistentAttribute) { - value = ((PersistentAttribute) value).getValue(); + if (value instanceof PersistentAttribute persistentAttribute) { + value = persistentAttribute.getValue(); } return (T) value; } @@ -780,8 +774,8 @@ public class WebSession extends BaseWebSession public T getAttribute(String name, Function creator, Function disposer) { synchronized (attributes) { Object value = attributes.get(name); - if (value instanceof PersistentAttribute) { - value = ((PersistentAttribute) value).getValue(); + if (value instanceof PersistentAttribute persistentAttribute) { + value = persistentAttribute.getValue(); } if (value == null) { value = creator.apply(null); @@ -965,9 +959,7 @@ public class WebSession extends BaseWebSession private boolean isAuthInfoInstanceOf(WebAuthInfo authInfo, Class adapter) { if (authInfo != null && authInfo.getAuthSession() != null) { - if (adapter.isInstance(authInfo.getAuthSession())) { - return true; - } + return adapter.isInstance(authInfo.getAuthSession()); } return false; }