mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
* handle string errors * handle empty columns / computed fields in permissions (#3789) * allow is_null for all operators (#3777)
This commit is contained in:
parent
405d6450f9
commit
fca16b88ef
@ -4,7 +4,7 @@ import { showNotification } from '../../App/Actions';
|
||||
import Button from '../../Common/Button/Button';
|
||||
|
||||
import './Notification/NotificationOverrides.css';
|
||||
import { isString } from '../../Common/utils/jsUtils';
|
||||
import { isObject, isString } from '../../Common/utils/jsUtils';
|
||||
|
||||
const styles = require('./Notification/Notification.scss');
|
||||
|
||||
@ -31,48 +31,47 @@ const getNotificationDetails = (detailsJson, children = null) => {
|
||||
const showErrorNotification = (title, message, error) => {
|
||||
const getErrorMessage = () => {
|
||||
let notificationMessage;
|
||||
if (
|
||||
error &&
|
||||
error.message &&
|
||||
(error.message.error === 'postgres query error' ||
|
||||
error.message.error === 'query execution failed')
|
||||
) {
|
||||
if (error.message.internal) {
|
||||
notificationMessage =
|
||||
error.message.code + ': ' + error.message.internal.error.message;
|
||||
} else {
|
||||
notificationMessage = error.code + ': ' + error.message.error;
|
||||
}
|
||||
} else if (error && 'info' in error) {
|
||||
notificationMessage = error.info;
|
||||
} else if (error && 'message' in error) {
|
||||
if (error.code) {
|
||||
if (error.message.error) {
|
||||
notificationMessage = error.message.error.message;
|
||||
|
||||
if (error) {
|
||||
if (isString(error)) {
|
||||
notificationMessage = error;
|
||||
} else if (
|
||||
error.message &&
|
||||
(error.message.error === 'postgres query error' ||
|
||||
error.message.error === 'query execution failed')
|
||||
) {
|
||||
if (error.message.internal) {
|
||||
notificationMessage =
|
||||
error.message.code + ': ' + error.message.internal.error.message;
|
||||
} else {
|
||||
notificationMessage = error.message;
|
||||
notificationMessage = error.code + ': ' + error.message.error;
|
||||
}
|
||||
} else if (error && error.message && isString(error.message)) {
|
||||
notificationMessage = error.message;
|
||||
} else if (error && error.message && 'code' in error.message) {
|
||||
notificationMessage = error.message.code + ' : ' + message;
|
||||
} else {
|
||||
notificationMessage = error.code;
|
||||
} else if ('info' in error) {
|
||||
notificationMessage = error.info;
|
||||
} else if ('message' in error) {
|
||||
if (error.code) {
|
||||
if (error.message.error) {
|
||||
notificationMessage = error.message.error.message;
|
||||
} else {
|
||||
notificationMessage = error.message;
|
||||
}
|
||||
} else if (error.message && isString(error.message)) {
|
||||
notificationMessage = error.message;
|
||||
} else if (error.message && 'code' in error.message) {
|
||||
notificationMessage = error.message.code + ' : ' + message;
|
||||
} else {
|
||||
notificationMessage = error.code;
|
||||
}
|
||||
} else if ('internal' in error && 'error' in error.internal) {
|
||||
notificationMessage = error.code + ' : ' + error.internal.error.message;
|
||||
} else if ('custom' in error) {
|
||||
notificationMessage = error.custom;
|
||||
} else if ('code' in error && 'error' in error && 'path' in error) {
|
||||
// Data API error
|
||||
notificationMessage = error.error;
|
||||
}
|
||||
} else if (error && 'internal' in error && 'error' in error.internal) {
|
||||
notificationMessage = error.code + ' : ' + error.internal.error.message;
|
||||
} else if (error && 'custom' in error) {
|
||||
notificationMessage = error.custom;
|
||||
} else if (
|
||||
error &&
|
||||
'code' in error &&
|
||||
'error' in error &&
|
||||
'path' in error
|
||||
) {
|
||||
// Data API error
|
||||
notificationMessage = error.error;
|
||||
} else {
|
||||
notificationMessage = error ? error : message;
|
||||
notificationMessage = message;
|
||||
}
|
||||
|
||||
return notificationMessage;
|
||||
@ -102,12 +101,14 @@ const showErrorNotification = (title, message, error) => {
|
||||
const getErrorJson = () => {
|
||||
let errorJson;
|
||||
|
||||
if (error && 'action' in error) {
|
||||
errorJson = error.action;
|
||||
} else if (error && 'internal' in error) {
|
||||
errorJson = error.internal;
|
||||
} else if (error && 'message' in error && !isString(error.message)) {
|
||||
errorJson = error.message;
|
||||
if (error && isObject(error)) {
|
||||
if ('action' in error) {
|
||||
errorJson = error.action;
|
||||
} else if ('internal' in error) {
|
||||
errorJson = error.internal;
|
||||
} else if ('message' in error && !isString(error.message)) {
|
||||
errorJson = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
return errorJson;
|
||||
|
@ -81,12 +81,14 @@ export const getPermissionColumnAccessSummary = (permission, tableFields) => {
|
||||
let allFields = true;
|
||||
|
||||
Object.keys(tableFields).forEach(fieldType => {
|
||||
noFields = noFields && !permission[fieldType].length;
|
||||
const permissionFields = permission[fieldType] || [];
|
||||
|
||||
noFields = noFields && !permissionFields.length;
|
||||
|
||||
allFields =
|
||||
allFields &&
|
||||
(permission[fieldType] === '*' ||
|
||||
permission[fieldType].length === tableFields[fieldType].length);
|
||||
(permissionFields === '*' ||
|
||||
permissionFields.length === tableFields[fieldType].length);
|
||||
});
|
||||
|
||||
if (noFields) {
|
||||
|
@ -50,7 +50,7 @@ import {
|
||||
PERM_OPEN_EDIT,
|
||||
PERM_SET_FILTER,
|
||||
PERM_SET_FILTER_SAME_AS,
|
||||
PERM_TOGGLE_COLUMN,
|
||||
PERM_TOGGLE_FIELD,
|
||||
PERM_TOGGLE_ALL_FIELDS,
|
||||
PERM_ALLOW_ALL,
|
||||
PERM_TOGGLE_MODIFY_LIMIT,
|
||||
@ -67,7 +67,7 @@ import {
|
||||
PERM_RESET_APPLY_SAME,
|
||||
PERM_SET_APPLY_SAME_PERM,
|
||||
PERM_DEL_APPLY_SAME_PERM,
|
||||
toggleColumn,
|
||||
toggleField,
|
||||
toggleAllFields,
|
||||
getFilterKey,
|
||||
getBasePermissionsState,
|
||||
@ -78,7 +78,6 @@ import {
|
||||
CREATE_NEW_PRESET,
|
||||
DELETE_PRESET,
|
||||
SET_PRESET_VALUE,
|
||||
PERM_TOGGLE_COMPUTED_FIELD,
|
||||
} from '../TablePermissions/Actions';
|
||||
|
||||
const modifyReducer = (tableName, schemas, modifyStateOrig, action) => {
|
||||
@ -389,33 +388,17 @@ const modifyReducer = (tableName, schemas, modifyStateOrig, action) => {
|
||||
|
||||
return returnState;
|
||||
|
||||
case PERM_TOGGLE_COLUMN:
|
||||
case PERM_TOGGLE_FIELD:
|
||||
return {
|
||||
...modifyState,
|
||||
permissionsState: {
|
||||
...updatePermissionsState(
|
||||
modifyState.permissionsState,
|
||||
'columns',
|
||||
toggleColumn(
|
||||
action.fieldType,
|
||||
toggleField(
|
||||
modifyState.permissionsState[modifyState.permissionsState.query],
|
||||
action.column,
|
||||
'columns'
|
||||
)
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
case PERM_TOGGLE_COMPUTED_FIELD:
|
||||
return {
|
||||
...modifyState,
|
||||
permissionsState: {
|
||||
...updatePermissionsState(
|
||||
modifyState.permissionsState,
|
||||
'computed_fields',
|
||||
toggleColumn(
|
||||
modifyState.permissionsState[modifyState.permissionsState.query],
|
||||
action.computedField,
|
||||
'computed_fields'
|
||||
action.fieldName,
|
||||
action.fieldType
|
||||
)
|
||||
),
|
||||
},
|
||||
|
@ -20,9 +20,7 @@ import {
|
||||
export const PERM_OPEN_EDIT = 'ModifyTable/PERM_OPEN_EDIT';
|
||||
export const PERM_SET_FILTER = 'ModifyTable/PERM_SET_FILTER';
|
||||
export const PERM_SET_FILTER_SAME_AS = 'ModifyTable/PERM_SET_FILTER_SAME_AS';
|
||||
export const PERM_TOGGLE_COLUMN = 'ModifyTable/PERM_TOGGLE_COLUMN';
|
||||
export const PERM_TOGGLE_COMPUTED_FIELD =
|
||||
'ModifyTable/PERM_TOGGLE_COMPUTED_FIELD';
|
||||
export const PERM_TOGGLE_FIELD = 'ModifyTable/PERM_TOGGLE_FIELD';
|
||||
export const PERM_TOGGLE_ALL_FIELDS = 'ModifyTable/PERM_TOGGLE_ALL_FIELDS';
|
||||
export const PERM_ALLOW_ALL = 'ModifyTable/PERM_ALLOW_ALL';
|
||||
export const PERM_TOGGLE_ENABLE_LIMIT = 'ModifyTable/PERM_TOGGLE_ENABLE_LIMIT';
|
||||
@ -70,10 +68,10 @@ const permSetFilterSameAs = filter => ({
|
||||
type: PERM_SET_FILTER_SAME_AS,
|
||||
filter,
|
||||
});
|
||||
const permToggleColumn = column => ({ type: PERM_TOGGLE_COLUMN, column });
|
||||
const permToggleComputedField = computedField => ({
|
||||
type: PERM_TOGGLE_COMPUTED_FIELD,
|
||||
computedField,
|
||||
const permToggleField = (fieldType, fieldName) => ({
|
||||
type: PERM_TOGGLE_FIELD,
|
||||
fieldType,
|
||||
fieldName,
|
||||
});
|
||||
const permToggleAllFields = allFields => ({
|
||||
type: PERM_TOGGLE_ALL_FIELDS,
|
||||
@ -250,20 +248,20 @@ const toggleAllFields = (permissions, allFields, fieldType) => {
|
||||
};
|
||||
|
||||
// fieldType: columns / computed_fields
|
||||
const toggleColumn = (permissions, column, fieldType) => {
|
||||
const currColumns = permissions ? permissions[fieldType] : [];
|
||||
let _newColumns = currColumns;
|
||||
const toggleField = (permissions, fieldName, fieldType) => {
|
||||
const currFields = permissions ? permissions[fieldType] : [];
|
||||
let _newFields = currFields;
|
||||
|
||||
const columnIndex = currColumns.indexOf(column);
|
||||
if (columnIndex === -1) {
|
||||
_newColumns.push(column);
|
||||
const fieldIndex = currFields.indexOf(fieldName);
|
||||
if (fieldIndex === -1) {
|
||||
_newFields.push(fieldName);
|
||||
} else {
|
||||
_newColumns.splice(columnIndex, 1);
|
||||
_newFields.splice(fieldIndex, 1);
|
||||
}
|
||||
|
||||
_newColumns = _newColumns.sort();
|
||||
_newFields = _newFields.sort();
|
||||
|
||||
return _newColumns;
|
||||
return _newFields;
|
||||
};
|
||||
|
||||
const permRemoveRole = (tableSchema, roleName) => {
|
||||
@ -778,8 +776,7 @@ export {
|
||||
permOpenEdit,
|
||||
permSetFilter,
|
||||
permSetFilterSameAs,
|
||||
permToggleColumn,
|
||||
permToggleComputedField,
|
||||
permToggleField,
|
||||
permToggleAllFields,
|
||||
permCloseEdit,
|
||||
permSetRoleName,
|
||||
@ -791,7 +788,7 @@ export {
|
||||
permCustomChecked,
|
||||
permRemoveRole,
|
||||
permSetBulkSelect,
|
||||
toggleColumn,
|
||||
toggleField,
|
||||
toggleAllFields,
|
||||
getFilterKey,
|
||||
getBasePermissionsState,
|
||||
|
@ -43,6 +43,7 @@ const operatorTypePGTypesMap = {
|
||||
json: ['json'],
|
||||
geometric: ['geometry'],
|
||||
geometric_geographic: ['geometry', 'geography'],
|
||||
is_null: Object.keys(PGTypes), // all types
|
||||
};
|
||||
|
||||
const boolOperatorsInfo = {
|
||||
@ -93,11 +94,6 @@ const columnOperatorsInfo = {
|
||||
type: 'comparision',
|
||||
inputStructure: 'object',
|
||||
},
|
||||
_is_null: {
|
||||
type: 'comparision',
|
||||
inputStructure: 'object',
|
||||
inputType: 'boolean',
|
||||
},
|
||||
_ceq: {
|
||||
type: 'comparision',
|
||||
inputStructure: 'object',
|
||||
@ -128,6 +124,11 @@ const columnOperatorsInfo = {
|
||||
inputStructure: 'object',
|
||||
inputType: 'column',
|
||||
},
|
||||
_is_null: {
|
||||
type: 'is_null',
|
||||
inputStructure: 'object',
|
||||
inputType: 'boolean',
|
||||
},
|
||||
_like: {
|
||||
type: 'pattern_match',
|
||||
inputStructure: 'object',
|
||||
|
@ -13,8 +13,7 @@ import {
|
||||
permOpenEdit,
|
||||
permSetFilter,
|
||||
permSetFilterSameAs,
|
||||
permToggleColumn,
|
||||
permToggleComputedField,
|
||||
permToggleField,
|
||||
permToggleAllFields,
|
||||
permAllowAll,
|
||||
permCloseEdit,
|
||||
@ -886,87 +885,56 @@ class Permissions extends Component {
|
||||
const getColumnList = () => {
|
||||
const _columnList = [];
|
||||
|
||||
const dispatchToggleColumn = e => {
|
||||
const column = e.target.value;
|
||||
dispatch(permToggleColumn(column));
|
||||
const dispatchToggleField = fieldType => e => {
|
||||
const fieldName = e.target.value;
|
||||
dispatch(permToggleField(fieldType, fieldName));
|
||||
};
|
||||
|
||||
const dispatchToggleComputedField = e => {
|
||||
const computedField = e.target.value;
|
||||
dispatch(permToggleComputedField(computedField));
|
||||
};
|
||||
|
||||
tableSchema.columns.forEach((colObj, i) => {
|
||||
const column = colObj.column_name;
|
||||
|
||||
let checked;
|
||||
const getFieldCheckbox = (fieldType, fieldName) => {
|
||||
let checked = false;
|
||||
if (permissionsState[query]) {
|
||||
if (permissionsState[query].columns === '*') {
|
||||
const permittedFields = permissionsState[query][fieldType] || [];
|
||||
|
||||
if (permittedFields === '*') {
|
||||
checked = true;
|
||||
} else {
|
||||
checked = permissionsState[query].columns.includes(column);
|
||||
checked = permittedFields.includes(fieldName);
|
||||
}
|
||||
} else {
|
||||
checked = false;
|
||||
}
|
||||
|
||||
_columnList.push(
|
||||
<div key={'column_' + i} className={styles.columnListElement}>
|
||||
return (
|
||||
<div key={fieldName} className={styles.columnListElement}>
|
||||
<div className="checkbox">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
value={column}
|
||||
onChange={dispatchToggleColumn}
|
||||
value={fieldName}
|
||||
onChange={dispatchToggleField(fieldType)}
|
||||
disabled={noPermissions}
|
||||
title={noPermissions ? noPermissionsMsg : ''}
|
||||
/>
|
||||
{column}
|
||||
{fieldType === 'columns' ? fieldName : <i>{fieldName}</i>}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
tableSchema.columns.forEach(colObj => {
|
||||
const columnName = colObj.column_name;
|
||||
|
||||
_columnList.push(getFieldCheckbox('columns', columnName));
|
||||
});
|
||||
|
||||
if (query === 'select') {
|
||||
groupedComputedFields.scalar.forEach((scalarComputedField, i) => {
|
||||
groupedComputedFields.scalar.forEach(scalarComputedField => {
|
||||
const computedFieldName = getComputedFieldName(
|
||||
scalarComputedField
|
||||
);
|
||||
|
||||
let checked;
|
||||
if (permissionsState[query]) {
|
||||
if (permissionsState[query].computed_fields === '*') {
|
||||
checked = true;
|
||||
} else {
|
||||
checked = permissionsState[query].computed_fields.includes(
|
||||
computedFieldName
|
||||
);
|
||||
}
|
||||
} else {
|
||||
checked = false;
|
||||
}
|
||||
|
||||
_columnList.push(
|
||||
<div
|
||||
key={'computed_field_' + i}
|
||||
className={styles.columnListElement}
|
||||
>
|
||||
<div className="checkbox">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
value={computedFieldName}
|
||||
onChange={dispatchToggleComputedField}
|
||||
disabled={noPermissions}
|
||||
title={noPermissions ? noPermissionsMsg : ''}
|
||||
/>
|
||||
<i>{computedFieldName}</i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
getFieldCheckbox('computed_fields', computedFieldName)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user