mirror of
https://github.com/grafana/grafana.git
synced 2025-01-02 04:07:15 -06:00
MSSQL: ConfigEditor
updates (#75275)
* Add secure json data type * Update Azure credentials form with Field components - Update labels - Update widths - Remove excess code * Update config editor * Fix lint
This commit is contained in:
parent
6811b0ae63
commit
61e3f3a059
@ -1,9 +1,7 @@
|
||||
import React, { ChangeEvent } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { InlineFormLabel, Button } from '@grafana/ui/src/components';
|
||||
import { Input } from '@grafana/ui/src/components/Forms/Legacy/Input/Input';
|
||||
import { Select } from '@grafana/ui/src/components/Forms/Legacy/Select/Select';
|
||||
import { Button, Field, Select, Input } from '@grafana/ui/src/components';
|
||||
|
||||
import { AzureCredentialsType, AzureAuthType } from '../types';
|
||||
|
||||
@ -52,117 +50,121 @@ export const AzureCredentialsForm = (props: Props) => {
|
||||
return (
|
||||
<div>
|
||||
{managedIdentityEnabled && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel tooltip="Choose the type of authentication to Azure services">
|
||||
Authentication
|
||||
</InlineFormLabel>
|
||||
<Select
|
||||
value={authTypeOptions.find((opt) => opt.value === credentials.authType)}
|
||||
options={authTypeOptions}
|
||||
onChange={onAuthTypeChange}
|
||||
isDisabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Field
|
||||
label="Authentication"
|
||||
description="Choose the type of authentication to Azure services"
|
||||
htmlFor="authentication-type"
|
||||
>
|
||||
<Select
|
||||
width={20}
|
||||
value={authTypeOptions.find((opt) => opt.value === credentials.authType)}
|
||||
options={authTypeOptions}
|
||||
onChange={onAuthTypeChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
{credentials.authType === 'clientsecret' && (
|
||||
<>
|
||||
{azureCloudOptions && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12" tooltip="Choose an Azure Cloud">
|
||||
Azure Cloud
|
||||
</InlineFormLabel>
|
||||
<Select
|
||||
value={azureCloudOptions.find((opt) => opt.value === credentials.azureCloud)}
|
||||
options={azureCloudOptions}
|
||||
onChange={(selected: SelectableValue<AzureAuthType>) => {
|
||||
const value = selected.value || '';
|
||||
onInputChange({ property: 'azureCloud', value });
|
||||
}}
|
||||
isDisabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Field label="Azure Cloud" htmlFor="azure-cloud-type" disabled={disabled}>
|
||||
<Select
|
||||
value={azureCloudOptions.find((opt) => opt.value === credentials.azureCloud)}
|
||||
options={azureCloudOptions}
|
||||
onChange={(selected: SelectableValue<AzureAuthType>) => {
|
||||
const value = selected.value || '';
|
||||
onInputChange({ property: 'azureCloud', value });
|
||||
}}
|
||||
isDisabled={disabled}
|
||||
inputId="azure-cloud-type"
|
||||
aria-label="Azure Cloud"
|
||||
width={20}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Directory (tenant) ID</InlineFormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.tenantId || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'tenantId', value });
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Application (client) ID</InlineFormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientId || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'clientId', value });
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{typeof credentials.clientSecret === 'symbol' ? (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel htmlFor="azure-client-secret" className="width-12">
|
||||
Client Secret
|
||||
</InlineFormLabel>
|
||||
<Input id="azure-client-secret" className="width-25" placeholder="configured" disabled />
|
||||
</div>
|
||||
{!disabled && (
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onInputChange({ property: 'clientSecret', value: '' });
|
||||
}}
|
||||
>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
|
||||
<div className="width-15">
|
||||
<Field
|
||||
label="Directory (tenant) ID"
|
||||
required
|
||||
htmlFor="tenant-id"
|
||||
invalid={!credentials.tenantId}
|
||||
error={'Tenant ID is required'}
|
||||
>
|
||||
<Input
|
||||
width={45}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.tenantId || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'tenantId', value });
|
||||
}}
|
||||
disabled={disabled}
|
||||
aria-label="Tenant ID"
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Application (client) ID"
|
||||
required
|
||||
htmlFor="client-id"
|
||||
invalid={!credentials.clientId}
|
||||
error={'Client ID is required'}
|
||||
>
|
||||
<Input
|
||||
width={45}
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientId || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'clientId', value });
|
||||
}}
|
||||
disabled={disabled}
|
||||
aria-label="Client ID"
|
||||
/>
|
||||
</Field>
|
||||
{!disabled &&
|
||||
(typeof credentials.clientSecret === 'symbol' ? (
|
||||
<Field label="Client Secret" htmlFor="client-secret" required>
|
||||
<div className="width-30" style={{ display: 'flex', gap: '4px' }}>
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientSecret || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'clientSecret', value });
|
||||
aria-label="Client Secret"
|
||||
placeholder="configured"
|
||||
disabled={true}
|
||||
data-testid={'client-secret'}
|
||||
width={45}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onInputChange({ property: 'clientSecret', value: '' });
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
) : (
|
||||
<Field
|
||||
label="Client Secret"
|
||||
required
|
||||
htmlFor="client-secret"
|
||||
invalid={!credentials.clientSecret}
|
||||
error={'Client secret is required'}
|
||||
>
|
||||
<Input
|
||||
width={45}
|
||||
aria-label="Client Secret"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientSecret || ''}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
onInputChange({ property: 'clientSecret', value });
|
||||
}}
|
||||
id="client-secret"
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Field>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -10,18 +10,19 @@ import {
|
||||
updateDatasourcePluginJsonDataOption,
|
||||
updateDatasourcePluginResetOption,
|
||||
} from '@grafana/data';
|
||||
import { ConfigSection, ConfigSubSection, DataSourceDescription } from '@grafana/experimental';
|
||||
import {
|
||||
Alert,
|
||||
FieldSet,
|
||||
InlineField,
|
||||
InlineFieldRow,
|
||||
InlineSwitch,
|
||||
Input,
|
||||
Link,
|
||||
SecretInput,
|
||||
Select,
|
||||
useStyles2,
|
||||
SecureSocksProxySettings,
|
||||
Divider,
|
||||
Field,
|
||||
Switch,
|
||||
} from '@grafana/ui';
|
||||
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
||||
import { config } from 'app/core/config';
|
||||
@ -29,14 +30,18 @@ import { ConnectionLimits } from 'app/features/plugins/sql/components/configurat
|
||||
import { useMigrateDatabaseFields } from 'app/features/plugins/sql/components/configuration/useMigrateDatabaseFields';
|
||||
|
||||
import { AzureAuthSettings } from '../azureauth/AzureAuthSettings';
|
||||
import { MSSQLAuthenticationType, MSSQLEncryptOptions, MssqlOptions, AzureAuthConfigType } from '../types';
|
||||
import {
|
||||
MSSQLAuthenticationType,
|
||||
MSSQLEncryptOptions,
|
||||
MssqlOptions,
|
||||
AzureAuthConfigType,
|
||||
MssqlSecureOptions,
|
||||
} from '../types';
|
||||
|
||||
const SHORT_WIDTH = 15;
|
||||
const LONG_WIDTH = 46;
|
||||
const LABEL_WIDTH_SSL = 25;
|
||||
const LABEL_WIDTH_DETAILS = 20;
|
||||
const LONG_WIDTH = 40;
|
||||
|
||||
export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<MssqlOptions>) => {
|
||||
export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<MssqlOptions, MssqlSecureOptions>) => {
|
||||
useMigrateDatabaseFields(props);
|
||||
|
||||
const { options: dsSettings, onOptionsChange } = props;
|
||||
@ -107,8 +112,25 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
||||
|
||||
return (
|
||||
<>
|
||||
<FieldSet label="MS SQL Connection" width={400}>
|
||||
<InlineField labelWidth={SHORT_WIDTH} label="Host">
|
||||
<DataSourceDescription
|
||||
dataSourceName="Microsoft SQL Server"
|
||||
docsLink="https://grafana.com/docs/grafana/latest/datasources/mssql/"
|
||||
hasRequiredFields
|
||||
/>
|
||||
<Alert title="User Permission" severity="info">
|
||||
The database user should only be granted SELECT permissions on the specified database and tables you want to
|
||||
query. Grafana does not validate that queries are safe so queries can contain any SQL statement. For example,
|
||||
statements like <code>USE otherdb;</code> and <code>DROP TABLE user;</code> would be executed. To protect
|
||||
against this we <em>highly</em> recommend you create a specific MS SQL user with restricted permissions. Check
|
||||
out the{' '}
|
||||
<Link rel="noreferrer" target="_blank" href="http://docs.grafana.org/features/datasources/mssql/">
|
||||
Microsoft SQL Server Data Source Docs
|
||||
</Link>{' '}
|
||||
for more information.
|
||||
</Alert>
|
||||
<Divider />
|
||||
<ConfigSection title="Connection">
|
||||
<Field label="Host" required invalid={!dsSettings.url} error={'Host is required'}>
|
||||
<Input
|
||||
width={LONG_WIDTH}
|
||||
name="host"
|
||||
@ -116,82 +138,23 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
||||
value={dsSettings.url || ''}
|
||||
placeholder="localhost:1433"
|
||||
onChange={onDSOptionChanged('url')}
|
||||
></Input>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={SHORT_WIDTH} label="Database">
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Database" required invalid={!jsonData.database} error={'Database is required'}>
|
||||
<Input
|
||||
width={LONG_WIDTH}
|
||||
name="database"
|
||||
value={jsonData.database || ''}
|
||||
placeholder="database name"
|
||||
onChange={onUpdateDatasourceJsonDataOption(props, 'database')}
|
||||
></Input>
|
||||
</InlineField>
|
||||
<InlineField
|
||||
label="Authentication"
|
||||
labelWidth={SHORT_WIDTH}
|
||||
htmlFor="authenticationType"
|
||||
tooltip={
|
||||
<ul className={styles.ulPadding}>
|
||||
<li>
|
||||
<i>SQL Server Authentication</i> This is the default mechanism to connect to MS SQL Server. Enter the
|
||||
SQL Server Authentication login or the Windows Authentication login in the DOMAIN\User format.
|
||||
</li>
|
||||
<li>
|
||||
<i>Windows Authentication</i> Windows Integrated Security - single sign on for users who are already
|
||||
logged onto Windows and have enabled this option for MS SQL Server.
|
||||
</li>
|
||||
{azureAuthIsSupported && (
|
||||
<li>
|
||||
<i>Azure Authentication</i> Securely authenticate and access Azure resources and applications using
|
||||
Azure AD credentials - Managed Service Identity and Client Secret Credentials are supported.
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
}
|
||||
>
|
||||
<Select
|
||||
// Default to basic authentication of none is set
|
||||
value={jsonData.authenticationType || MSSQLAuthenticationType.sqlAuth}
|
||||
inputId="authenticationType"
|
||||
options={buildAuthenticationOptions()}
|
||||
onChange={onAuthenticationMethodChanged}
|
||||
></Select>
|
||||
</InlineField>
|
||||
{/* Basic SQL auth. Render if authType === MSSQLAuthenticationType.sqlAuth OR
|
||||
if no authType exists, which will be the case when creating a new data source */}
|
||||
{(jsonData.authenticationType === MSSQLAuthenticationType.sqlAuth || !jsonData.authenticationType) && (
|
||||
<InlineFieldRow>
|
||||
<InlineField labelWidth={SHORT_WIDTH} label="User">
|
||||
<Input
|
||||
width={SHORT_WIDTH}
|
||||
value={dsSettings.user || ''}
|
||||
placeholder="user"
|
||||
onChange={onDSOptionChanged('user')}
|
||||
></Input>
|
||||
</InlineField>
|
||||
<InlineField label="Password" labelWidth={SHORT_WIDTH}>
|
||||
<SecretInput
|
||||
width={SHORT_WIDTH}
|
||||
placeholder="Password"
|
||||
isConfigured={dsSettings.secureJsonFields && dsSettings.secureJsonFields.password}
|
||||
onReset={onResetPassword}
|
||||
onBlur={onUpdateDatasourceSecureJsonDataOption(props, 'password')}
|
||||
></SecretInput>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
</FieldSet>
|
||||
/>
|
||||
</Field>
|
||||
</ConfigSection>
|
||||
|
||||
{config.secureSocksDSProxyEnabled && (
|
||||
<SecureSocksProxySettings options={dsSettings} onOptionsChange={onOptionsChange} />
|
||||
)}
|
||||
|
||||
<FieldSet label="TLS/SSL Auth">
|
||||
<InlineField
|
||||
labelWidth={LABEL_WIDTH_SSL}
|
||||
<ConfigSection title="TLS/SSL Auth">
|
||||
<Field
|
||||
htmlFor="encrypt"
|
||||
tooltip={
|
||||
description={
|
||||
<>
|
||||
Determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server.
|
||||
<ul className={styles.ulPadding}>
|
||||
@ -216,23 +179,19 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
||||
value={jsonData.encrypt || MSSQLEncryptOptions.false}
|
||||
inputId="encrypt"
|
||||
onChange={onEncryptChanged}
|
||||
></Select>
|
||||
</InlineField>
|
||||
width={LONG_WIDTH}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
{jsonData.encrypt === MSSQLEncryptOptions.true ? (
|
||||
<>
|
||||
<InlineField labelWidth={LABEL_WIDTH_SSL} htmlFor="skipTlsVerify" label="Skip TLS Verify">
|
||||
<InlineSwitch
|
||||
id="skipTlsVerify"
|
||||
onChange={onSkipTLSVerifyChanged}
|
||||
value={jsonData.tlsSkipVerify || false}
|
||||
></InlineSwitch>
|
||||
</InlineField>
|
||||
<Field htmlFor="skipTlsVerify" label="Skip TLS Verify">
|
||||
<Switch id="skipTlsVerify" onChange={onSkipTLSVerifyChanged} value={jsonData.tlsSkipVerify || false} />
|
||||
</Field>
|
||||
{jsonData.tlsSkipVerify ? null : (
|
||||
<>
|
||||
<InlineField
|
||||
labelWidth={LABEL_WIDTH_SSL}
|
||||
tooltip={
|
||||
<Field
|
||||
description={
|
||||
<span>
|
||||
Path to file containing the public key certificate of the CA that signed the SQL Server
|
||||
certificate. Needed when the server certificate is self signed.
|
||||
@ -244,76 +203,141 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps<Ms
|
||||
value={jsonData.sslRootCertFile || ''}
|
||||
onChange={onUpdateDatasourceJsonDataOption(props, 'sslRootCertFile')}
|
||||
placeholder="TLS/SSL root certificate file path"
|
||||
></Input>
|
||||
</InlineField>
|
||||
<InlineField labelWidth={LABEL_WIDTH_SSL} label="Hostname in server certificate">
|
||||
width={LONG_WIDTH}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Hostname in server certificate">
|
||||
<Input
|
||||
placeholder="Common Name (CN) in server certificate"
|
||||
value={jsonData.serverName || ''}
|
||||
onChange={onUpdateDatasourceJsonDataOption(props, 'serverName')}
|
||||
></Input>
|
||||
</InlineField>
|
||||
width={LONG_WIDTH}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</FieldSet>
|
||||
</ConfigSection>
|
||||
|
||||
{azureAuthIsSupported && jsonData.authenticationType === MSSQLAuthenticationType.azureAuth && (
|
||||
<FieldSet label="Azure Authentication Settings">
|
||||
<azureAuthSettings.azureAuthSettingsUI dataSourceConfig={dsSettings} onChange={onOptionsChange} />
|
||||
</FieldSet>
|
||||
)}
|
||||
|
||||
<ConnectionLimits labelWidth={SHORT_WIDTH} options={dsSettings} onOptionsChange={onOptionsChange} />
|
||||
|
||||
<FieldSet label="MS SQL details">
|
||||
<InlineField
|
||||
tooltip={
|
||||
<span>
|
||||
A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example
|
||||
<code>1m</code> if your data is written every minute.
|
||||
</span>
|
||||
<ConfigSection title="Authentication">
|
||||
<Field
|
||||
label="Authentication Type"
|
||||
htmlFor="authenticationType"
|
||||
description={
|
||||
<ul className={styles.ulPadding}>
|
||||
<li>
|
||||
<i>SQL Server Authentication</i> This is the default mechanism to connect to MS SQL Server. Enter the
|
||||
SQL Server Authentication login or the Windows Authentication login in the DOMAIN\User format.
|
||||
</li>
|
||||
<li>
|
||||
<i>Windows Authentication</i> Windows Integrated Security - single sign on for users who are already
|
||||
logged onto Windows and have enabled this option for MS SQL Server.
|
||||
</li>
|
||||
{azureAuthIsSupported && (
|
||||
<li>
|
||||
<i>Azure Authentication</i> Securely authenticate and access Azure resources and applications using
|
||||
Azure AD credentials - Managed Service Identity and Client Secret Credentials are supported.
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
}
|
||||
label="Min time interval"
|
||||
labelWidth={LABEL_WIDTH_DETAILS}
|
||||
>
|
||||
<Input
|
||||
placeholder="1m"
|
||||
value={jsonData.timeInterval || ''}
|
||||
onChange={onUpdateDatasourceJsonDataOption(props, 'timeInterval')}
|
||||
></Input>
|
||||
</InlineField>
|
||||
<InlineField
|
||||
tooltip={
|
||||
<span>
|
||||
The number of seconds to wait before canceling the request when connecting to the database. The default is{' '}
|
||||
<code>0</code>, meaning no timeout.
|
||||
</span>
|
||||
}
|
||||
label="Connection timeout"
|
||||
labelWidth={LABEL_WIDTH_DETAILS}
|
||||
>
|
||||
<NumberInput
|
||||
placeholder="60"
|
||||
min={0}
|
||||
value={jsonData.connectionTimeout}
|
||||
onChange={onConnectionTimeoutChanged}
|
||||
></NumberInput>
|
||||
</InlineField>
|
||||
</FieldSet>
|
||||
<Select
|
||||
// Default to basic authentication of none is set
|
||||
value={jsonData.authenticationType || MSSQLAuthenticationType.sqlAuth}
|
||||
inputId="authenticationType"
|
||||
options={buildAuthenticationOptions()}
|
||||
onChange={onAuthenticationMethodChanged}
|
||||
width={LONG_WIDTH}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Alert title="User Permission" severity="info">
|
||||
The database user should only be granted SELECT permissions on the specified database and tables you want to
|
||||
query. Grafana does not validate that queries are safe so queries can contain any SQL statement. For example,
|
||||
statements like <code>USE otherdb;</code> and <code>DROP TABLE user;</code> would be executed. To protect
|
||||
against this we <em>highly</em> recommend you create a specific MS SQL user with restricted permissions. Check
|
||||
out the{' '}
|
||||
<Link rel="noreferrer" target="_blank" href="http://docs.grafana.org/features/datasources/mssql/">
|
||||
Microsoft SQL Server Data Source Docs
|
||||
</Link>{' '}
|
||||
for more information.
|
||||
</Alert>
|
||||
{/* Basic SQL auth. Render if authType === MSSQLAuthenticationType.sqlAuth OR
|
||||
if no authType exists, which will be the case when creating a new data source */}
|
||||
{(jsonData.authenticationType === MSSQLAuthenticationType.sqlAuth || !jsonData.authenticationType) && (
|
||||
<>
|
||||
<Field label="Username" required invalid={!dsSettings.user} error={'Username is required'}>
|
||||
<Input
|
||||
value={dsSettings.user || ''}
|
||||
placeholder="user"
|
||||
onChange={onDSOptionChanged('user')}
|
||||
width={LONG_WIDTH}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
label="Password"
|
||||
required
|
||||
invalid={!dsSettings.secureJsonFields.password && !dsSettings.secureJsonData?.password}
|
||||
error={'Password is required'}
|
||||
>
|
||||
<SecretInput
|
||||
width={LONG_WIDTH}
|
||||
placeholder="Password"
|
||||
isConfigured={dsSettings.secureJsonFields && dsSettings.secureJsonFields.password}
|
||||
onReset={onResetPassword}
|
||||
onChange={onUpdateDatasourceSecureJsonDataOption(props, 'password')}
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
|
||||
{azureAuthIsSupported && jsonData.authenticationType === MSSQLAuthenticationType.azureAuth && (
|
||||
<FieldSet label="Azure Authentication Settings">
|
||||
<azureAuthSettings.azureAuthSettingsUI dataSourceConfig={dsSettings} onChange={onOptionsChange} />
|
||||
</FieldSet>
|
||||
)}
|
||||
</ConfigSection>
|
||||
|
||||
<Divider />
|
||||
<ConfigSection
|
||||
title="Additional settings"
|
||||
description="Additional settings are optional settings that can be configured for more control over your data source. This includes connection limits, connection timeout, group-by time interval, and Secure Socks Proxy."
|
||||
isCollapsible={true}
|
||||
isInitiallyOpen={true}
|
||||
>
|
||||
<ConnectionLimits labelWidth={SHORT_WIDTH} options={dsSettings} onOptionsChange={onOptionsChange} />
|
||||
|
||||
<ConfigSubSection title="Connection details">
|
||||
<Field
|
||||
description={
|
||||
<span>
|
||||
A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example
|
||||
<code>1m</code> if your data is written every minute.
|
||||
</span>
|
||||
}
|
||||
label="Min time interval"
|
||||
>
|
||||
<Input
|
||||
width={LONG_WIDTH}
|
||||
placeholder="1m"
|
||||
value={jsonData.timeInterval || ''}
|
||||
onChange={onUpdateDatasourceJsonDataOption(props, 'timeInterval')}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
description={
|
||||
<span>
|
||||
The number of seconds to wait before canceling the request when connecting to the database. The default
|
||||
is <code>0</code>, meaning no timeout.
|
||||
</span>
|
||||
}
|
||||
label="Connection timeout"
|
||||
>
|
||||
<NumberInput
|
||||
width={LONG_WIDTH}
|
||||
placeholder="60"
|
||||
min={0}
|
||||
value={jsonData.connectionTimeout}
|
||||
onChange={onConnectionTimeoutChanged}
|
||||
/>
|
||||
</Field>
|
||||
</ConfigSubSection>
|
||||
{config.secureSocksDSProxyEnabled && (
|
||||
<SecureSocksProxySettings options={dsSettings} onOptionsChange={onOptionsChange} />
|
||||
)}
|
||||
</ConfigSection>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -43,6 +43,10 @@ export interface MssqlOptions extends SQLOptions {
|
||||
azureCredentials?: AzureCredentialsType;
|
||||
}
|
||||
|
||||
export interface MssqlSecureOptions {
|
||||
password?: string;
|
||||
}
|
||||
|
||||
export type AzureAuthJSONDataType = DataSourceJsonData & {
|
||||
azureCredentials: AzureCredentialsType;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user