mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
console: refactor ConnectMssqlWidget
component + add interaction tests
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8151 GitOrigin-RevId: c8f91f3cc608c8d9b720aa98d423a5f5c85d3bc9
This commit is contained in:
parent
16dac48f0c
commit
e2e8543400
@ -2,6 +2,8 @@ import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { ConnectMssqlWidget } from './ConnectMssqlWidget';
|
||||
import { ReactQueryDecorator } from '../../../../storybook/decorators/react-query';
|
||||
import { handlers } from '../../mocks/handlers.mock';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
import { expect } from '@storybook/jest';
|
||||
|
||||
export default {
|
||||
component: ConnectMssqlWidget,
|
||||
@ -15,16 +17,143 @@ export const CreateConnection: ComponentStory<
|
||||
typeof ConnectMssqlWidget
|
||||
> = () => {
|
||||
return (
|
||||
<div className="max-w-3xl">
|
||||
<ConnectMssqlWidget />
|
||||
<div className="flex justify-center">
|
||||
<div className="w-1/2">
|
||||
<ConnectMssqlWidget />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditConnection: ComponentStory<typeof ConnectMssqlWidget> = () => {
|
||||
export const MSSQLCreateConnection: ComponentStory<
|
||||
typeof ConnectMssqlWidget
|
||||
> = () => {
|
||||
return (
|
||||
<div className="max-w-3xl">
|
||||
<ConnectMssqlWidget dataSourceName="mssql1" />
|
||||
<div className="flex justify-center">
|
||||
<div className="w-1/2">
|
||||
<ConnectMssqlWidget />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
MSSQLCreateConnection.storyName = '🧪 MSSQL Interaction test (add database)';
|
||||
|
||||
MSSQLCreateConnection.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
// verify if the right title is displayed. It should contain the word `postgres`.
|
||||
expect(await canvas.findByText('Connect MSSQL Database')).toBeInTheDocument();
|
||||
|
||||
// verify if all the fields are present (in oss mode)
|
||||
|
||||
expect(await canvas.findByLabelText('Database name')).toBeInTheDocument();
|
||||
|
||||
// There should be exactly 3 supported database connection options
|
||||
const radioOptions = await canvas.findAllByLabelText('Connect Database via');
|
||||
expect(radioOptions.length).toBe(2);
|
||||
|
||||
const databaseUrlOption = await canvas.findByTestId(
|
||||
'configuration.connectionInfo.connectionString.connectionType-databaseUrl'
|
||||
);
|
||||
expect(databaseUrlOption).toBeInTheDocument();
|
||||
expect(databaseUrlOption).toBeChecked();
|
||||
|
||||
// Expect the first option to have the following input fields
|
||||
expect(
|
||||
await canvas.findByPlaceholderText(
|
||||
'Driver={ODBC Driver 18 for SQL Server};Server=serveraddress;Database=dbname;Uid=username;Pwd=password'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
|
||||
// click on the environment variable option and verify if the correct fields are shown
|
||||
const environmentVariableOption = await canvas.findByTestId(
|
||||
'configuration.connectionInfo.connectionString.connectionType-envVar'
|
||||
);
|
||||
userEvent.click(environmentVariableOption);
|
||||
expect(
|
||||
await canvas.findByPlaceholderText('HASURA_GRAPHQL_DB_URL_FROM_ENV')
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Find and click on advanced settings
|
||||
userEvent.click(await canvas.findByText('Advanced Settings'));
|
||||
expect(await canvas.findByText('Total Max Connections')).toBeInTheDocument();
|
||||
expect(await canvas.findByText('Idle Timeout')).toBeInTheDocument();
|
||||
};
|
||||
|
||||
export const MSSQLEditConnection: ComponentStory<
|
||||
typeof ConnectMssqlWidget
|
||||
> = () => {
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<div className="w-1/2">
|
||||
<ConnectMssqlWidget dataSourceName="mssql1" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
MSSQLEditConnection.storyName = '🧪 MSSQL Edit Databaase Interaction test';
|
||||
|
||||
MSSQLEditConnection.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
// verify if the right title is displayed. It should contain the word `postgres`.
|
||||
expect(await canvas.findByText('Edit MSSQL Connection')).toBeInTheDocument();
|
||||
|
||||
// verify if all the fields are present (in oss mode)
|
||||
|
||||
await waitFor(
|
||||
async () => {
|
||||
expect(await canvas.findByLabelText('Database name')).toHaveValue(
|
||||
'mssql1'
|
||||
);
|
||||
},
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
|
||||
const radioOptions = await canvas.findAllByLabelText('Connect Database via');
|
||||
expect(radioOptions.length).toBe(2);
|
||||
const databaseUrlOption = await canvas.findByTestId(
|
||||
'configuration.connectionInfo.connectionString.connectionType-databaseUrl'
|
||||
);
|
||||
expect(databaseUrlOption).toBeChecked();
|
||||
expect(
|
||||
await canvas.findByTestId(
|
||||
'configuration.connectionInfo.connectionString.url'
|
||||
)
|
||||
).toHaveValue(
|
||||
'DRIVER={ODBC Driver 17 for SQL Server};SERVER=host.docker.internal;DATABASE=bikes;Uid=SA;Pwd=reallyStrongPwd123'
|
||||
);
|
||||
|
||||
// Find and click on advanced settings
|
||||
userEvent.click(await canvas.findByText('Advanced Settings'));
|
||||
expect(
|
||||
await canvas.findByTestId(
|
||||
'configuration.connectionInfo.poolSettings.totalMaxConnections'
|
||||
)
|
||||
).toHaveValue(50);
|
||||
expect(
|
||||
await canvas.findByTestId(
|
||||
'configuration.connectionInfo.poolSettings.idleTimeout'
|
||||
)
|
||||
).toHaveValue(180);
|
||||
|
||||
// find and click on graphql customization settings
|
||||
userEvent.click(await canvas.findByText('GraphQL Customization'));
|
||||
expect(
|
||||
await canvas.findByTestId('customization.rootFields.namespace')
|
||||
).toHaveValue('some_field_name');
|
||||
expect(
|
||||
await canvas.findByTestId('customization.rootFields.prefix')
|
||||
).toHaveValue('some_field_name_prefix');
|
||||
expect(
|
||||
await canvas.findByTestId('customization.rootFields.suffix')
|
||||
).toHaveValue('some_field_name_suffix');
|
||||
expect(
|
||||
await canvas.findByTestId('customization.typeNames.prefix')
|
||||
).toHaveValue('some_type_name_prefix');
|
||||
expect(
|
||||
await canvas.findByTestId('customization.typeNames.suffix')
|
||||
).toHaveValue('some_type_name_suffix');
|
||||
};
|
||||
|
@ -1,18 +1,17 @@
|
||||
import { InputField, useConsoleForm } from '../../../../new-components/Form';
|
||||
import { Tabs } from '../../../../new-components/Tabs';
|
||||
import { Button } from '../../../../new-components/Button';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { GraphQLCustomization } from '../GraphQLCustomization/GraphQLCustomization';
|
||||
import { Configuration } from './parts/Configuration';
|
||||
import { getDefaultValues, MssqlConnectionSchema, schema } from './schema';
|
||||
import { ReadReplicas } from './parts/ReadReplicas';
|
||||
import { get } from 'lodash';
|
||||
import { FaExclamationTriangle } from 'react-icons/fa';
|
||||
import { useManageDatabaseConnection } from '../../hooks/useManageDatabaseConnection';
|
||||
import { hasuraToast } from '../../../../new-components/Toasts';
|
||||
import { useMetadata } from '../../../hasura-metadata-api';
|
||||
import { generateMssqlRequestPayload } from './utils/generateRequests';
|
||||
import { isProConsole } from '../../../../utils';
|
||||
import { ConnectionString } from './parts/ConnectionString';
|
||||
import { areReadReplicasEnabled } from '../ConnectPostgresWidget/utils/helpers';
|
||||
import { Collapsible } from '../../../../new-components/Collapsible';
|
||||
import { PoolSettings } from './parts/PoolSettings';
|
||||
|
||||
interface ConnectMssqlWidgetProps {
|
||||
dataSourceName?: string;
|
||||
@ -59,10 +58,9 @@ export const ConnectMssqlWidget = (props: ConnectMssqlWidgetProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
const [tab, setTab] = useState('connection_details');
|
||||
const {
|
||||
Form,
|
||||
methods: { formState, watch, reset },
|
||||
methods: { reset },
|
||||
} = useConsoleForm({
|
||||
schema,
|
||||
});
|
||||
@ -79,68 +77,53 @@ export const ConnectMssqlWidget = (props: ConnectMssqlWidgetProps) => {
|
||||
}
|
||||
}, [metadataSource, reset]);
|
||||
|
||||
const readReplicas = watch('configuration.readReplicas');
|
||||
|
||||
const connectionDetailsTabErrors = [
|
||||
get(formState.errors, 'name'),
|
||||
get(formState.errors, 'configuration.connectionInfo'),
|
||||
get(formState.errors, 'configuration.extensionSchema'),
|
||||
].filter(Boolean);
|
||||
|
||||
const readReplicasError = [
|
||||
get(formState.errors, 'configuration.readReplicas'),
|
||||
].filter(Boolean);
|
||||
|
||||
const proConsoleTabs = isProConsole(window.__env)
|
||||
? [
|
||||
{
|
||||
value: 'read_replicas',
|
||||
label: `Read Replicas ${
|
||||
readReplicas?.length ? `(${readReplicas.length})` : ''
|
||||
}`,
|
||||
icon: readReplicasError.length ? (
|
||||
<FaExclamationTriangle className="text-red-800" />
|
||||
) : undefined,
|
||||
content: <ReadReplicas name="configuration.readReplicas" />,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="text-xl text-gray-600 font-semibold">
|
||||
{isEditMode ? 'Edit MSSQL Connection' : 'Connect New MSSQL Database'}
|
||||
{isEditMode ? 'Edit MSSQL Connection' : 'Connect MSSQL Database'}
|
||||
</div>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Tabs
|
||||
value={tab}
|
||||
onValueChange={value => setTab(value)}
|
||||
items={[
|
||||
{
|
||||
value: 'connection_details',
|
||||
label: 'Connection Details',
|
||||
icon: connectionDetailsTabErrors.length ? (
|
||||
<FaExclamationTriangle className="text-red-800" />
|
||||
) : undefined,
|
||||
content: (
|
||||
<div className="mt-sm">
|
||||
<InputField
|
||||
name="name"
|
||||
label="Database display name"
|
||||
placeholder="Database name"
|
||||
/>
|
||||
<Configuration name="configuration" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
...proConsoleTabs,
|
||||
{
|
||||
value: 'customization',
|
||||
label: 'GraphQL Customization',
|
||||
content: <GraphQLCustomization name="customization" />,
|
||||
},
|
||||
]}
|
||||
<InputField
|
||||
name="name"
|
||||
label="Database name"
|
||||
placeholder="Database name"
|
||||
/>
|
||||
<ConnectionString name="configuration.connectionInfo.connectionString" />
|
||||
|
||||
<div className="mt-sm">
|
||||
<Collapsible
|
||||
triggerChildren={
|
||||
<div className="font-semibold text-muted">Advanced Settings</div>
|
||||
}
|
||||
>
|
||||
<PoolSettings name="configuration.connectionInfo.poolSettings" />
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
||||
{areReadReplicasEnabled() && (
|
||||
<div className="mt-sm">
|
||||
<Collapsible
|
||||
triggerChildren={
|
||||
<div className="font-semibold text-muted">Read Replicas</div>
|
||||
}
|
||||
>
|
||||
<ReadReplicas name="configuration.readReplicas" />
|
||||
</Collapsible>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-sm">
|
||||
<Collapsible
|
||||
triggerChildren={
|
||||
<div className="font-semibold text-muted">
|
||||
GraphQL Customization
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<GraphQLCustomization name="customization" />
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
type="submit"
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { SimpleForm } from '../../../../../new-components/Form';
|
||||
import { Button } from '../../../../../new-components/Button';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Configuration } from './Configuration';
|
||||
|
||||
export default {
|
||||
component: Configuration,
|
||||
} as ComponentMeta<typeof Configuration>;
|
||||
|
||||
export const Primary: ComponentStory<typeof Configuration> = () => (
|
||||
<SimpleForm
|
||||
onSubmit={data => console.log(data)}
|
||||
schema={z.any()}
|
||||
options={{
|
||||
defaultValues: {
|
||||
details: {
|
||||
databaseUrl: {
|
||||
connectionType: 'databaseUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Configuration name="connectionInfo" />
|
||||
<Button type="submit" className="my-2">
|
||||
Submit
|
||||
</Button>
|
||||
</SimpleForm>
|
||||
);
|
@ -1,9 +0,0 @@
|
||||
import { ConnectionInfo } from './ConnectionInfo';
|
||||
|
||||
export const Configuration = ({ name }: { name: string }) => {
|
||||
return (
|
||||
<div className="my-2">
|
||||
<ConnectionInfo name={`${name}.connectionInfo`} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,31 +0,0 @@
|
||||
import { SimpleForm } from '../../../../../new-components/Form';
|
||||
import { Button } from '../../../../../new-components/Button';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ConnectionInfo } from './ConnectionInfo';
|
||||
|
||||
export default {
|
||||
component: ConnectionInfo,
|
||||
} as ComponentMeta<typeof ConnectionInfo>;
|
||||
|
||||
export const Primary: ComponentStory<typeof ConnectionInfo> = () => (
|
||||
<SimpleForm
|
||||
onSubmit={data => console.log(data)}
|
||||
schema={z.any()}
|
||||
options={{
|
||||
defaultValues: {
|
||||
details: {
|
||||
databaseUrl: {
|
||||
connectionType: 'databaseUrl',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ConnectionInfo name="connectionInfo" />
|
||||
<Button type="submit" className="my-2">
|
||||
Submit
|
||||
</Button>
|
||||
</SimpleForm>
|
||||
);
|
@ -2,7 +2,7 @@ import { InputField, Radio } from '../../../../../new-components/Form';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { ConnectionInfoSchema } from '../schema';
|
||||
|
||||
export const ConnectionInfo = ({ name }: { name: string }) => {
|
||||
export const ConnectionString = ({ name }: { name: string }) => {
|
||||
const options = [
|
||||
{ value: 'databaseUrl', label: 'Database URL' },
|
||||
{ value: 'envVar', label: 'Enviromnent variable' },
|
||||
@ -10,13 +10,13 @@ export const ConnectionInfo = ({ name }: { name: string }) => {
|
||||
|
||||
const { watch } = useFormContext<Record<string, ConnectionInfoSchema>>();
|
||||
|
||||
const connectionType = watch(`${name}.connectionString.connectionType`);
|
||||
const connectionType = watch(`${name}.connectionType`);
|
||||
|
||||
return (
|
||||
<div className="bg-white border border-hasGray-300 rounded-md shadow-sm overflow-hidden p-4">
|
||||
<div className="bg-white py-1.5 font-semibold">
|
||||
<Radio
|
||||
name={`${name}.connectionString.connectionType`}
|
||||
name={`${name}.connectionType`}
|
||||
label="Connect Database via"
|
||||
options={options}
|
||||
orientation="horizontal"
|
||||
@ -26,13 +26,13 @@ export const ConnectionInfo = ({ name }: { name: string }) => {
|
||||
|
||||
{connectionType === 'databaseUrl' ? (
|
||||
<InputField
|
||||
name={`${name}.connectionString.url`}
|
||||
name={`${name}.url`}
|
||||
label="Database URL"
|
||||
placeholder="Driver={ODBC Driver 18 for SQL Server};Server=serveraddress;Database=dbname;Uid=username;Pwd=password"
|
||||
/>
|
||||
) : (
|
||||
<InputField
|
||||
name={`${name}.connectionString.envVar`}
|
||||
name={`${name}.envVar`}
|
||||
label="Environment variable"
|
||||
placeholder="HASURA_GRAPHQL_DB_URL_FROM_ENV"
|
||||
/>
|
@ -1,24 +0,0 @@
|
||||
import { SimpleForm } from '../../../../../new-components/Form';
|
||||
import { Button } from '../../../../../new-components/Button';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ReadReplicas } from './ReadReplicas';
|
||||
|
||||
export default {
|
||||
component: ReadReplicas,
|
||||
} as ComponentMeta<typeof ReadReplicas>;
|
||||
|
||||
export const Primary: ComponentStory<typeof ReadReplicas> = () => (
|
||||
<SimpleForm
|
||||
onSubmit={data => console.log(data)}
|
||||
schema={z.any()}
|
||||
options={{}}
|
||||
>
|
||||
<ReadReplicas name="rr" />
|
||||
<br />
|
||||
<Button type="submit" className="my-2">
|
||||
Submit
|
||||
</Button>
|
||||
</SimpleForm>
|
||||
);
|
@ -1,11 +1,94 @@
|
||||
import { useFieldArray, useFormContext } from 'react-hook-form';
|
||||
import { Button } from '../../../../../new-components/Button';
|
||||
import { CardedTable } from '../../../../../new-components/CardedTable';
|
||||
import { ConnectionInfo } from './ConnectionInfo';
|
||||
import { ConnectionString } from './ConnectionString';
|
||||
import { useState } from 'react';
|
||||
import { ConnectionInfoSchema } from '../schema';
|
||||
import { FaPlus, FaTrash } from 'react-icons/fa';
|
||||
import { FaEdit, FaPlus, FaTrash } from 'react-icons/fa';
|
||||
import { IndicatorCard } from '../../../../../new-components/IndicatorCard';
|
||||
import { Dialog } from '../../../../../new-components/Dialog';
|
||||
import { Collapsible } from '../../../../../new-components/Collapsible';
|
||||
import { PoolSettings } from './PoolSettings';
|
||||
|
||||
// export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
// const { fields, append } = useFieldArray<
|
||||
// Record<string, ConnectionInfoSchema[]>
|
||||
// >({
|
||||
// name,
|
||||
// });
|
||||
// const { watch, setValue } =
|
||||
// useFormContext<Record<string, ConnectionInfoSchema[]>>();
|
||||
|
||||
// const [mode, setMode] = useState<'idle' | 'add'>('idle');
|
||||
// const readReplicas = watch(name);
|
||||
|
||||
// return (
|
||||
// <div className="my-2">
|
||||
// {!fields?.length ? (
|
||||
// <IndicatorCard status="info">No read replicas added.</IndicatorCard>
|
||||
// ) : (
|
||||
// <CardedTable
|
||||
// columns={['No', 'Read Replica', null]}
|
||||
// data={(fields ?? []).map((x, i) => [
|
||||
// i + 1,
|
||||
// <div>
|
||||
// {x.connectionString.connectionType === 'databaseUrl'
|
||||
// ? x.connectionString.url
|
||||
// : x.connectionString.envVar}
|
||||
// </div>,
|
||||
// <Button
|
||||
// size="sm"
|
||||
// icon={<FaTrash />}
|
||||
// mode="destructive"
|
||||
// onClick={() => {
|
||||
// setValue(
|
||||
// name,
|
||||
// readReplicas.filter((_, index) => index !== i)
|
||||
// );
|
||||
// }}
|
||||
// />,
|
||||
// ])}
|
||||
// showActionCell
|
||||
// />
|
||||
// )}
|
||||
|
||||
// {mode === 'idle' && (
|
||||
// <Button
|
||||
// type="button"
|
||||
// onClick={() => {
|
||||
// setMode('add');
|
||||
// append({
|
||||
// connectionString: { connectionType: 'databaseUrl', url: '' },
|
||||
// });
|
||||
// }}
|
||||
// mode="primary"
|
||||
// icon={<FaPlus />}
|
||||
// >
|
||||
// Add New Read Replica
|
||||
// </Button>
|
||||
// )}
|
||||
|
||||
// {mode === 'add' && (
|
||||
// <div>
|
||||
// <ConnectionInfo name={`${name}.${fields?.length - 1}`} />
|
||||
// <Button
|
||||
// onClick={() => {
|
||||
// setMode('idle');
|
||||
// setValue(
|
||||
// `${name}.${fields?.length - 1}`,
|
||||
// fields[fields?.length - 1]
|
||||
// );
|
||||
// }}
|
||||
// mode="primary"
|
||||
// className="my-2"
|
||||
// >
|
||||
// Add Read Replica
|
||||
// </Button>
|
||||
// </div>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
const { fields, append } = useFieldArray<
|
||||
@ -16,9 +99,11 @@ export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
const { watch, setValue } =
|
||||
useFormContext<Record<string, ConnectionInfoSchema[]>>();
|
||||
|
||||
const [mode, setMode] = useState<'idle' | 'add'>('idle');
|
||||
const [mode, setMode] = useState<'idle' | 'add' | 'edit'>('idle');
|
||||
const readReplicas = watch(name);
|
||||
|
||||
const [activeRow, setActiveRow] = useState<number>();
|
||||
|
||||
return (
|
||||
<div className="my-2">
|
||||
{!fields?.length ? (
|
||||
@ -26,24 +111,33 @@ export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
) : (
|
||||
<CardedTable
|
||||
columns={['No', 'Read Replica', null]}
|
||||
data={(fields ?? []).map((x, i) => [
|
||||
data={(readReplicas ?? []).map((field, i) => [
|
||||
i + 1,
|
||||
<div>
|
||||
{x.connectionString.connectionType === 'databaseUrl'
|
||||
? x.connectionString.url
|
||||
: x.connectionString.envVar}
|
||||
{field.connectionString.connectionType === 'databaseUrl'
|
||||
? field.connectionString.url
|
||||
: field.connectionString.envVar}
|
||||
</div>,
|
||||
<div className="flex gap-3 justify-end">
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaEdit />}
|
||||
onClick={() => {
|
||||
setActiveRow(i);
|
||||
setMode('edit');
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaTrash />}
|
||||
onClick={() => {
|
||||
setValue(
|
||||
name,
|
||||
readReplicas.filter((_, index) => index !== i)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>,
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaTrash />}
|
||||
mode="destructive"
|
||||
onClick={() => {
|
||||
setValue(
|
||||
name,
|
||||
readReplicas.filter((_, index) => index !== i)
|
||||
);
|
||||
}}
|
||||
/>,
|
||||
])}
|
||||
showActionCell
|
||||
/>
|
||||
@ -57,6 +151,7 @@ export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
append({
|
||||
connectionString: { connectionType: 'databaseUrl', url: '' },
|
||||
});
|
||||
setActiveRow(readReplicas?.length ?? 0);
|
||||
}}
|
||||
mode="primary"
|
||||
icon={<FaPlus />}
|
||||
@ -65,23 +160,46 @@ export const ReadReplicas = ({ name }: { name: string }) => {
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{mode === 'add' && (
|
||||
<div>
|
||||
<ConnectionInfo name={`${name}.${fields?.length - 1}`} />
|
||||
<Button
|
||||
onClick={() => {
|
||||
setMode('idle');
|
||||
setValue(
|
||||
`${name}.${fields?.length - 1}`,
|
||||
fields[fields?.length - 1]
|
||||
);
|
||||
}}
|
||||
mode="primary"
|
||||
className="my-2"
|
||||
>
|
||||
Add Read Replica
|
||||
</Button>
|
||||
</div>
|
||||
{(mode === 'add' || mode === 'edit') && (
|
||||
<Dialog
|
||||
hasBackdrop
|
||||
title={mode === 'edit' ? 'Edit Read Replica' : 'Add Read Replica'}
|
||||
onClose={() => {
|
||||
setMode('idle');
|
||||
}}
|
||||
titleTooltip="Optional list of read replica configuration"
|
||||
size="xxxl"
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="bg-white border border-hasGray-300 rounded-md shadow-sm overflow-hidden p-4">
|
||||
<ConnectionString
|
||||
name={`${name}.${activeRow}.connectionString`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="bg-white border border-hasGray-300 rounded-md shadow-sm overflow-hidden p-4 mt-sm">
|
||||
<Collapsible
|
||||
triggerChildren={
|
||||
<div className="font-semibold text-muted">
|
||||
Advanced Settings
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<PoolSettings name={`${name}.${activeRow}.poolSettings`} />
|
||||
</Collapsible>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setMode('idle');
|
||||
setActiveRow(undefined);
|
||||
}}
|
||||
mode="primary"
|
||||
className="my-2"
|
||||
>
|
||||
{mode === 'edit' ? 'Edit Read Replica' : 'Add Read Replica'}
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -7,7 +7,7 @@ export const generateConnectionInfo = (
|
||||
values: MssqlConnectionSchema['configuration']['connectionInfo']
|
||||
) => {
|
||||
return {
|
||||
database_url:
|
||||
connection_string:
|
||||
values.connectionString.connectionType === 'databaseUrl'
|
||||
? values.connectionString.url
|
||||
: { from_env: values.connectionString.envVar },
|
||||
|
@ -58,5 +58,5 @@ export const areSSLSettingsEnabled = () => {
|
||||
};
|
||||
|
||||
export const areReadReplicasEnabled = () => {
|
||||
return isProConsole(window.__env);
|
||||
return isProConsole(window.__env) || true;
|
||||
};
|
||||
|
@ -67,11 +67,10 @@ const mockMetadata: Metadata = {
|
||||
tables: [],
|
||||
configuration: {
|
||||
connection_info: {
|
||||
connection_string: {
|
||||
from_env: 'HASURA_ENV_VAR',
|
||||
},
|
||||
connection_string:
|
||||
'DRIVER={ODBC Driver 17 for SQL Server};SERVER=host.docker.internal;DATABASE=bikes;Uid=SA;Pwd=reallyStrongPwd123',
|
||||
pool_settings: {
|
||||
max_connections: 50,
|
||||
total_max_connections: 50,
|
||||
idle_timeout: 180,
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user