mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-11-12 23:21:02 +03:00
console: implement new design for naming convention and edit functionality for Graphql Field Customization
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4859 Co-authored-by: Rikin Kachhia <54616969+rikinsk@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Hardman <28978422+mattshardman@users.noreply.github.com> GitOrigin-RevId: ebe25491b90caf9d1de091072727503d666469fe
This commit is contained in:
parent
b9fb7d8720
commit
4a129042fa
@ -56,7 +56,7 @@
|
||||
- objects now have a title and, when available, the same description as in the GraphQL schema
|
||||
- server: fix dropping column from a table that has update permissions (fix #8415)
|
||||
- console: Hide TimescaleDB internal schema from data tab
|
||||
- console: support naming convention in source customization for postgres DB [CON-297]
|
||||
- console: support naming conventions under GraphQL customizations while connecting postgres DB
|
||||
|
||||
## v2.8.3
|
||||
|
||||
|
@ -1579,7 +1579,7 @@ code {
|
||||
}
|
||||
|
||||
.connect_form_width {
|
||||
width: 50%;
|
||||
width: 66%;
|
||||
}
|
||||
|
||||
/* container height subtracting top header and bottom scroll bar */
|
||||
|
@ -137,7 +137,6 @@ const ConnectDatabaseForm: React.FC<ConnectDatabaseFormProps> = ({
|
||||
changeConnectionType(driverToLabel[value].defaultConnection);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.connect_form_layout}>
|
||||
@ -447,15 +446,14 @@ const ConnectDatabaseForm: React.FC<ConnectDatabaseFormProps> = ({
|
||||
TODO: remove the edit state condition when the BE issue is solved
|
||||
https://github.com/hasura/graphql-engine-mono/issues/4700
|
||||
*/}
|
||||
{!isEditState && (
|
||||
<GraphQLFieldCustomizationContainer
|
||||
rootFields={connectionDBState.customization?.rootFields}
|
||||
typeNames={connectionDBState.customization?.typeNames}
|
||||
namingConvention={connectionDBState.customization?.namingConvention}
|
||||
connectionDBStateDispatch={connectionDBStateDispatch}
|
||||
connectionDBState={connectionDBState}
|
||||
/>
|
||||
)}
|
||||
|
||||
<GraphQLFieldCustomizationContainer
|
||||
rootFields={connectionDBState.customization?.rootFields}
|
||||
typeNames={connectionDBState.customization?.typeNames}
|
||||
namingConvention={connectionDBState.customization?.namingConvention}
|
||||
connectionDBStateDispatch={connectionDBStateDispatch}
|
||||
connectionDBState={connectionDBState}
|
||||
/>
|
||||
</div>
|
||||
<hr className={styles.line_width} />
|
||||
</>
|
||||
|
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export const FormRow = (props: Props) => {
|
||||
const { name, label, placeholder, value = '', onChange } = props;
|
||||
return (
|
||||
<>
|
||||
<label
|
||||
htmlFor={name}
|
||||
className="font-normal px-sm py-xs text-gray-600 w-1/3"
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
<span className="px-sm py-xs">
|
||||
<input
|
||||
type="text"
|
||||
name={name}
|
||||
aria-label={name}
|
||||
placeholder={placeholder}
|
||||
className="form-control font-normal"
|
||||
defaultValue={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,188 +1,84 @@
|
||||
import { getSupportedDrivers } from '@/dataSources';
|
||||
import { namingConventionOptions } from '@/metadata/types';
|
||||
import { Collapse } from '@/new-components/Collapse';
|
||||
import { ToolTip } from '@/new-components/Tooltip';
|
||||
import React from 'react';
|
||||
import { ConnectDBState } from '../state';
|
||||
import { FormRow } from './FormRow';
|
||||
import { NamingConvention } from './NamingConvention';
|
||||
import {
|
||||
CustomizationFieldName,
|
||||
GraphQLFieldCustomizationProps,
|
||||
RootFields,
|
||||
TypeNames,
|
||||
} from './types';
|
||||
|
||||
type FormRowProps = {
|
||||
name: string;
|
||||
label: string;
|
||||
placeholder: string;
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
const FormRow: React.FC<FormRowProps> = ({
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
value = '',
|
||||
onChange,
|
||||
}) => (
|
||||
<>
|
||||
<label
|
||||
htmlFor={name}
|
||||
className="font-normal px-sm py-xs text-gray-600 w-1/3"
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
<span className="px-sm py-xs">
|
||||
<input
|
||||
type="text"
|
||||
name={name}
|
||||
aria-label={name}
|
||||
placeholder={placeholder}
|
||||
className="form-control font-normal"
|
||||
defaultValue={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
|
||||
type TypeNamesField = {
|
||||
id: 'prefix' | 'suffix';
|
||||
label: string;
|
||||
placeholder: string;
|
||||
};
|
||||
|
||||
const TypeNames: TypeNamesField[] = [
|
||||
{ label: 'Prefix', placeholder: 'prefix_', id: 'prefix' },
|
||||
{ label: 'Suffix', placeholder: '_suffix', id: 'suffix' },
|
||||
];
|
||||
|
||||
type RootFieldsField = Omit<TypeNamesField, 'id'> & {
|
||||
id: TypeNamesField['id'] | 'namespace';
|
||||
};
|
||||
|
||||
const RootFields: RootFieldsField[] = [
|
||||
{ label: 'Namespace', placeholder: 'Namespace...', id: 'namespace' },
|
||||
...TypeNames,
|
||||
];
|
||||
|
||||
export type CustomizationFieldName =
|
||||
| 'rootFields.namespace'
|
||||
| 'rootFields.prefix'
|
||||
| 'rootFields.suffix'
|
||||
| 'typeNames.prefix'
|
||||
| 'typeNames.suffix'
|
||||
| 'namingConvention';
|
||||
|
||||
export type GraphQLFieldCustomizationProps = {
|
||||
rootFields?: {
|
||||
namespace?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
typeNames?: {
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
namingConvention?: namingConventionOptions;
|
||||
onChange: (fieldName: CustomizationFieldName, fieldValue: string) => void;
|
||||
connectionDBState?: ConnectDBState;
|
||||
};
|
||||
|
||||
export const GraphQLFieldCustomization: React.FC<GraphQLFieldCustomizationProps> = ({
|
||||
export const GraphQLFieldCustomization = ({
|
||||
rootFields,
|
||||
typeNames,
|
||||
namingConvention,
|
||||
onChange,
|
||||
namingConvention,
|
||||
connectionDBState,
|
||||
}) => {
|
||||
}: GraphQLFieldCustomizationProps) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="w-full mb-md">
|
||||
<div>
|
||||
<div className="cursor-pointer w-full flex-initial align-middle">
|
||||
<div className="font-semibold">
|
||||
<Collapse
|
||||
title="GraphQL Field Customization"
|
||||
defaultOpen={false}
|
||||
tooltip="Set a namespace or add a prefix / suffix to the root fields and types for the database's objects in the GraphQL API"
|
||||
>
|
||||
<Collapse.Content>
|
||||
{connectionDBState?.dbType &&
|
||||
getSupportedDrivers(
|
||||
'connectDbForm.namingConvention'
|
||||
).includes(connectionDBState?.dbType) && (
|
||||
<div className="grid gap-0 grid-cols-2 grid-rows">
|
||||
<label className="p-sm text-gray-600 font-semibold py-xs w-1/3">
|
||||
Naming Convention
|
||||
</label>
|
||||
<span className="px-sm py-xs">
|
||||
<select
|
||||
className="form-control font-normal cursor-pointer"
|
||||
onChange={e => {
|
||||
if (namingConvention) {
|
||||
onChange('namingConvention', e.target.value);
|
||||
}
|
||||
}}
|
||||
value={namingConvention}
|
||||
>
|
||||
<option value="hasura-default">
|
||||
hasura-default
|
||||
</option>
|
||||
<option value="graphql-default">
|
||||
graphql-default
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="p-sm text-gray-600 font-semibold">
|
||||
Root Fields
|
||||
</div>
|
||||
<div className="mb-md">
|
||||
<div className="w-full flex-initial align-middle">
|
||||
<div className="font-semibold">
|
||||
<Collapse title="GraphQL Field Customization" defaultOpen={false}>
|
||||
<Collapse.Content>
|
||||
<NamingConvention
|
||||
onChange={onChange}
|
||||
namingConvention={namingConvention}
|
||||
connectionDBState={connectionDBState}
|
||||
/>
|
||||
<div>
|
||||
<div className="flex items-center p-sm text-gray-600 font-semibold">
|
||||
Root Fields
|
||||
<ToolTip message="Set a namespace or add a prefix / suffix to the root fields for the database's objects in the GraphQL API" />
|
||||
</div>
|
||||
<form
|
||||
aria-label="rootFields"
|
||||
className={`grid gap-0 grid-cols-2 grid-rows-${RootFields.length}`}
|
||||
>
|
||||
{RootFields.map(({ label, placeholder, id }) => {
|
||||
const inputName: CustomizationFieldName = `rootFields.${id}`;
|
||||
return (
|
||||
<FormRow
|
||||
key={id}
|
||||
name={inputName}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
value={rootFields?.[id]}
|
||||
onChange={(value: string) =>
|
||||
onChange(inputName, value)
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</form>
|
||||
<div>
|
||||
<div className="p-sm text-gray-600 font-semibold">
|
||||
Type Names
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
aria-label="rootFields"
|
||||
className={`grid gap-0 grid-cols-2 grid-rows-${RootFields.length}`}
|
||||
>
|
||||
{RootFields.map(({ label, placeholder, id }) => {
|
||||
const inputName: CustomizationFieldName = `rootFields.${id}`;
|
||||
return (
|
||||
<FormRow
|
||||
key={id}
|
||||
name={inputName}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
value={rootFields?.[id]}
|
||||
onChange={(value: string) => onChange(inputName, value)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</form>
|
||||
<div>
|
||||
<div className="flex items-center p-sm text-gray-600 font-semibold">
|
||||
Type Names
|
||||
<ToolTip message="Add a prefix / suffix to the types for the database's objects in the GraphQL API" />
|
||||
</div>
|
||||
<form
|
||||
aria-label="typeNames"
|
||||
className={`grid gap-0 grid-cols-2 grid-rows-${TypeNames.length}`}
|
||||
>
|
||||
{TypeNames.map(({ label, placeholder, id }) => {
|
||||
const inputName: CustomizationFieldName = `typeNames.${id}`;
|
||||
return (
|
||||
<FormRow
|
||||
key={id}
|
||||
name={inputName}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
value={typeNames?.[id]}
|
||||
onChange={(value: string) =>
|
||||
onChange(inputName, value)
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</form>
|
||||
</Collapse.Content>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
aria-label="typeNames"
|
||||
className={`grid gap-0 grid-cols-2 grid-rows-${TypeNames.length}`}
|
||||
>
|
||||
{TypeNames.map(({ label, placeholder, id }) => {
|
||||
const inputName: CustomizationFieldName = `typeNames.${id}`;
|
||||
return (
|
||||
<FormRow
|
||||
key={id}
|
||||
name={inputName}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
value={typeNames?.[id]}
|
||||
onChange={(value: string) => onChange(inputName, value)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</form>
|
||||
</Collapse.Content>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { Dispatch } from 'react';
|
||||
import { ConnectDBActions } from '../state';
|
||||
import { GraphQLFieldCustomization } from './GraphQLFieldCustomization';
|
||||
import {
|
||||
CustomizationFieldName,
|
||||
GraphQLFieldCustomization,
|
||||
GraphQLFieldCustomizationProps,
|
||||
} from './GraphQLFieldCustomization';
|
||||
} from './types';
|
||||
|
||||
type GraphQLFieldCustomizationContainerProps = Omit<
|
||||
GraphQLFieldCustomizationProps,
|
||||
|
@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { NamingConventionOptions } from '@/metadata/types';
|
||||
import { ToolTip } from '@/new-components/Tooltip';
|
||||
import { useServerConfig } from '@/hooks';
|
||||
import { getSupportedDrivers } from '@/dataSources';
|
||||
import { CardRadioGroup } from '@/new-components/CardRadioGroup';
|
||||
import { GraphQLFieldCustomizationProps } from './types';
|
||||
|
||||
const namingConventionRadioGroupItems: {
|
||||
value: NamingConventionOptions;
|
||||
title: string;
|
||||
body: React.ReactNode;
|
||||
}[] = [
|
||||
{
|
||||
value: 'hasura-default',
|
||||
title: 'hasura-default',
|
||||
body: (
|
||||
<div className="font-thin">
|
||||
<li>All names will use snake_case</li>
|
||||
<li> Enum values will not be changed</li>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 'graphql-default',
|
||||
title: 'graphql-default',
|
||||
body: (
|
||||
<div className="font-thin">
|
||||
<li>
|
||||
Field names, argument names, and <br />{' '}
|
||||
<p className="pl-6 pb-0">boolean operators will be camelCased</p>
|
||||
</li>
|
||||
<li>Type names will be PascalCased</li>
|
||||
<li>Enum values will be UPPERCASED</li>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export const NamingConvention: React.FC<GraphQLFieldCustomizationProps> = ({
|
||||
onChange,
|
||||
namingConvention,
|
||||
connectionDBState,
|
||||
}) => {
|
||||
const { data: configData, isLoading, isError } = useServerConfig();
|
||||
|
||||
if (isError) {
|
||||
return <div>Error in fetching server configuration</div>;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
const isNamingConventionEnabled = configData?.experimental_features.includes(
|
||||
'naming_convention'
|
||||
);
|
||||
|
||||
const isNamingConventionSupported =
|
||||
connectionDBState?.dbType &&
|
||||
getSupportedDrivers('connectDbForm.namingConvention').includes(
|
||||
connectionDBState?.dbType
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isNamingConventionSupported ? (
|
||||
<div className="p-sm box-border">
|
||||
<p className="flex items-center text-gray-600 font-semibold">
|
||||
Naming Convention
|
||||
<ToolTip message="Choose a default naming convention for your auto-generated GraphQL schema objects (fields, types, arguments, etc.)" />
|
||||
<a
|
||||
href="https://hasura.io/docs/latest/graphql/core/databases/postgres/schema/naming-convention/#set-naming-convention-for-a-particular-source"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span className="italic font-thin text-sm pl-1">(Know More)</span>
|
||||
</a>
|
||||
</p>
|
||||
{!isNamingConventionEnabled ? (
|
||||
<div className="font-thin">
|
||||
Naming convention is not enabled. To enable naming convention,
|
||||
start the Hasura server with environment variable
|
||||
<code>
|
||||
HASURA_GRAPHQL_EXPERIMENTAL_FEATURES:
|
||||
"naming_convention"
|
||||
</code>
|
||||
</div>
|
||||
) : (
|
||||
<span className="p-sm py-8">
|
||||
<CardRadioGroup
|
||||
items={namingConventionRadioGroupItems}
|
||||
onChange={ncType => onChange('namingConvention', ncType)}
|
||||
value={namingConvention}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
import { NamingConventionOptions } from '@/metadata/types';
|
||||
import { ConnectDBState } from '../state';
|
||||
|
||||
export type TypeNamesField = {
|
||||
id: 'prefix' | 'suffix';
|
||||
label: string;
|
||||
placeholder: string;
|
||||
};
|
||||
|
||||
export const TypeNames: TypeNamesField[] = [
|
||||
{ label: 'Prefix', placeholder: 'prefix_', id: 'prefix' },
|
||||
{ label: 'Suffix', placeholder: '_suffix', id: 'suffix' },
|
||||
];
|
||||
|
||||
export type RootFieldsField = {
|
||||
id: 'prefix' | 'suffix' | 'namespace';
|
||||
label: string;
|
||||
placeholder: string;
|
||||
};
|
||||
|
||||
export const RootFields: RootFieldsField[] = [
|
||||
{ label: 'Namespace', placeholder: 'Namespace...', id: 'namespace' },
|
||||
...TypeNames,
|
||||
];
|
||||
|
||||
export type CustomizationFieldName =
|
||||
| 'rootFields.namespace'
|
||||
| 'rootFields.prefix'
|
||||
| 'rootFields.suffix'
|
||||
| 'typeNames.prefix'
|
||||
| 'typeNames.suffix'
|
||||
| 'namingConvention'
|
||||
| string;
|
||||
|
||||
export type GraphQLFieldCustomizationProps = {
|
||||
rootFields?: {
|
||||
namespace?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
typeNames?: {
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
onChange: (fieldName: CustomizationFieldName, fieldValue: string) => void;
|
||||
connectionDBState?: ConnectDBState;
|
||||
namingConvention?: NamingConventionOptions;
|
||||
};
|
@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { GraphQLFieldCustomization } from '../GraphQLFieldCustomization/GraphQLFieldCustomization';
|
||||
import { renderWithClient } from '../../../../../hooks/__tests__/common/decorator';
|
||||
|
||||
describe('component GraphQLFieldCustomization', () => {
|
||||
it('renders', () => {
|
||||
render(<GraphQLFieldCustomization onChange={() => null} />);
|
||||
renderWithClient(<GraphQLFieldCustomization onChange={() => null} />);
|
||||
|
||||
fireEvent.click(screen.getByText('GraphQL Field Customization'));
|
||||
|
||||
@ -21,7 +22,7 @@ describe('component GraphQLFieldCustomization', () => {
|
||||
});
|
||||
|
||||
it('passes props', () => {
|
||||
render(
|
||||
renderWithClient(
|
||||
<GraphQLFieldCustomization
|
||||
rootFields={{
|
||||
namespace: 'name',
|
||||
@ -53,7 +54,7 @@ describe('component GraphQLFieldCustomization', () => {
|
||||
describe('when the user provides the values', () => {
|
||||
it('calls the on change callback', () => {
|
||||
const onChange = jest.fn();
|
||||
render(<GraphQLFieldCustomization onChange={onChange} />);
|
||||
renderWithClient(<GraphQLFieldCustomization onChange={onChange} />);
|
||||
|
||||
fireEvent.click(screen.getByText('GraphQL Field Customization'));
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { CustomizationFieldName } from '../GraphQLFieldCustomization/GraphQLFieldCustomization';
|
||||
import { getActionType } from '../GraphQLFieldCustomization/GraphQLFieldCustomizationContainer';
|
||||
import { CustomizationFieldName } from '../GraphQLFieldCustomization/types';
|
||||
|
||||
describe('getActionType', () => {
|
||||
const tests = [
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
SSLConfigOptions,
|
||||
IsolationLevelOptions,
|
||||
GraphQLFieldCustomization,
|
||||
namingConventionOptions,
|
||||
NamingConventionOptions,
|
||||
} from '../../../../metadata/types';
|
||||
|
||||
export const connectionTypes = {
|
||||
@ -260,7 +260,7 @@ export type ConnectDBActions =
|
||||
| { type: 'RESET_INPUT_STATE' }
|
||||
| {
|
||||
type: 'UPDATE_CUSTOMIZATION_NAMING_CONVENTION';
|
||||
data: namingConventionOptions;
|
||||
data: NamingConventionOptions;
|
||||
}
|
||||
| { type: 'UPDATE_CUSTOMIZATION_ROOT_FIELDS_NAMESPACE'; data: string }
|
||||
| { type: 'UPDATE_CUSTOMIZATION_ROOT_FIELDS_PREFIX'; data: string }
|
||||
|
@ -71,6 +71,23 @@ export const addSource = (
|
||||
const adaptedCustomizations = adaptCustomizations(payload?.customization);
|
||||
|
||||
if (driver === 'mssql') {
|
||||
if (payload?.replace_configuration) {
|
||||
return {
|
||||
type: 'mssql_update_source',
|
||||
args: {
|
||||
name: payload.name,
|
||||
configuration: {
|
||||
connection_info: {
|
||||
connection_string: payload.dbUrl,
|
||||
pool_settings: payload.connection_pool_settings,
|
||||
},
|
||||
read_replicas: replicas?.length ? replicas : null,
|
||||
},
|
||||
replace_configuration,
|
||||
...adaptedCustomizations,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'mssql_add_source',
|
||||
args: {
|
||||
@ -93,6 +110,22 @@ export const addSource = (
|
||||
typeof payload.dbUrl === 'string'
|
||||
? JSON.parse(payload.dbUrl)
|
||||
: payload.dbUrl;
|
||||
if (payload?.replace_configuration) {
|
||||
return {
|
||||
type: 'bigquery_update_source',
|
||||
args: {
|
||||
name: payload.name,
|
||||
configuration: {
|
||||
service_account,
|
||||
global_select_limit: payload.bigQuery.global_select_limit,
|
||||
project_id: payload.bigQuery.projectId,
|
||||
datasets: payload.bigQuery.datasets.split(',').map(d => d.trim()),
|
||||
},
|
||||
replace_configuration,
|
||||
...adaptedCustomizations,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'bigquery_add_source',
|
||||
args: {
|
||||
@ -109,6 +142,32 @@ export const addSource = (
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
(driver === 'postgres' || driver === 'citus') &&
|
||||
payload?.replace_configuration
|
||||
) {
|
||||
return {
|
||||
type: `${driver === 'postgres' ? 'pg' : 'citus'}_update_source`,
|
||||
args: {
|
||||
name: payload.name,
|
||||
configuration: {
|
||||
connection_info: {
|
||||
database_url: payload.connection_parameters
|
||||
? { connection_parameters: payload.connection_parameters }
|
||||
: payload.dbUrl,
|
||||
use_prepared_statements: payload.preparedStatements,
|
||||
isolation_level: payload.isolationLevel,
|
||||
pool_settings: payload.connection_pool_settings,
|
||||
ssl_configuration: payload.sslConfiguration,
|
||||
},
|
||||
read_replicas: replicas?.length ? replicas : null,
|
||||
},
|
||||
replace_configuration,
|
||||
...adaptedCustomizations,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: `${driver === 'postgres' ? 'pg' : 'citus'}_add_source`,
|
||||
args: {
|
||||
|
@ -1010,7 +1010,7 @@ export type IsolationLevelOptions =
|
||||
| 'repeatable-read'
|
||||
| 'serializable';
|
||||
|
||||
export type namingConventionOptions = 'hasura-default' | 'graphql-default';
|
||||
export type NamingConventionOptions = 'hasura-default' | 'graphql-default';
|
||||
|
||||
export interface SSLConfigOptions {
|
||||
sslmode?: SSLModeOptions;
|
||||
@ -1054,7 +1054,7 @@ export type GraphQLFieldCustomization = {
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
namingConvention?: namingConventionOptions;
|
||||
namingConvention?: NamingConventionOptions;
|
||||
};
|
||||
|
||||
export interface SourceConnectionInfo {
|
||||
|
@ -4,7 +4,7 @@ import React from 'react';
|
||||
interface CardRadioGroupItem<T> {
|
||||
value: T;
|
||||
title: string;
|
||||
body: string;
|
||||
body: string | React.ReactNode;
|
||||
}
|
||||
|
||||
interface CardRadioGroupProps<T> {
|
||||
@ -58,7 +58,7 @@ export const CardRadioGroup = <T extends string = string>(
|
||||
<label
|
||||
htmlFor={`radio-select-${iValue}`}
|
||||
className={clsx(
|
||||
'mb-sm font-semibold',
|
||||
'mb-sm font-semibold mt-0.5',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-pointer'
|
||||
)}
|
||||
>
|
||||
|
@ -13,6 +13,7 @@ keywords:
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import Thumbnail from "@site/src/components/Thumbnail";
|
||||
import TabItem from '@theme/TabItem';
|
||||
import GraphiQLIDE from '@site/src/components/GraphiQLIDE';
|
||||
|
||||
@ -153,19 +154,26 @@ For the above schema, a sample GraphQL query will look like the following with t
|
||||
`}
|
||||
/>
|
||||
|
||||
## Set default naming convention for all sources {#pg-default-naming-convention}
|
||||
## Set default naming convention for all database sources {#pg-default-naming-convention}
|
||||
|
||||
For setting the default naming convention for all sources, set the environment variable
|
||||
For setting the default naming convention for all database sources, set the environment variable
|
||||
`HASURA_GRAPHQL_DEFAULT_NAMING_CONVENTION` to one of `hasura-default` or `graphql-default`.
|
||||
|
||||
This means any database source will follow this naming convention unless explicitly set to something else.
|
||||
|
||||
## Set naming convention for a particular source {#pg-source-naming-convention}
|
||||
## Set naming convention for a particular database source {#pg-source-naming-convention}
|
||||
|
||||
<Tabs className="api-tabs">
|
||||
<TabItem value="console" label="Console">
|
||||
|
||||
Console support will be added soon.
|
||||
Currently setting the database naming convention is only allowed at the time of connecting your database.
|
||||
Head to the `Data -> Manage -> Connect Database` page. Under the `GraphQL Field Customization` section you can
|
||||
choose the naming convention of your choice.
|
||||
|
||||
<Thumbnail
|
||||
src="/img/graphql/core/schema/naming-convention.png"
|
||||
alt="Naming Convention"
|
||||
/>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cli" label="CLI">
|
||||
|
BIN
docs/static/img/graphql/core/schema/naming-convention.png
vendored
Normal file
BIN
docs/static/img/graphql/core/schema/naming-convention.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
Loading…
Reference in New Issue
Block a user