diff --git a/console/src/components/Services/Data/Metadata/Metadata.js b/console/src/components/Services/Data/Metadata/Metadata.js index bc57d1b51534f..09f1a3351a5d0 100644 --- a/console/src/components/Services/Data/Metadata/Metadata.js +++ b/console/src/components/Services/Data/Metadata/Metadata.js @@ -89,48 +89,48 @@ class Metadata extends Component { {this.state.showMetadata ? [ -
-

Reload metadata

-
+
+

Reload metadata

+
Refresh Hasura metadata, typically required if you have changed the underlying postgres. -
-
, -
- -
, -
-

Reset Metadata

-
+
+
, +
+ +
, +
+

Reset Metadata

+
Permanently clear GraphQL Engine's metadata and configure it from scratch (tracking relevant tables and relationships). This process is not reversible. -
-
, -
- -
, - ] +
+
, +
+ +
, + ] : null} {window.localStorage.CONSOLE_ACCESS_KEY ? [ -
-

Clear access key (logout)

-
+
+

Clear access key (logout)

+
The console caches the access key (HASURA_GRAPHQL_ACCESS_KEY) in the browser. You can clear this cache to force a prompt for the access key when the console is accessed next using this browser. -
-
, -
- -
, - ] +
+
, +
+ +
, + ] : null} ); diff --git a/console/src/components/Services/Data/RawSQL/Actions.js b/console/src/components/Services/Data/RawSQL/Actions.js index 7bcb5853fd3db..d92fcc449902e 100644 --- a/console/src/components/Services/Data/RawSQL/Actions.js +++ b/console/src/components/Services/Data/RawSQL/Actions.js @@ -49,7 +49,7 @@ const executeSQL = (isMigration, migrationName) => (dispatch, getState) => { const regExp = /create (view|table) ((\"?\w+\"?)\.(\"?\w+\"?)|(\"?\w+\"?))/; // eslint-disable-line const matches = sql.match(new RegExp(regExp, 'gmi')); if (matches) { - matches.forEach((element) => { + matches.forEach(element => { const itemMatch = element.match(new RegExp(regExp, 'i')); if (itemMatch && itemMatch.length === 6) { const trackQuery = { @@ -66,8 +66,12 @@ const executeSQL = (isMigration, migrationName) => (dispatch, getState) => { trackQuery.args.schema = itemMatch[3]; } // replace and trim schema and table name - trackQuery.args.name = trackQuery.args.name.replace(/['"]+/g, '').trim(); - trackQuery.args.schema = trackQuery.args.schema.replace(/['"]+/g, '').trim(); + trackQuery.args.name = trackQuery.args.name + .replace(/['"]+/g, '') + .trim(); + trackQuery.args.schema = trackQuery.args.schema + .replace(/['"]+/g, '') + .trim(); schemaChangesUp.push(trackQuery); } }); diff --git a/console/src/components/Services/Data/TablePermissions/Permissions.js b/console/src/components/Services/Data/TablePermissions/Permissions.js index e1561759112d5..e304a515693d5 100644 --- a/console/src/components/Services/Data/TablePermissions/Permissions.js +++ b/console/src/components/Services/Data/TablePermissions/Permissions.js @@ -253,21 +253,21 @@ class Permissions extends Component { const bulkSelect = permsState.bulkSelect; const currentInputSelection = bulkSelect.filter(e => e === role) .length ? ( - - ) : ( - - ); + + ) : ( + + ); _permissionsRowHtml.push(
diff --git a/console/src/components/Services/EventTrigger/Add/AddActions.js b/console/src/components/Services/EventTrigger/Add/AddActions.js index 452894fe9bd1a..e696531deb8b4 100644 --- a/console/src/components/Services/EventTrigger/Add/AddActions.js +++ b/console/src/components/Services/EventTrigger/Add/AddActions.js @@ -27,6 +27,11 @@ const UPDATE_TABLE_LIST = 'AddTrigger/UPDATE_TABLE_LIST'; const TOGGLE_COLUMNS = 'AddTrigger/TOGGLE_COLUMNS'; const TOGGLE_QUERY_TYPE_SELECTED = 'AddTrigger/TOGGLE_QUERY_TYPE_SELECTED'; const TOGGLE_QUERY_TYPE_DESELECTED = 'AddTrigger/TOGGLE_QUERY_TYPE_DESELECTED'; +const REMOVE_HEADER = 'AddTrigger/REMOVE_HEADER'; +const SET_HEADERKEY = 'AddTrigger/SET_HEADERKEY'; +const SET_HEADERTYPE = 'AddTrigger/SET_HEADERTYPE'; +const SET_HEADERVALUE = 'AddTrigger/SET_HEADERVALUE'; +const ADD_HEADER = 'AddTrigger/ADD_HEADER'; const setTriggerName = value => ({ type: SET_TRIGGERNAME, value }); const setTableName = value => ({ type: SET_TABLENAME, value }); @@ -35,6 +40,24 @@ const setWebhookURL = value => ({ type: SET_WEBHOOK_URL, value }); const setRetryNum = value => ({ type: SET_RETRY_NUM, value }); const setRetryInterval = value => ({ type: SET_RETRY_INTERVAL, value }); const setDefaults = () => ({ type: SET_DEFAULTS }); +const addHeader = () => ({ type: ADD_HEADER }); +const removeHeader = i => ({ type: REMOVE_HEADER, index: i }); +const setHeaderKey = (key, index) => ({ + type: SET_HEADERKEY, + key, + index, +}); +const setHeaderType = (headerType, index) => ({ + type: SET_HEADERTYPE, + headerType, + index, +}); +const setHeaderValue = (headerValue, index) => ({ + type: SET_HEADERVALUE, + headerValue, + index, +}); + // General error during validation. // const validationError = (error) => ({type: VALIDATION_ERROR, error: error}); const validationError = error => { @@ -82,6 +105,19 @@ const createTrigger = () => { if (currentState.retryConf) { payload.args.retry_conf = currentState.retryConf; } + + // create header payload + const headers = []; + currentState.headers.map(header => { + if (header.key !== '' && header.type !== '') { + if (header.type === 'static') { + headers.push({ name: header.key, value: header.value }); + } else if (header.type === 'env') { + headers.push({ name: header.key, value_from_env: header.value }); + } + } + }); + payload.args.headers = headers; const upQueryArgs = []; upQueryArgs.push(payload); const downQueryArgs = []; @@ -196,6 +232,49 @@ const setOperationSelection = (type, isChecked) => { const addTriggerReducer = (state = defaultState, action) => { switch (action.type) { + case ADD_HEADER: + return { + ...state, + headers: [...state.headers, { key: '', type: '', value: '' }], + }; + case REMOVE_HEADER: + return { + ...state, + headers: [ + ...state.headers.slice(0, action.index), + ...state.headers.slice(action.index + 1), + ], + }; + case SET_HEADERKEY: + const i = action.index; + return { + ...state, + headers: [ + ...state.headers.slice(0, i), + { ...state.headers[i], key: action.key }, + ...state.headers.slice(i + 1), + ], + }; + case SET_HEADERTYPE: + const ij = action.index; + return { + ...state, + headers: [ + ...state.headers.slice(0, ij), + { ...state.headers[ij], type: action.headerType }, + ...state.headers.slice(ij + 1), + ], + }; + case SET_HEADERVALUE: + const ik = action.index; + return { + ...state, + headers: [ + ...state.headers.slice(0, ik), + { ...state.headers[ik], value: action.headerValue }, + ...state.headers.slice(ik + 1), + ], + }; case SET_DEFAULTS: return { ...defaultState, @@ -280,6 +359,11 @@ const addTriggerReducer = (state = defaultState, action) => { export default addTriggerReducer; export { + addHeader, + setHeaderKey, + setHeaderValue, + setHeaderType, + removeHeader, setTriggerName, setTableName, setSchemaName, diff --git a/console/src/components/Services/EventTrigger/Add/AddState.js b/console/src/components/Services/EventTrigger/Add/AddState.js index a698c35a83082..e3f692ba5ed31 100644 --- a/console/src/components/Services/EventTrigger/Add/AddState.js +++ b/console/src/components/Services/EventTrigger/Add/AddState.js @@ -11,6 +11,7 @@ const defaultState = { lastError: null, internalError: null, lastSuccess: null, + headers: [{ key: '', type: '', value: '' }], }; export default defaultState; diff --git a/console/src/components/Services/EventTrigger/Add/AddTrigger.js b/console/src/components/Services/EventTrigger/Add/AddTrigger.js index 75dc32cb7e3a0..ee5af1a146e6b 100644 --- a/console/src/components/Services/EventTrigger/Add/AddTrigger.js +++ b/console/src/components/Services/EventTrigger/Add/AddTrigger.js @@ -5,6 +5,11 @@ import * as tooltip from './Tooltips'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import { + removeHeader, + setHeaderKey, + setHeaderValue, + setHeaderType, + addHeader, setTriggerName, setTableName, setSchemaName, @@ -16,6 +21,7 @@ import { setOperationSelection, setDefaults, } from './AddActions'; +import { listDuplicate } from '../../../../utils/data'; import { showErrorNotification } from '../Notification'; import { createTrigger } from './AddActions'; import { fetchTableListBySchema } from './AddActions'; @@ -80,6 +86,27 @@ class AddTrigger extends Component { customMsg = 'Please select a minimum of one column for update operation'; } + } else if (this.props.headers.length === 1) { + if (this.props.headers[0].key !== '') { + // let the default value through and ignore it while querying? + // Need a better method + if (this.props.headers[0].type === '') { + isValid = false; + errorMsg = 'No type selected for trigger header'; + customMsg = 'Please select a type for the trigger header'; + } + } + } else if (this.props.headers.length > 1) { + // repitition check + const repeatList = listDuplicate( + this.props.headers.map(header => header.key) + ); + if (repeatList.length > 0) { + isValid = false; + errorMsg = 'Duplicate entries in trigger headers'; + customMsg = `You have the following column names repeated: [${repeatList}]`; + } + // Check for empty header keys and key/value validation? } if (isValid) { this.props.dispatch(createTrigger()); @@ -107,6 +134,7 @@ class AddTrigger extends Component { lastError, lastSuccess, internalError, + headers, } = this.props; const styles = require('../TableCommon/Table.scss'); let createBtnText = 'Create'; @@ -188,6 +216,72 @@ class AddTrigger extends Component { return null; }; + const heads = headers.map((header, i) => { + let removeIcon; + if (i + 1 === headers.length) { + removeIcon = ; + } else { + removeIcon = ( + { + dispatch(removeHeader(i)); + }} + /> + ); + } + return ( +
+ { + dispatch(setHeaderKey(e.target.value, i)); + }} + data-test={`header-${i}`} + /> + {' '} + { + dispatch(setHeaderValue(e.target.value, i)); + }} + data-test={`header-value-${i}`} + />{' '} + {removeIcon} +
+ ); + }); + return (
+
+

Headers

+ {heads} +
) : null}
diff --git a/console/src/components/Services/EventTrigger/Settings/Settings.js b/console/src/components/Services/EventTrigger/Settings/Settings.js index 5d33492ba2e78..20ec339d9cda6 100644 --- a/console/src/components/Services/EventTrigger/Settings/Settings.js +++ b/console/src/components/Services/EventTrigger/Settings/Settings.js @@ -70,6 +70,25 @@ class Settings extends Component { {triggerSchema.retry_interval > 1 ? 'seconds' : 'second'} + {'headers' in triggerSchema ? ( + + Headers + + + + + ) : null} Operation / Columns @@ -83,6 +102,7 @@ class Settings extends Component { width="100%" showPrintMargin={false} showGutter={false} + readOnly />