Merge branch 'devel' into CB-4325-remove-preloaded-property-from-useResource-hook

This commit is contained in:
s.teleshev
2023-12-12 12:00:35 +01:00
28 changed files with 136 additions and 260 deletions
+1 -1
View File
@@ -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
@@ -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;
@@ -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> 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> T getAttribute(String name, Function<T, T> creator, Function<T, T> 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 <T> boolean isAuthInfoInstanceOf(WebAuthInfo authInfo, Class<T> adapter) {
if (authInfo != null && authInfo.getAuthSession() != null) {
if (adapter.isInstance(authInfo.getAuthSession())) {
return true;
}
return adapter.isInstance(authInfo.getAuthSession());
}
return false;
}
@@ -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());
}
}
@@ -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);
}
@@ -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<DBDAttributeConstraint> constraints = new ArrayList<>();
boolean hasKey = true;
for (DBDAttributeBinding attr : resultsInfo.getAttributes()) {
// get attributes only from row identifiers
Set<DBDAttributeBinding> 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,
@@ -2222,12 +2222,12 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
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<T extends WebAuthApplication>
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<T extends WebAuthApplication>
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);
}
}
@@ -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);
@@ -72,12 +72,12 @@ export const Switch: SwitchType = observer(function Switch({
}
return (
<Field data-testid="field" title={rest.title}>
<div data-testid="switch-body" className={styles.switchBody}>
<div data-testid="switch-control" className={s(styles, { switchControl: true, disabled: disabled, checked: checkboxState.checked })}>
<div data-testid="switch-control-track" className={styles.switchControlTrack} />
<div data-testid="switch-control-underlay" className={styles.switchControlUnderlay}>
<div data-testid="switch-control-thumb" className={styles.switchControlThumb} />
<Field title={rest.title}>
<div className={styles.switchBody}>
<div className={s(styles, { switchControl: true, disabled: disabled, checked: checkboxState.checked })}>
<div className={styles.switchControlTrack} />
<div className={styles.switchControlUnderlay}>
<div className={styles.switchControlThumb} />
<input
{...rest}
type="checkbox"
@@ -86,13 +86,12 @@ export const Switch: SwitchType = observer(function Switch({
aria-checked={checkboxState.checked}
checked={checkboxState.checked}
disabled={disabled}
data-testid="switch-input"
className={styles.switchInput}
onChange={checkboxState.change}
/>
</div>
</div>
<FieldLabel htmlFor={id || value || name} data-testid="field-label" className={styles.fieldLabel}>
<FieldLabel htmlFor={id || value || name} className={styles.fieldLabel}>
{children}
</FieldLabel>
</div>
@@ -293,13 +293,7 @@ export const Combobox: ComboboxType = observer(function Combobox({
<MenuButton {...menu} disabled={readOnly || disabled || hideMenu} className={styles.menuButton}>
<Icon name="arrow" viewBox="0 0 16 16" className={s(styles, { icon: true, focus })} />
</MenuButton>
<Menu
{...menu}
ref={menuRef}
aria-label={propertyName}
className={s(styles, { menu: true })}
modal
>
<Menu {...menu} ref={menuRef} aria-label={propertyName} className={s(styles, { menu: true })} modal>
{!filteredItems.length ? (
<MenuItem id="placeholder" disabled {...menu} className={s(styles, { menuItem: true })}>
{translate('combobox_no_results_placeholder')}
@@ -322,11 +316,11 @@ export const Combobox: ComboboxType = observer(function Combobox({
onClick={event => handleSelect(event.currentTarget.id)}
>
{iconSelector && (
<div data-testid="item-icon" className={s(styles, { itemIcon: true })}>
<div className={s(styles, { itemIcon: true })}>
{icon && typeof icon === 'string' ? <IconOrImage icon={icon} className={s(styles, { iconOrImage: true })} /> : icon}
</div>
)}
<div data-testid="item-value">{valueSelector(item)}</div>
<div>{valueSelector(item)}</div>
</MenuItem>
);
})
@@ -192,11 +192,7 @@ export const InputField: InputFieldType = observer<ControlledProps | ObjectProps
<Icon name="copy" viewBox="0 0 32 32" className={styles.icon} />
</div>
)}
{icon && (
<div data-testid="icon-container" className={s(styles, { customIconContainer: true })}>
{icon}
</div>
)}
{icon && <div className={s(styles, { customIconContainer: true })}>{icon}</div>}
</div>
{(description || passwordType) && <FieldDescription invalid={error}>{description}</FieldDescription>}
</Field>
@@ -17,14 +17,12 @@ interface Props {
export const SnackbarBody: React.FC<React.PropsWithChildren<Props>> = function SnackbarBody({ title, className, children }) {
const styles = useS(style);
return (
<div data-testid="notification-body" className={s(styles, { notificationBody: true }, className)}>
<div data-testid="body-text-block" className={styles.bodyTextBlock}>
<h2 data-testid="text-block-title" title={title} className={styles.textBlockTitle}>
<div className={s(styles, { notificationBody: true }, className)}>
<div className={styles.bodyTextBlock}>
<h2 title={title} className={styles.textBlockTitle}>
{title}
</h2>
<div data-testid="message" className={styles.message}>
{children}
</div>
<div className={styles.message}>{children}</div>
</div>
</div>
);
@@ -15,9 +15,5 @@ interface Props {
export const SnackbarContent: React.FC<React.PropsWithChildren<Props>> = function SnackbarContent({ children, className }) {
const styles = useS(style);
return (
<div data-testid="notification-content" className={s(styles, { notificationContent: true }, className)}>
{children}
</div>
);
return <div className={s(styles, { notificationContent: true }, className)}>{children}</div>;
};
@@ -19,13 +19,9 @@ export const SnackbarFooter: React.FC<React.PropsWithChildren<Props>> = function
const timeStringFromTimestamp = new Date(timestamp).toLocaleTimeString();
return (
<div data-testid="notification-footer" className={s(styles, { notificationFooter: true }, className)}>
<span data-testid="footer-time" className={styles.footerTime}>
{timeStringFromTimestamp}
</span>
<div data-testid="actions" className={styles.actions}>
{children}
</div>
<div className={s(styles, { notificationFooter: true }, className)}>
<span className={styles.footerTime}>{timeStringFromTimestamp}</span>
<div className={styles.actions}>{children}</div>
</div>
);
};
@@ -21,7 +21,7 @@ interface SnackbarStatusProps {
export const SnackbarStatus: React.FC<SnackbarStatusProps> = function SnackbarStatus({ status, className }) {
const styles = useS(style);
return status === ENotificationType.Loading ? (
<div data-testid="loader-container" className={s(styles, { loaderContainer: true }, className)}>
<div className={s(styles, { loaderContainer: true }, className)}>
<Loader className={styles.loader} hideMessage />
</div>
) : (
@@ -34,7 +34,7 @@ export const SnackbarWrapper: React.FC<React.PropsWithChildren<Props>> = functio
}, []);
return (
<div data-testid="notification" className={s(styles, { notification: true, mounted, closing }, className)}>
<div className={s(styles, { notification: true, mounted, closing }, className)}>
{children}
{!persistent && onClose && (
<IconButton name="cross" viewBox="0 0 16 16" className={s(styles, { iconButton: true, large: true })} onClick={onClose} />
@@ -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),
};
};
-3
View File
@@ -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"
},
@@ -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<FunctionType>): 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<VisitorState> = {
JSXFragment(path) {
path.skip();
},
JSXElement(path, { name }) {
const openingElement = path.get('openingElement');
path.skip();
addTestIdAttribute(openingElement.node, name);
},
};
const functionVisitor: Visitor<VisitorState> = {
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<FunctionType>) => {
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;
}
@@ -1,10 +0,0 @@
{
"extends": "./tsconfig.json",
"include": [
"src",
"tests",
"bin",
"configs"
],
"exclude": ["**/node_modules", "**/lib"]
}
-13
View File
@@ -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/**/*"]
}
@@ -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"],
@@ -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'],
@@ -103,6 +103,7 @@ export default [
['ui_upload_file_fail', 'Не удалось загрузить файл'],
['ui_filter', 'Фильтр'],
['ui_disable', 'Отключить'],
['ui_test', 'Проверить'],
['root_permission_denied', 'Отказано в доступе'],
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
@@ -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', '您没有权限执行此操作'],
@@ -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<Props>(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)(
<Container className={props.className} gap vertical>
<GroupItem keepSize>{translate('authentication_request_token')}</GroupItem>
<GroupItem keepSize>
<Button type="button" mod={['unelevated']} loading={action.authenticating} onClick={action.auth}>
{translate('authentication_authenticate')}
</Button>
</GroupItem>
</Container>,
return (
<Container className={props.className} gap vertical center>
<Container keepSize center vertical gap dense>
<Container keepSize>{translate('authentication_request_token')}</Container>
<Container keepSize>
<Button type="button" mod={['unelevated']} loading={action.authenticating} onClick={action.auth}>
{translate('authentication_authenticate')}
</Button>
</Container>
</Container>
</Container>
);
});
@@ -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<IConnectionFormProps> = observer(function OriginInfo({ tabId, state: { info, resource } }) {
export const OriginInfo: TabContainerPanelComponent<IConnectionFormProps> = 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<Record<string, any>>();
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<IConnectionFormProps> = 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<IConnectionFormProps> = obse
);
}
// const authorized = !info?.origin || userInfoService.hasOrigin(info.origin);
// if (!authorized && info?.origin) {
// return styled(styles)(
// <ColoredContainer parent vertical>
// <AuthenticationProvider origin={info.origin} onAuthenticate={connection.reload} />
// </ColoredContainer>
// );
// }
if (!isAuthenticated) {
return styled(styles)(
<ColoredContainer parent>
<TextPlaceholder>
{translate('connections_public_connection_cloud_auth_required', undefined, {
providerLabel: providerLoader.data?.label,
})}
</TextPlaceholder>
</ColoredContainer>,
);
}
if (!connection.data?.origin.details || connection.data.origin.details.length === 0) {
return styled(styles)(
@@ -38,7 +38,7 @@ const NavTreeLimitMessage: NavigationNodeRendererComponent = observer(function N
}
return (
<div className={s(styles, { loadMoreBox: true })} data-testid="load-more-box">
<div className={s(styles, { loadMoreBox: true })}>
<Link title={translate('app_navigationTree_limited', undefined, { limit: limit })} onClick={loadMore}>
{translate('ui_load_more')}
</Link>