console: show total max connections in pool settings fields for CE/EE/Cloud

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6080
GitOrigin-RevId: aafa8350f8d00d3f8ddb6e51964f06a25455aac5
This commit is contained in:
Varun Choudhary 2022-10-17 16:06:37 +05:30 committed by hasura-bot
parent 06138634bc
commit b60b38d70b
8 changed files with 128 additions and 61 deletions

View File

@ -1,11 +1,13 @@
import React, { InputHTMLAttributes } from 'react';
import { IconTooltip } from '@/new-components/Tooltip';
import { FaExclamationTriangle } from 'react-icons/fa';
interface LabeledInputProps extends InputHTMLAttributes<HTMLInputElement> {
label: string;
boldlabel?: boolean;
tooltipText?: string;
type?: string;
icon?: boolean;
}
export const LabeledInput: React.FC<LabeledInputProps> = props => (
@ -17,6 +19,7 @@ export const LabeledInput: React.FC<LabeledInputProps> = props => (
>
{props?.boldlabel ? <b>{props.label}</b> : props.label}
{props.tooltipText && <IconTooltip message={props.tooltipText} />}
{props.icon && <FaExclamationTriangle className="text-blue-300 ml-xs" />}
</label>
<input
type={props?.type ?? 'text'}

View File

@ -90,6 +90,7 @@ const ConnectDatabaseForm = (props: ConnectDatabaseFormProps) => {
connectionTypeState,
isReadReplica = false,
title,
isEditState,
} = props;
const isDBSupported = (driver: Driver, connectionType: string) => {
@ -385,6 +386,7 @@ const ConnectDatabaseForm = (props: ConnectDatabaseFormProps) => {
<ConnectionSettingsForm
connectionDBState={connectionDBState}
connectionDBStateDispatch={connectionDBStateDispatch}
isEditState={isEditState}
/>
{/*
TODO: remove the edit state condition when the BE issue is solved

View File

@ -1,3 +1,6 @@
/* eslint-disable no-underscore-dangle */
import { useMetadata } from '@/features/MetadataAPI';
import { isProConsole } from '@/utils/proConsole';
import React, { Dispatch } from 'react';
import { ConnectDBActions, ConnectDBState } from '../state';
import { buildFormSettings } from './buildFormSettings';
@ -11,15 +14,26 @@ import {
PreparedStatements,
Retries,
SSLCertificates,
CumulativeMaxConnections,
} from './parts';
export interface ConnectionSettingsFormProps {
connectionDBState: ConnectDBState;
connectionDBStateDispatch: Dispatch<ConnectDBActions>;
isEditState?: boolean;
}
const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = props => {
const { connectionDBState } = props;
const { connectionDBState, isEditState } = props;
const { data: metadata } = useMetadata();
const currentDBState = metadata?.metadata?.sources.find(
d => d.name === connectionDBState?.displayName
);
const isMaxConnectionSet =
currentDBState?.configuration?.connection_info?.pool_settings
?.max_connections;
const formSettings = React.useMemo(
() => buildFormSettings(connectionDBState.dbType),
@ -28,12 +42,29 @@ const ConnectionSettingsForm: React.FC<ConnectionSettingsFormProps> = props => {
if (!formSettings.connectionSettings) return null;
if (!isEditState) {
return (
<FormContainer>
{!isProConsole(window.__env) && <MaxConnections {...props} />}
{formSettings.cumulativeMaxConnections && (
<CumulativeMaxConnections {...props} />
)}
<IdleTimeout {...props} />
{formSettings.retries && <Retries {...props} />}
{formSettings.pool_timeout && <PoolTimeout {...props} />}
{formSettings.connection_lifetime && <ConnectionLifetime {...props} />}
{formSettings.isolation_level && <IsolationLevel {...props} />}
{formSettings.prepared_statements && <PreparedStatements {...props} />}
{formSettings.ssl_certificates && <SSLCertificates {...props} />}
</FormContainer>
);
}
return (
<FormContainer>
<MaxConnections {...props} />
{/* {formSettings.cumulativeMaxConnections && (
{isMaxConnectionSet && <MaxConnections {...props} />}
{formSettings.cumulativeMaxConnections && (
<CumulativeMaxConnections {...props} />
)} */}
)}
<IdleTimeout {...props} />
{formSettings.retries && <Retries {...props} />}
{formSettings.pool_timeout && <PoolTimeout {...props} />}

View File

@ -1,30 +1,50 @@
import React from 'react';
import { LabeledInput } from '@/components/Common/LabeledInput';
import { ConnectionSettingsFormProps } from '@/components/Services/Data/DataSources/ConnectionSettings/ConnectionSettingsForm';
import React from 'react';
import { IndicatorCard } from '@/new-components/IndicatorCard';
import { FaExclamationTriangle } from 'react-icons/fa';
import styles from '../../DataSources.module.scss';
export const CumulativeMaxConnections: React.VFC<ConnectionSettingsFormProps> =
({ connectionDBState, connectionDBStateDispatch }) => (
<div className={styles.connection_settings_input_layout}>
<LabeledInput
label="Cumulative Max Connections"
tooltipText="Maximum number of database connections"
type="number"
className={`form-control ${styles.connnection_settings_form_input}`}
placeholder="50"
value={
connectionDBState.connectionSettings?.cumulative_max_connections ||
undefined
}
onChange={e =>
connectionDBStateDispatch({
type: 'UPDATE_CUMULATIVE_MAX_CONNECTIONS',
data: e.target.value,
})
}
min="0"
boldlabel
data-test="max-connections"
/>
</div>
<>
<div className={styles.connection_settings_input_layout}>
<LabeledInput
label="Total Max Connections"
tooltipText="Maximum number of database connections"
type="number"
className={`form-control ${styles.connnection_settings_form_input}`}
placeholder="50"
value={
connectionDBState.connectionSettings?.total_max_connections ||
undefined
}
onChange={e =>
connectionDBStateDispatch({
type: 'UPDATE_TOTAL_MAX_CONNECTIONS',
data: e.target.value,
})
}
min="0"
boldlabel
data-test="max-connections"
icon={
connectionDBState?.connectionSettings?.max_connections !== undefined
}
/>
</div>
{connectionDBState?.connectionSettings?.max_connections && (
<IndicatorCard status="info">
<p className="font-bold">
<FaExclamationTriangle className="text-blue-300 pb-1 mr-4 text-lg" />
Set Total Max Connections
</p>
<p className="ml-lg">
You have set <b>Max Connections Per Instance</b> which is not
recommended for Hasura Cloud. Use <b>Total Max Connections</b>{' '}
instead.
</p>
</IndicatorCard>
)}
</>
);

View File

@ -9,7 +9,7 @@ export const MaxConnections: React.VFC<ConnectionSettingsFormProps> = ({
}) => (
<div className={styles.connection_settings_input_layout}>
<LabeledInput
label="Max Connections"
label="Max Connections Per Instance"
tooltipText="Maximum number of database connections per instance"
type="number"
className={`form-control ${styles.connnection_settings_form_input}`}

View File

@ -259,7 +259,7 @@ export type ConnectDBActions =
| { type: 'UPDATE_DB_PASSWORD'; data: string }
| { type: 'UPDATE_DB_DATABASE_NAME'; data: string }
| { type: 'UPDATE_MAX_CONNECTIONS'; data: string }
| { type: 'UPDATE_CUMULATIVE_MAX_CONNECTIONS'; data: string }
| { type: 'UPDATE_TOTAL_MAX_CONNECTIONS'; data: string }
| { type: 'UPDATE_RETRIES'; data: string }
| { type: 'UPDATE_IDLE_TIMEOUT'; data: string }
| { type: 'UPDATE_POOL_TIMEOUT'; data: string }
@ -389,11 +389,12 @@ export const connectDBReducer = (
max_connections: setNumberFromString(action.data),
},
};
case 'UPDATE_CUMULATIVE_MAX_CONNECTIONS':
case 'UPDATE_TOTAL_MAX_CONNECTIONS':
return produce(state, (draft: ConnectDBState) => {
draft.connectionSettings = state.connectionSettings ?? {};
draft.connectionSettings.cumulative_max_connections =
setNumberFromString(action.data);
draft.connectionSettings.total_max_connections = setNumberFromString(
action.data
);
});
case 'UPDATE_RETRIES':
return {
@ -670,9 +671,9 @@ export const makeReadReplicaConnectionObject = (
if (stateVal.connectionSettings?.max_connections) {
pool_settings.max_connections = stateVal.connectionSettings.max_connections;
}
if (stateVal.connectionSettings?.cumulative_max_connections) {
pool_settings.cumulative_max_connections =
stateVal.connectionSettings.cumulative_max_connections;
if (stateVal.connectionSettings?.total_max_connections) {
pool_settings.total_max_connections =
stateVal.connectionSettings.total_max_connections;
}
if (stateVal.connectionSettings?.idle_timeout) {
pool_settings.idle_timeout = stateVal.connectionSettings.idle_timeout;

View File

@ -1,3 +1,4 @@
/* eslint-disable no-underscore-dangle */
import React, { useState, useEffect } from 'react';
import Helmet from 'react-helmet';
import { connect, ConnectedProps } from 'react-redux';
@ -9,6 +10,7 @@ import {
useIsFeatureFlagEnabled,
} from '@/features/FeatureFlags';
import { nativeDrivers } from '@/features/DataSource';
import { isProConsole } from '@/utils/proConsole';
import styles from './styles.module.scss';
import { Dispatch, ReduxState } from '../../../../types';
import BreadCrumb from '../../../Common/Layout/BreadCrumb/BreadCrumb';
@ -61,7 +63,6 @@ const DatabaseListItem: React.FC<DatabaseListItemProps> = ({
const [removing, setRemoving] = useState(false);
const [showUrl, setShowUrl] = useState(false);
const [dbVersion, setDbVersion] = useState('');
const fetchDBVersion = () => {
const query = services[dataSource.driver].getDatabaseVersionSql ?? '';
@ -103,6 +104,7 @@ const DatabaseListItem: React.FC<DatabaseListItemProps> = ({
dataSource.name,
inconsistentObjects
);
return (
<tr data-test={dataSource.name}>
<td className="px-sm py-xs align-top w-0 whitespace-nowrap">
@ -128,29 +130,14 @@ const DatabaseListItem: React.FC<DatabaseListItemProps> = ({
>
Reload
</Button>
<Button
size="sm"
className="mr-xs"
onClick={() => {
onEdit(dataSource.name);
}}
>
Edit
</Button>
<Button
size="sm"
isLoading={removing}
loadingText="Removing..."
className="text-red-600"
onClick={() => {
setRemoving(true);
onRemove(dataSource.name, dataSource.driver, () =>
setRemoving(false)
);
}}
>
Remove
</Button>
{isProConsole(window.__env)
? !dataSource?.connection_pool_settings?.total_max_connections && (
<span className="bg-blue-100 font-bold rounded-lg pr-xs">
<FaExclamationTriangle className="mr-0.5 pb-1 pl-1.5 text-lg" />
Set Total Max Connections
</span>
)
: null}
</td>
<td className="px-sm py-xs max-w-xs align-top">
<CollapsibleToggle dataSource={dataSource} dbVersion={dbVersion} />
@ -180,7 +167,30 @@ const DatabaseListItem: React.FC<DatabaseListItemProps> = ({
onClick={() => setShowUrl(true)}
>
<FaEye aria-hidden="true" />
<div className="ml-xs">Show Connection String</div>
<div className="ml-xs mr-4">Show Connection String</div>
<Button
size="sm"
className="mr-xs"
onClick={() => {
onEdit(dataSource.name);
}}
>
Edit
</Button>
<Button
size="sm"
isLoading={removing}
loadingText="Removing..."
className="text-red-600"
onClick={() => {
setRemoving(true);
onRemove(dataSource.name, dataSource.driver, () =>
setRemoving(false)
);
}}
>
Remove
</Button>
</span>
)}
{showUrl && (

View File

@ -1069,7 +1069,7 @@ export interface SSLConfigOptions {
export interface ConnectionPoolSettings {
max_connections?: number;
cumulative_max_connections?: number;
total_max_connections?: number;
idle_timeout?: number;
retries?: number;
pool_timeout?: number;