console: support computed fields in remote schema join

https://github.com/hasura/graphql-engine-mono/pull/2188

GitOrigin-RevId: 2d6fae62dbdcbdc7515a7b4982299dc9610a2230
This commit is contained in:
Ikechukwu Eze 2021-08-27 10:57:21 +01:00 committed by hasura-bot
parent 7a1446cec2
commit 3f4dda2520
11 changed files with 128 additions and 47 deletions

View File

@ -10,9 +10,10 @@
- server: fix broken `untrack_function` for non-default source
- server: Adding support for TLS allowlist by domain and service id (port)
- server: add support for `graphql-ws` clients
- console: fix error due too rendering inconsistent object's message
- console: fix error due to rendering inconsistent object's message
- console: support insecure TLS allowlist
- cli: fix delay starting console using `hasura console` (#7255)
- console: support computed fields in remote schema join
- cli: fix delay starting console using `hasura console` (#7255
## v2.0.7

View File

@ -310,6 +310,7 @@ const Relationships = ({
manualRelAdd,
currentSchema,
migrationMode,
allFunctions,
schemaList,
readOnlyMode,
currentSource,
@ -494,6 +495,7 @@ const Relationships = ({
relationships={existingRemoteRelationships}
reduxDispatch={dispatch}
table={tableSchema}
allFunctions={allFunctions}
remoteSchemas={remoteSchemas}
/>
</div>
@ -518,24 +520,32 @@ Relationships.propTypes = {
ongoingRequest: PropTypes.bool.isRequired,
lastError: PropTypes.object,
lastFormError: PropTypes.object,
allFunctions: PropTypes.array.isRequired,
lastSuccess: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
remoteSchemas: PropTypes.array.isRequired,
};
const mapStateToProps = (state, ownProps) => ({
tableName: ownProps.params.table,
allSchemas: state.tables.allSchemas,
currentSchema: state.tables.currentSchema,
migrationMode: state.main.migrationMode,
readOnlyMode: state.main.readOnlyMode,
serverVersion: state.main.serverVersion,
schemaList: state.tables.schemaList,
remoteSchemas: getRemoteSchemasSelector(state).map(schema => schema.name),
adminHeaders: state.tables.dataHeaders,
currentSource: state.tables.currentDataSource,
...state.tables.modify,
});
const mapStateToProps = (state, ownProps) => {
const {
nonTrackablePostgresFunctions: nonTrackableFns,
postgresFunctions: trackedFns,
} = state.tables;
return {
tableName: ownProps.params.table,
allSchemas: state.tables.allSchemas,
currentSchema: state.tables.currentSchema,
migrationMode: state.main.migrationMode,
readOnlyMode: state.main.readOnlyMode,
serverVersion: state.main.serverVersion,
schemaList: state.tables.schemaList,
allFunctions: nonTrackableFns?.concat(trackedFns ?? []) ?? [],
remoteSchemas: getRemoteSchemasSelector(state).map(schema => schema.name),
adminHeaders: state.tables.dataHeaders,
currentSource: state.tables.currentDataSource,
...state.tables.modify,
};
};
const relationshipsConnector = connect =>
connect(mapStateToProps)(Relationships);

View File

@ -33,6 +33,7 @@ class RelationshipsView extends Component {
lastFormError,
lastSuccess,
dispatch,
allFunctions,
manualRelAdd,
currentSchema,
migrationMode,
@ -137,6 +138,7 @@ class RelationshipsView extends Component {
relationships={tableSchema.remote_relationships}
reduxDispatch={dispatch}
table={tableSchema}
allFunctions={allFunctions}
remoteSchemas={remoteSchemas}
/>
</div>
@ -200,22 +202,30 @@ RelationshipsView.propTypes = {
lastSuccess: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
serverVersion: PropTypes.string,
allFunctions: PropTypes.array.isRequired,
remoteSchemas: PropTypes.array.isRequired,
featuresCompatibility: PropTypes.object,
};
const mapStateToProps = (state, ownProps) => ({
tableName: ownProps.params.table,
allSchemas: state.tables.allSchemas,
currentSchema: state.tables.currentSchema,
migrationMode: state.main.migrationMode,
readOnlyMode: state.main.readOnlyMode,
serverVersion: state.main.serverVersion,
schemaList: state.tables.schemaList,
remoteSchemas: getRemoteSchemasSelector(state).map(schema => schema.name),
currentSource: state.tables.currentDataSource,
...state.tables.modify,
});
const mapStateToProps = (state, ownProps) => {
const {
nonTrackablePostgresFunctions: nonTrackableFns,
postgresFunctions: trackedFns,
} = state.tables;
return {
tableName: ownProps.params.table,
allSchemas: state.tables.allSchemas,
currentSchema: state.tables.currentSchema,
migrationMode: state.main.migrationMode,
readOnlyMode: state.main.readOnlyMode,
serverVersion: state.main.serverVersion,
allFunctions: nonTrackableFns?.concat(trackedFns ?? []) ?? [],
schemaList: state.tables.schemaList,
remoteSchemas: getRemoteSchemasSelector(state).map(schema => schema.name),
currentSource: state.tables.currentDataSource,
...state.tables.modify,
};
};
const relationshipsViewConnector = connect =>
connect(mapStateToProps)(RelationshipsView);

View File

@ -6,11 +6,13 @@ import ToolTip from '../../../../Common/Tooltip/Tooltip';
import KnowMoreLink from '../../../../Common/KnowMoreLink/KnowMoreLink';
import { Dispatch } from '../../../../../types';
import { Table } from '../../../../../dataSources/types';
import { PGFunction } from '../../../../../dataSources/services/postgresql/types';
type Props = {
relationships: RemoteRelationshipServer[];
reduxDispatch: Dispatch;
table: Table;
allFunctions: PGFunction[];
remoteSchemas: string[];
};
@ -18,6 +20,7 @@ const RemoteRelationships: React.FC<Props> = ({
relationships,
reduxDispatch,
table,
allFunctions,
remoteSchemas,
}) => {
return (
@ -32,6 +35,7 @@ const RemoteRelationships: React.FC<Props> = ({
<RemoteRelationshipList
relationships={relationships}
table={table}
allFunctions={allFunctions}
remoteSchemas={remoteSchemas}
reduxDispatch={reduxDispatch}
/>

View File

@ -1,4 +1,4 @@
@import "../../../../Common/Common.scss";
@import '../../../../Common/Common.scss';
.schemaExplorerContainer {
background-color: #f7f7f7;
@ -7,7 +7,7 @@
border-radius: 4px;
}
.height200Px {
.height200Px {
height: 200px;
}
@ -29,16 +29,15 @@
}
.scalarColumnSelect {
margin-left: 5px;
margin-left: 5px;
border-radius: 4px;
background-color: white;
background-color: white;
border: 1px solid #ccc;
}
.argValue {
background-color: white;
height: 30px;
padding: 5px;
padding-right: 2.5rem;
color: #555555;
font-style: normal;
}
@ -54,6 +53,6 @@
}
.argElement {
color: #8B2BB9;
color: #8b2bb9;
font-style: italic;
}
}

View File

@ -2,13 +2,14 @@ import React from 'react';
import { TreeArgElement, ArgValueKind } from '../utils';
import styles from '../SchemaExplorer.scss';
import ArgValueElement from './ArgValue';
import { HasuraColumn } from './Explorer';
type Props = {
arg: TreeArgElement;
handleToggle: (a: TreeArgElement) => void;
handleArgValueKindChange: (a: TreeArgElement, type: ArgValueKind) => void;
handleArgValueChange: (a: TreeArgElement, value: string) => void;
columns: string[];
columns: HasuraColumn;
};
const ArgElement: React.FC<Props> = ({

View File

@ -1,12 +1,13 @@
import React from 'react';
import { ArgValue } from '../utils';
import styles from '../SchemaExplorer.scss';
import { HasuraColumn } from './Explorer';
type Props = {
value: ArgValue;
handleArgValueKindChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
handleArgValueChange: (e: React.BaseSyntheticEvent) => void;
columns: string[];
columns: HasuraColumn;
};
const ArgValueElement: React.FC<Props> = ({
@ -41,13 +42,26 @@ const ArgValueElement: React.FC<Props> = ({
-- column-name --
</option>
)}
{columns.map(o => {
return (
<option key={o} value={o}>
{o}
</option>
);
})}
<optgroup label="Columns">
{columns.columns.map(o => {
return (
<option key={o} value={o}>
{o}
</option>
);
})}
</optgroup>
{columns.computedFields.length ? (
<optgroup label="Computed Fields">
{columns.computedFields.map(o => {
return (
<option key={o} value={o}>
{o}
</option>
);
})}
</optgroup>
) : null}
</select>
) : (
<input

View File

@ -22,10 +22,15 @@ type Props = {
handleArgValueKindChange: (a: TreeArgElement, type: ArgValueKind) => void;
handleArgValueChange: (a: TreeArgElement, value: string) => void;
remoteSchemaName: string;
columns: string[];
columns: HasuraColumn;
reduxDispatch: ThunkAction<void, ReduxState, unknown, ReduxAction>;
};
export type HasuraColumn = {
columns: string[];
computedFields: string[];
};
const Explorer: React.FC<Props> = ({
relationship,
toggleArg,
@ -85,7 +90,13 @@ const Explorer: React.FC<Props> = ({
}
case 'field': {
const el: TreeFieldElement = element;
return <FieldElement field={el} handleToggle={toggleField} />;
return (
<FieldElement
field={el}
handleToggle={toggleField}
key={`field-element-${el.name}-${el.depth}`}
/>
);
}
default:
return null;

View File

@ -25,6 +25,11 @@ import {
import Explorer from './Explorer';
import { ReduxState, ReduxAction } from '../../../../../../types';
import { Table } from '../../../../../../dataSources/types';
import { PGFunction } from '../../../../../../dataSources/services/postgresql/types';
import {
getComputedFieldFunction,
getGroupedTableComputedFields,
} from '../../../../../../dataSources/services/postgresql';
type Props = {
table: Table;
@ -32,6 +37,7 @@ type Props = {
isLast: boolean;
state: RemoteRelationship;
dispatch: React.Dispatch<RemoteRelAction>;
allFunctions: PGFunction[];
reduxDispatch: ThunkAction<void, ReduxState, unknown, ReduxAction>;
};
@ -40,6 +46,7 @@ const RemoteRelEditor: React.FC<Props> = ({
isLast,
remoteSchemas,
state,
allFunctions,
dispatch,
reduxDispatch,
}) => {
@ -77,6 +84,18 @@ const RemoteRelEditor: React.FC<Props> = ({
}
);
const computedFields = getGroupedTableComputedFields(table, allFunctions);
const scalarComputedFields = computedFields.scalar.filter(sc => {
const cFn = getComputedFieldFunction(sc, allFunctions)?.input_arg_types;
// Only the computed fields that do not require extra arguments other than the table row
// are currenlty supported by the server https://github.com/hasura/graphql-engine/issues/7336
return cFn?.length === 1 && cFn[0].name === table.table_name;
});
const computedFieldsNames = scalarComputedFields.map(
f => f.computed_field_name
);
return (
<React.Fragment>
<div>
@ -152,7 +171,10 @@ const RemoteRelEditor: React.FC<Props> = ({
handleArgValueKindChange={handleArgValueKindChange}
handleArgValueChange={handleArgValueChange}
remoteSchemaName={state.remoteSchema}
columns={tableColumns}
columns={{
columns: tableColumns,
computedFields: computedFieldsNames,
}}
reduxDispatch={reduxDispatch}
/>
</div>

View File

@ -7,6 +7,7 @@ import { useRemoteRelationship } from '../state';
import { saveRemoteRelationship, dropRemoteRelationship } from '../../Actions';
import { Dispatch } from '../../../../../../types';
import { Table } from '../../../../../../dataSources/types';
import { PGFunction } from '../../../../../../dataSources/services/postgresql/types';
type Props = {
relationship?: RemoteRelationshipServer;
@ -14,6 +15,7 @@ type Props = {
isLast: boolean;
remoteSchemas: string[];
reduxDispatch: Dispatch;
allFunctions: PGFunction[];
};
const EditorWrapper: React.FC<Props> = ({
@ -22,6 +24,7 @@ const EditorWrapper: React.FC<Props> = ({
isLast,
remoteSchemas,
reduxDispatch,
allFunctions,
}) => {
const { state, dispatch, reset } = useRemoteRelationship(table, relationship);
@ -31,6 +34,7 @@ const EditorWrapper: React.FC<Props> = ({
remoteSchemas={remoteSchemas}
isLast={isLast}
state={state}
allFunctions={allFunctions}
dispatch={dispatch}
reduxDispatch={reduxDispatch}
/>

View File

@ -3,11 +3,13 @@ import { RemoteRelationshipServer } from '../utils';
import RemoteRelationshipEditor from './RemoteRelEditorWrapper';
import { Dispatch } from '../../../../../../types';
import { Table } from '../../../../../../dataSources/types';
import { PGFunction } from '../../../../../../dataSources/services/postgresql/types';
type Props = {
relationships: RemoteRelationshipServer[];
table: Table;
remoteSchemas: string[];
allFunctions: PGFunction[];
reduxDispatch: Dispatch;
};
@ -15,6 +17,7 @@ const RemoteRelationshipList: React.FC<Props> = ({
relationships,
table,
remoteSchemas,
allFunctions,
reduxDispatch,
}) => {
return (
@ -26,6 +29,7 @@ const RemoteRelationshipList: React.FC<Props> = ({
table={table}
remoteSchemas={remoteSchemas}
reduxDispatch={reduxDispatch}
allFunctions={allFunctions}
isLast={false}
/>
))}
@ -33,6 +37,7 @@ const RemoteRelationshipList: React.FC<Props> = ({
key="add-remote-rel"
table={table}
remoteSchemas={remoteSchemas}
allFunctions={allFunctions}
reduxDispatch={reduxDispatch}
isLast
/>