mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 09:22:43 +03:00
This commit is contained in:
parent
32f1d47baa
commit
8a9901d417
@ -8,8 +8,8 @@ export const dataTypes = [
|
||||
'text',
|
||||
'numeric',
|
||||
'date',
|
||||
'timestamp with time zone',
|
||||
'time with time zone',
|
||||
'timestamptz',
|
||||
'timetz',
|
||||
'boolean',
|
||||
];
|
||||
export const typeDefaults = {
|
||||
@ -19,8 +19,8 @@ export const typeDefaults = {
|
||||
text: 'test-text',
|
||||
numeric: '0.55555',
|
||||
date: 'now()',
|
||||
'timestamp with time zone': 'now()',
|
||||
'time with time zone': 'now()',
|
||||
timestamptz: 'now()',
|
||||
timetz: 'now()',
|
||||
boolean: 'false',
|
||||
};
|
||||
export const queryTypes = ['insert', 'select', 'update', 'delete'];
|
||||
@ -28,6 +28,14 @@ export const getColName = i => `apic_test_column_${i}`;
|
||||
export const getTableName = (i, testName = '') =>
|
||||
`apic_test_table_${testName}_${i}`;
|
||||
export const getElementFromAlias = alias => `[data-test=${alias}]`;
|
||||
export const getElementFromClassName = cn => `.${cn}`;
|
||||
export const tableColumnTypeSelector = alias => {
|
||||
cy.get(`${getElementFromAlias(alias)}`)
|
||||
.children('div')
|
||||
.click()
|
||||
.find('input')
|
||||
.focus();
|
||||
};
|
||||
export const makeDataAPIUrl = dataApiUrl => `${dataApiUrl}/v1/query`;
|
||||
export const makeDataAPIOptions = (dataApiUrl, key, body) => ({
|
||||
method: 'POST',
|
||||
|
@ -1,6 +1,10 @@
|
||||
/* eslint import/prefer-default-export: 0 */
|
||||
|
||||
import { getElementFromAlias, baseUrl } from '../../../helpers/dataHelpers';
|
||||
import {
|
||||
getElementFromAlias,
|
||||
baseUrl,
|
||||
tableColumnTypeSelector,
|
||||
} from '../../../helpers/dataHelpers';
|
||||
import { validateCT } from '../../validators/validators';
|
||||
import { makeDataAPIOptions } from '../../../helpers/dataHelpers';
|
||||
import { toggleOnMigrationMode } from '../../data/migration-mode/utils';
|
||||
@ -29,11 +33,21 @@ export const createTestTable = () => {
|
||||
cy.get(getElementFromAlias('column-0'))
|
||||
.clear()
|
||||
.type('id');
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
// cy.get(getElementFromAlias('col-type-0')).click();
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
cy.get(getElementFromAlias('column-1'))
|
||||
.clear()
|
||||
.type('name');
|
||||
cy.get(getElementFromAlias('col-type-1')).select('text');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// cy.get(getElementFromAlias('col-type-1')).select('text');
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Click on create
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
tableColumnTypeSelector,
|
||||
getElementFromAlias,
|
||||
getTableName,
|
||||
getColName,
|
||||
@ -34,7 +35,10 @@ export const failCTWithoutColumns = () => {
|
||||
export const failCTWithoutPK = () => {
|
||||
// Set first column
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// Click on create
|
||||
cy.get(getElementFromAlias('table-create')).click();
|
||||
// Check for an error
|
||||
@ -48,7 +52,10 @@ export const failCTWithoutPK = () => {
|
||||
export const failCTDuplicateColumns = () => {
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('serial');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Click on create
|
||||
@ -65,12 +72,41 @@ export const failCTDuplicateColumns = () => {
|
||||
validateCT(getTableName(0, testName), 'failure');
|
||||
};
|
||||
|
||||
export const failCTDuplicatePrimaryKey = () => {
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1'))
|
||||
.clear()
|
||||
.type(getColName(1));
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
cy.get(getElementFromAlias('primary-key-select-1')).select('0');
|
||||
cy.on('window:alert', str => {
|
||||
expect(
|
||||
str ===
|
||||
`You key [${getColName(
|
||||
0
|
||||
)}] is already present in the current set of primary keys.`
|
||||
).to.be.true;
|
||||
});
|
||||
// Check if the route didn't change
|
||||
cy.url().should('eq', `${baseUrl}/data/schema/public/table/add`);
|
||||
// Validate
|
||||
validateCT(getTableName(0, testName), 'failure');
|
||||
};
|
||||
|
||||
export const failCTWrongDefaultValue = () => {
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1'))
|
||||
.clear()
|
||||
.type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
cy.get(getElementFromAlias('col-default-1')).type('qwerty');
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
@ -87,7 +123,10 @@ export const passCT = () => {
|
||||
cy.get(getElementFromAlias('column-1'))
|
||||
.clear()
|
||||
.type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('text');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
cy.get(getElementFromAlias('col-default-1')).clear();
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
@ -114,13 +153,22 @@ export const passCTWithFK = () => {
|
||||
.type(getTableName(1, testName));
|
||||
// Set first column
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1')).type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('text');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
// Set third column
|
||||
cy.get(getElementFromAlias('column-2')).type(getColName(2));
|
||||
cy.get(getElementFromAlias('col-type-2')).select('text');
|
||||
tableColumnTypeSelector('col-type-2');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
@ -170,7 +218,10 @@ export const failCTDuplicateTable = () => {
|
||||
cy.get(getElementFromAlias('tableName')).type(getTableName(0, testName));
|
||||
// Set column
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Click on create
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
dataTypes,
|
||||
getElementFromAlias,
|
||||
typeDefaults,
|
||||
tableColumnTypeSelector,
|
||||
} from '../../../helpers/dataHelpers';
|
||||
|
||||
import {
|
||||
@ -24,7 +25,12 @@ const setColumns = () => {
|
||||
// Type column name
|
||||
cy.get(getElementFromAlias(`column-${i}`)).type(getColName(i));
|
||||
// Select column type
|
||||
cy.get(getElementFromAlias(`col-type-${i}`)).select(dataTypes[i]);
|
||||
tableColumnTypeSelector(`col-type-${i}`);
|
||||
// cy.get(getElementFromAlias(`col-type-${i}`)).click();
|
||||
cy.get(getElementFromAlias(`data_test_column_type_value_${dataTypes[i]}`))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias(`col-type-${i}`)).select(dataTypes[i]);
|
||||
|
||||
if (i === dataTypes.indexOf('text')) {
|
||||
cy.get(getElementFromAlias(`unique-${i}`)).check();
|
||||
@ -109,7 +115,11 @@ export const passSearchTables = () => {
|
||||
// Type column name
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(0));
|
||||
// Select column type
|
||||
cy.get(getElementFromAlias('col-type-0')).select('integer');
|
||||
// cy.get(getElementFromAlias('col-type-0')).select('integer');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Click on create
|
||||
@ -425,9 +435,18 @@ export const checkViewRelationship = () => {
|
||||
// Type table name
|
||||
cy.get(getElementFromAlias('tableName')).type(getTableName(2, testName));
|
||||
cy.get(getElementFromAlias('column-0')).type('id');
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
// cy.get(getElementFromAlias('col-type-0')).click();
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
cy.get(getElementFromAlias('column-1')).type('someID');
|
||||
cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
// cy.get(getElementFromAlias('col-type-1')).click();
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Click on create
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
tableColumnTypeSelector,
|
||||
baseUrl,
|
||||
getTableName,
|
||||
getColName,
|
||||
@ -18,7 +19,11 @@ export const passMTCreateTable = () => {
|
||||
cy.url().should('eq', `${baseUrl}/data/schema/public/table/add`);
|
||||
cy.get(getElementFromAlias('tableName')).type(getTableName(0, testName));
|
||||
cy.get(getElementFromAlias('column-0')).type('id');
|
||||
cy.get(getElementFromAlias('col-type-0')).select('Integer');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-0')).select('Integer');
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('id');
|
||||
cy.get(getElementFromAlias('table-create')).click();
|
||||
cy.wait(7000);
|
||||
@ -106,7 +111,11 @@ export const failMTWithoutColType = () => {
|
||||
export const Addcolumnnullable = () => {
|
||||
cy.get(getElementFromAlias('column-name')).type('{selectall}{del}');
|
||||
cy.get(getElementFromAlias('column-name')).type(getColName(3));
|
||||
cy.get(getElementFromAlias('data-type')).select('Text');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('data-type')).select('Text');
|
||||
cy.get(getElementFromAlias('nullable-checkbox')).uncheck({ force: true });
|
||||
cy.get(getElementFromAlias('add-column-button')).click();
|
||||
cy.wait(2500);
|
||||
@ -121,7 +130,12 @@ export const Addcolumnnullable = () => {
|
||||
export const Addcolumnname = name => {
|
||||
cy.get(getElementFromAlias('column-name')).type('{selectall}{del}');
|
||||
cy.get(getElementFromAlias('column-name')).type(name);
|
||||
cy.get(getElementFromAlias('data-type')).select('integer');
|
||||
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('data-type')).select('integer');
|
||||
|
||||
cy.get(getElementFromAlias('add-column-button')).click();
|
||||
cy.wait(5000);
|
||||
@ -131,7 +145,11 @@ export const Addcolumnname = name => {
|
||||
export const passMTAddColumn = () => {
|
||||
cy.get(getElementFromAlias('column-name')).type('{selectall}{del}');
|
||||
cy.get(getElementFromAlias('column-name')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('data-type')).select('integer');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('data-type')).select('integer');
|
||||
cy.get(getElementFromAlias('add-column-button')).click();
|
||||
cy.wait(5000);
|
||||
// cy.get('.notification-success').click();
|
||||
@ -287,14 +305,14 @@ export const Createtable = (name, dict) => {
|
||||
|
||||
export const Createtables = () => {
|
||||
cy.get(getElementFromAlias('data-create-table')).click();
|
||||
Createtable('author', { id: 'Integer', name: 'Text' });
|
||||
Createtable('author', { id: 'integer', name: 'Text' });
|
||||
cy.get(getElementFromAlias('sidebar-add-table')).click();
|
||||
Createtable('article', {
|
||||
id: 'Integer',
|
||||
title: 'Text',
|
||||
Content: 'Text',
|
||||
author_id: 'Integer',
|
||||
rating: 'Integer',
|
||||
id: 'integer',
|
||||
title: 'text',
|
||||
Content: 'text',
|
||||
author_id: 'integer',
|
||||
rating: 'integer',
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
tableColumnTypeSelector,
|
||||
baseUrl,
|
||||
getTableName,
|
||||
getElementFromAlias,
|
||||
@ -21,13 +22,26 @@ export const passPTCreateTable = () => {
|
||||
cy.get(getElementFromAlias('tableName')).type(getTableName(0, testName));
|
||||
// Set first column
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1')).type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
// Set third column
|
||||
cy.get(getElementFromAlias('column-2')).type(getColName(2));
|
||||
cy.get(getElementFromAlias('col-type-2')).select('text');
|
||||
tableColumnTypeSelector('col-type-2');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-2')).select('text');
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Create
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { baseUrl, getElementFromAlias } from '../../../helpers/dataHelpers';
|
||||
import {
|
||||
baseUrl,
|
||||
getElementFromAlias,
|
||||
tableColumnTypeSelector,
|
||||
} from '../../../helpers/dataHelpers';
|
||||
|
||||
import {
|
||||
setMetaData,
|
||||
@ -28,7 +32,11 @@ export const Createtable = (name, fields) => {
|
||||
for (const key in fields) {
|
||||
if (fields.hasOwnProperty(key)) {
|
||||
cy.get(getElementFromAlias(`column-${i}`)).type(key);
|
||||
cy.get(getElementFromAlias(`col-type-${i}`)).select(fields[key]);
|
||||
tableColumnTypeSelector(`col-type-${i}`);
|
||||
cy.get(getElementFromAlias(`data_test_column_type_value_${fields[key]}`))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias(`col-type-${i}`)).select(fields[key]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -75,19 +83,19 @@ export const Createtable = (name, fields) => {
|
||||
};
|
||||
|
||||
export const passRTCreateTables = () => {
|
||||
Createtable('author', { id: 'Integer', name: 'Text' });
|
||||
Createtable('author', { id: 'integer', name: 'text' });
|
||||
Createtable('article', {
|
||||
id: 'Integer',
|
||||
title: 'Text',
|
||||
Content: 'Text',
|
||||
author_id: 'Integer',
|
||||
rating: 'Integer',
|
||||
id: 'integer',
|
||||
title: 'text',
|
||||
Content: 'text',
|
||||
author_id: 'integer',
|
||||
rating: 'integer',
|
||||
});
|
||||
Createtable('comment', {
|
||||
id: 'Integer',
|
||||
user_id: 'Integer',
|
||||
article_id: 'Integer',
|
||||
comment: 'Text',
|
||||
id: 'integer',
|
||||
user_id: 'integer',
|
||||
article_id: 'integer',
|
||||
comment: 'text',
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { getElementFromAlias, baseUrl } from '../../../helpers/dataHelpers';
|
||||
import {
|
||||
getElementFromAlias,
|
||||
baseUrl,
|
||||
tableColumnTypeSelector,
|
||||
} from '../../../helpers/dataHelpers';
|
||||
|
||||
import {
|
||||
setMetaData,
|
||||
@ -17,7 +21,10 @@ export const Createtable = (name, dict) => {
|
||||
const values = Object.keys(dict).map(k => dict[k]);
|
||||
for (let i = 0; i < keys.length; i += 1) {
|
||||
cy.get(getElementFromAlias(`column-${i}`)).type(keys[i]);
|
||||
cy.get(getElementFromAlias(`col-type-${i}`)).select(values[i]);
|
||||
tableColumnTypeSelector(`col-type-${i}`);
|
||||
cy.get(getElementFromAlias(`data_test_column_type_value_${values[i]}`))
|
||||
.first()
|
||||
.click();
|
||||
}
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('id');
|
||||
cy.get(getElementFromAlias('table-create')).click();
|
||||
@ -32,21 +39,21 @@ export const Createtable = (name, dict) => {
|
||||
|
||||
export const passVCreateTables = () => {
|
||||
cy.get(getElementFromAlias('data-create-table')).click();
|
||||
Createtable('author', { id: 'Integer', name: 'Text' });
|
||||
Createtable('author', { id: 'integer', name: 'text' });
|
||||
cy.get(getElementFromAlias('sidebar-add-table')).click();
|
||||
Createtable('article', {
|
||||
id: 'Integer',
|
||||
title: 'Text',
|
||||
Content: 'Text',
|
||||
author_id: 'Integer',
|
||||
rating: 'Integer',
|
||||
id: 'integer',
|
||||
title: 'text',
|
||||
Content: 'text',
|
||||
author_id: 'integer',
|
||||
rating: 'integer',
|
||||
});
|
||||
cy.get(getElementFromAlias('sidebar-add-table')).click();
|
||||
Createtable('comment', {
|
||||
id: 'Integer',
|
||||
user_id: 'Integer',
|
||||
article_id: 'Integer',
|
||||
comment: 'Text',
|
||||
id: 'integer',
|
||||
user_id: 'integer',
|
||||
article_id: 'integer',
|
||||
comment: 'text',
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,10 @@ import {
|
||||
getTimeoutSeconds,
|
||||
baseUrl,
|
||||
} from '../../../helpers/eventHelpers';
|
||||
import { getColName } from '../../../helpers/dataHelpers';
|
||||
import {
|
||||
getColName,
|
||||
tableColumnTypeSelector,
|
||||
} from '../../../helpers/dataHelpers';
|
||||
import {
|
||||
setMetaData,
|
||||
validateCT,
|
||||
@ -31,13 +34,26 @@ export const passPTCreateTable = () => {
|
||||
cy.get(getElementFromAlias('tableName')).type(getTableName(0, testName));
|
||||
// Set first column
|
||||
cy.get(getElementFromAlias('column-0')).type(getColName(0));
|
||||
cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
tableColumnTypeSelector('col-type-0');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_serial'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-0')).select('serial');
|
||||
// Set second column
|
||||
cy.get(getElementFromAlias('column-1')).type(getColName(1));
|
||||
cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
tableColumnTypeSelector('col-type-1');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_integer'))
|
||||
.first()
|
||||
.click();
|
||||
|
||||
// cy.get(getElementFromAlias('col-type-1')).select('integer');
|
||||
// Set third column
|
||||
cy.get(getElementFromAlias('column-2')).type(getColName(2));
|
||||
cy.get(getElementFromAlias('col-type-2')).select('text');
|
||||
tableColumnTypeSelector('col-type-2');
|
||||
cy.get(getElementFromAlias('data_test_column_type_value_text'))
|
||||
.first()
|
||||
.click();
|
||||
// cy.get(getElementFromAlias('col-type-2')).select('text');
|
||||
// Set primary key
|
||||
cy.get(getElementFromAlias('primary-key-select-0')).select('0');
|
||||
// Create
|
||||
|
309
console/package-lock.json
generated
309
console/package-lock.json
generated
@ -370,7 +370,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz",
|
||||
"integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.0.0"
|
||||
}
|
||||
@ -1559,7 +1558,6 @@
|
||||
"version": "7.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz",
|
||||
"integrity": "sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esutils": "^2.0.2",
|
||||
"lodash": "^4.17.11",
|
||||
@ -1569,8 +1567,7 @@
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1613,6 +1610,62 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/babel-utils": {
|
||||
"version": "0.6.10",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.10.tgz",
|
||||
"integrity": "sha512-/fnkM/LTEp3jKe++T0KyTszVGWNKPNOUJfjNKLO17BzQ6QPxgbg3whayom1Qr2oLFH3V92tDymU+dT5q676uow==",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.6",
|
||||
"@emotion/memoize": "^0.6.6",
|
||||
"@emotion/serialize": "^0.9.1",
|
||||
"convert-source-map": "^1.5.1",
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/hash": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.6.tgz",
|
||||
"integrity": "sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ=="
|
||||
},
|
||||
"@emotion/memoize": {
|
||||
"version": "0.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz",
|
||||
"integrity": "sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ=="
|
||||
},
|
||||
"@emotion/serialize": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.9.1.tgz",
|
||||
"integrity": "sha512-zTuAFtyPvCctHBEL8KZ5lJuwBanGSutFEncqLn/m9T1a6a93smBStK+bZzcNPgj4QS8Rkw9VTwJGhRIUVO8zsQ==",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.6",
|
||||
"@emotion/memoize": "^0.6.6",
|
||||
"@emotion/unitless": "^0.6.7",
|
||||
"@emotion/utils": "^0.8.2"
|
||||
}
|
||||
},
|
||||
"@emotion/stylis": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.7.1.tgz",
|
||||
"integrity": "sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ=="
|
||||
},
|
||||
"@emotion/unitless": {
|
||||
"version": "0.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.7.tgz",
|
||||
"integrity": "sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg=="
|
||||
},
|
||||
"@emotion/utils": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
|
||||
"integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw=="
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.7.8",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz",
|
||||
@ -1800,8 +1853,7 @@
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.5",
|
||||
@ -2409,6 +2461,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-emotion": {
|
||||
"version": "9.2.11",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz",
|
||||
"integrity": "sha512-dgCImifnOPPSeXod2znAmgc64NhaaOjGEHROR/M+lmStb3841yK1sgaDYAYMnlvWNz8GnpwIPN0VmNpbWYZ+VQ==",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.0.0",
|
||||
"@emotion/babel-utils": "^0.6.4",
|
||||
"@emotion/hash": "^0.6.2",
|
||||
"@emotion/memoize": "^0.6.1",
|
||||
"@emotion/stylis": "^0.7.0",
|
||||
"babel-plugin-macros": "^2.0.0",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"convert-source-map": "^1.5.0",
|
||||
"find-root": "^1.1.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"source-map": "^0.5.7",
|
||||
"touch": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-istanbul": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz",
|
||||
@ -2465,6 +2543,73 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-macros": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz",
|
||||
"integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.2",
|
||||
"cosmiconfig": "^5.2.0",
|
||||
"resolve": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.4.tgz",
|
||||
"integrity": "sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.2"
|
||||
}
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
|
||||
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
|
||||
"requires": {
|
||||
"import-fresh": "^2.0.0",
|
||||
"is-directory": "^0.3.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"parse-json": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
|
||||
"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-syntax-jsx": {
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
|
||||
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
|
||||
},
|
||||
"babel-plugin-transform-react-remove-prop-types": {
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.18.tgz",
|
||||
@ -2949,6 +3094,21 @@
|
||||
"os-homedir": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"caller-callsite": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
|
||||
"integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
|
||||
"requires": {
|
||||
"callsites": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"callsites": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
|
||||
"integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
|
||||
}
|
||||
}
|
||||
},
|
||||
"caller-path": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
|
||||
@ -3604,7 +3764,6 @@
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
|
||||
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
@ -3698,6 +3857,20 @@
|
||||
"elliptic": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"create-emotion": {
|
||||
"version": "9.2.12",
|
||||
"resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.12.tgz",
|
||||
"integrity": "sha512-P57uOF9NL2y98Xrbl2OuiDQUZ30GVmASsv5fbsjF4Hlraip2kyAvMm+2PoYUvFFw03Fhgtxk3RqZSm2/qHL9hA==",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.2",
|
||||
"@emotion/memoize": "^0.6.1",
|
||||
"@emotion/stylis": "^0.7.0",
|
||||
"@emotion/unitless": "^0.6.2",
|
||||
"csstype": "^2.5.2",
|
||||
"stylis": "^3.5.0",
|
||||
"stylis-rule-sheet": "^0.0.10"
|
||||
}
|
||||
},
|
||||
"create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
@ -3926,6 +4099,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz",
|
||||
"integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg=="
|
||||
},
|
||||
"currently-unhandled": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
|
||||
@ -4405,6 +4583,15 @@
|
||||
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
|
||||
"dev": true
|
||||
},
|
||||
"emotion": {
|
||||
"version": "9.2.12",
|
||||
"resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.12.tgz",
|
||||
"integrity": "sha512-hcx7jppaI8VoXxIWEhxpDW7I+B4kq9RNzQLmsrF6LY8BGKqe2N+gFAQr0EfuFucFlPs2A9HM4+xNj4NeqEWIOQ==",
|
||||
"requires": {
|
||||
"babel-plugin-emotion": "^9.2.11",
|
||||
"create-emotion": "^9.2.12"
|
||||
}
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@ -4456,7 +4643,6 @@
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
@ -4920,8 +5106,7 @@
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
@ -5403,6 +5588,11 @@
|
||||
"integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=",
|
||||
"dev": true
|
||||
},
|
||||
"find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
},
|
||||
"find-up": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
|
||||
@ -7199,6 +7389,30 @@
|
||||
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
|
||||
"optional": true
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
|
||||
"integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
|
||||
"requires": {
|
||||
"caller-path": "^2.0.0",
|
||||
"resolve-from": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"caller-path": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
|
||||
"integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
|
||||
"requires": {
|
||||
"caller-callsite": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
|
||||
"integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"import-local": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
|
||||
@ -7492,8 +7706,7 @@
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
@ -7566,8 +7779,7 @@
|
||||
"is-directory": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
|
||||
},
|
||||
"is-dotfile": {
|
||||
"version": "1.0.3",
|
||||
@ -7952,8 +8164,7 @@
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
@ -8925,6 +9136,11 @@
|
||||
"p-is-promise": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"memoize-one": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.0.4.tgz",
|
||||
"integrity": "sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA=="
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
@ -11010,8 +11226,7 @@
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
@ -12016,6 +12231,14 @@
|
||||
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
|
||||
"dev": true
|
||||
},
|
||||
"raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"requires": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.24.1",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
|
||||
@ -12257,6 +12480,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-input-autosize": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-2.2.1.tgz",
|
||||
"integrity": "sha512-3+K4CD13iE4lQQ2WlF8PuV5htfmTRLH6MDnfndHM6LuBRszuXnuyIfE7nhSKt8AzRBZ50bu0sAhkNMeS5pxQQA==",
|
||||
"requires": {
|
||||
"prop-types": "^15.5.8"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.5.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz",
|
||||
@ -12390,6 +12621,20 @@
|
||||
"resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-4.0.8.tgz",
|
||||
"integrity": "sha1-InQDWWtRUeGCN32rg1tdRfD4BU4="
|
||||
},
|
||||
"react-select": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-select/-/react-select-2.4.3.tgz",
|
||||
"integrity": "sha512-cmxNaiHpviRYkojeW9rGEUJ4jpX7QTmPe2wcscwA4d1lStzw/cJtr4ft5H2O/YhfpkrcwaLghu3XmEYdXhBo8Q==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"emotion": "^9.1.2",
|
||||
"memoize-one": "^5.0.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"raf": "^3.4.0",
|
||||
"react-input-autosize": "^2.2.1",
|
||||
"react-transition-group": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"react-side-effect": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.5.tgz",
|
||||
@ -14243,6 +14488,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"stylis": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz",
|
||||
"integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q=="
|
||||
},
|
||||
"stylis-rule-sheet": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
|
||||
"integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw=="
|
||||
},
|
||||
"subscriptions-transport-ws": {
|
||||
"version": "0.9.15",
|
||||
"resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.15.tgz",
|
||||
@ -14656,6 +14911,24 @@
|
||||
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
||||
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
|
||||
},
|
||||
"touch": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-2.0.2.tgz",
|
||||
"integrity": "sha512-qjNtvsFXTRq7IuMLweVgFxmEuQ6gLbRs2jQxL80TtZ31dEKWYIxRXquij6w6VimyDek5hD3PytljHmEtAs2u0A==",
|
||||
"requires": {
|
||||
"nopt": "~1.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
|
@ -89,6 +89,7 @@
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^3.2.0",
|
||||
"react-router-redux": "^4.0.8",
|
||||
"react-select": "^2.4.3",
|
||||
"react-table": "^6.8.6",
|
||||
"react-tabs": "^2.1.0",
|
||||
"react-toggle": "^4.0.2",
|
||||
|
@ -280,6 +280,11 @@ button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button > i {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.no_border {
|
||||
border: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
|
@ -0,0 +1,70 @@
|
||||
import React from 'react';
|
||||
import Select, { components } from 'react-select';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/*
|
||||
* Wrap the option generated by react-select and adds utility properties
|
||||
* */
|
||||
const CustomOption = props => {
|
||||
return (
|
||||
<div
|
||||
title={props.data.description || ''}
|
||||
data-test={`data_test_column_type_value_${props.data.value}`}
|
||||
>
|
||||
<components.Option {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
* Searchable select box component
|
||||
* 1) options: Accepts options
|
||||
* 2) value: selectedValue
|
||||
* 3) onChange: function to call on change of value
|
||||
* 4) bsClass: Wrapper class
|
||||
* 5) customStyle: Custom style
|
||||
* */
|
||||
const SearchableSelectBox = ({
|
||||
options,
|
||||
onChange,
|
||||
value,
|
||||
bsClass,
|
||||
styleOverrides,
|
||||
}) => {
|
||||
/* Select element style customization */
|
||||
|
||||
const customStyles = {};
|
||||
if (styleOverrides) {
|
||||
Object.keys(styleOverrides).forEach(comp => {
|
||||
customStyles[comp] = provided => {
|
||||
return {
|
||||
...provided,
|
||||
...styleOverrides[comp],
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
isSearchable
|
||||
components={{ Option: CustomOption }}
|
||||
classNamePrefix={`${bsClass}`}
|
||||
placeholder="column_type"
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
styles={customStyles}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
SearchableSelectBox.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
options: PropTypes.array.isRequired,
|
||||
bsClass: PropTypes.string,
|
||||
customStyle: PropTypes.object,
|
||||
};
|
||||
|
||||
export default SearchableSelectBox;
|
@ -54,7 +54,7 @@
|
||||
.ReactTable .rt-table .rt-thead .rt-td {
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
border-right: 1px solid rgba(0,0,0,0.1);
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ReactTable .rt-table .rt-thead .rt-th.collapsed,
|
||||
@ -66,11 +66,11 @@
|
||||
.ReactTable .rt-tbody .rt-th,
|
||||
.ReactTable .rt-tbody .rt-td {
|
||||
padding: 8px;
|
||||
border-right: 1px solid rgba(0,0,0,0.1);
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.ReactTable .rt-th, .ReactTable .rt-td
|
||||
{
|
||||
.ReactTable .rt-th,
|
||||
.ReactTable .rt-td {
|
||||
overflow: unset !important;
|
||||
}
|
||||
.ReactTable .rt-th .ellipsis,
|
||||
@ -105,8 +105,7 @@
|
||||
.ReactTable .rt-table .rt-tbody .rt-tr-group .rt-tr.-odd:hover {
|
||||
background-color: #ebf7de;
|
||||
}
|
||||
.ReactTable .rt-table
|
||||
{
|
||||
.ReactTable .rt-table {
|
||||
overflow: unset;
|
||||
}
|
||||
.ReactTable .rt-table .rt-tbody {
|
||||
|
@ -150,10 +150,6 @@ a.expanded {
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.select200 {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.defaultWidth {
|
||||
width: 200px;
|
||||
margin-right: 0px;
|
||||
@ -211,10 +207,3 @@ a.expanded {
|
||||
.tableCellExpanded {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.tableActionBtn {
|
||||
i {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
21
console/src/components/Common/TextInput/TextInput.js
Normal file
21
console/src/components/Common/TextInput/TextInput.js
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const TextInput = props => {
|
||||
const { type = 'text', placeholder = '', bsclass = null, onChange } = props;
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
type={type}
|
||||
placeholder={placeholder}
|
||||
className={`${bsclass} form-control`}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
TextInput.propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default TextInput;
|
@ -323,9 +323,7 @@ class Main extends React.Component {
|
||||
<div className={styles.socialIcon}>
|
||||
<img
|
||||
className="img img-responsive"
|
||||
src={`${
|
||||
globals.assetsPath
|
||||
}/common/img/githubicon.png`}
|
||||
src={`${globals.assetsPath}/common/img/githubicon.png`}
|
||||
alt={'GitHub'}
|
||||
/>
|
||||
</div>
|
||||
@ -356,9 +354,7 @@ class Main extends React.Component {
|
||||
<div className={styles.socialIcon}>
|
||||
<img
|
||||
className="img img-responsive"
|
||||
src={`${
|
||||
globals.assetsPath
|
||||
}/common/img/twittericon.png`}
|
||||
src={`${globals.assetsPath}/common/img/twittericon.png`}
|
||||
alt={'Twitter'}
|
||||
/>
|
||||
</div>
|
||||
|
@ -100,12 +100,6 @@ class Common extends React.Component {
|
||||
<OverlayTrigger placement="right" overlay={graphqlurl}>
|
||||
<i className="fa fa-question-circle" aria-hidden="true" />
|
||||
</OverlayTrigger>
|
||||
<br />
|
||||
<br />
|
||||
<small>
|
||||
Note: Specifying the server URL via an environmental variable is
|
||||
recommended if you have different URLs for multiple environments.
|
||||
</small>
|
||||
</h4>
|
||||
<div className={styles.wd_300}>
|
||||
<DropdownButton
|
||||
@ -137,6 +131,11 @@ class Common extends React.Component {
|
||||
testId="remote-schema-graphql-url"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<small>
|
||||
Note: Specifying the server URL via an environmental variable is
|
||||
recommended if you have different URLs for multiple environments.
|
||||
</small>
|
||||
<div className={styles.subheading_text + ' ' + styles.addPaddTop}>
|
||||
Headers for the remote GraphQL server
|
||||
</div>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import defaultState from './AddState';
|
||||
|
||||
import _push from '../push';
|
||||
import { loadSchema, makeMigrationCall } from '../DataActions';
|
||||
import {
|
||||
@ -30,6 +31,10 @@ const REQUEST_ERROR = 'AddTable/REQUEST_ERROR';
|
||||
const VALIDATION_ERROR = 'AddTable/VALIDATION_ERROR';
|
||||
const RESET_VALIDATION_ERROR = 'AddTable/RESET_VALIDATION_ERROR';
|
||||
|
||||
/*
|
||||
* For any action dispatched, the ability to notify the renderer that something is happening
|
||||
* */
|
||||
|
||||
const setDefaults = () => ({ type: SET_DEFAULTS });
|
||||
const setTableName = value => ({ type: SET_TABLENAME, value });
|
||||
const setTableComment = value => ({ type: SET_TABLECOMMENT, value });
|
||||
@ -46,11 +51,10 @@ const setColDefault = (colDefault, index, isNull) => ({
|
||||
index,
|
||||
isNull,
|
||||
});
|
||||
const setColType = (coltype, index, isNull) => ({
|
||||
const setColType = (coltype, index) => ({
|
||||
type: SET_COLTYPE,
|
||||
coltype,
|
||||
index,
|
||||
isNull,
|
||||
});
|
||||
const removeColDefault = index => ({ type: REMOVE_COLDEFAULT, index });
|
||||
const setColNullable = (isNull, index) => ({
|
||||
@ -383,7 +387,6 @@ const addTableReducer = (state = defaultState, action) => {
|
||||
{
|
||||
...state.columns[ij],
|
||||
type: action.coltype,
|
||||
nullable: action.isNull,
|
||||
},
|
||||
...state.columns.slice(ij + 1),
|
||||
],
|
||||
|
@ -2,17 +2,20 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import * as tooltip from './Tooltips';
|
||||
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import PrimaryKeySelector from '../Common/ReusableComponents/PrimaryKeySelector';
|
||||
import ForeignKeyWrapper from './ForeignKeyWrapper';
|
||||
import UniqueKeyWrapper from './UniqueKeyWrapper';
|
||||
|
||||
import dataTypes from '../Common/DataTypes';
|
||||
import { TIMESTAMP, DATE, UUID } from '../utils';
|
||||
import { showErrorNotification } from '../../Common/Notification';
|
||||
|
||||
import TableName from './TableName';
|
||||
import TableColumns from './TableColumns';
|
||||
import TableComment from './TableComment';
|
||||
|
||||
import * as tooltip from './Tooltips';
|
||||
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
|
||||
|
||||
import {
|
||||
setTableName,
|
||||
setTableComment,
|
||||
@ -21,17 +24,15 @@ import {
|
||||
setColType,
|
||||
setColNullable,
|
||||
setColDefault,
|
||||
removeColDefault,
|
||||
setForeignKeys,
|
||||
validationError,
|
||||
resetValidation,
|
||||
setDefaults,
|
||||
setPk,
|
||||
createTableSql,
|
||||
addCol,
|
||||
setUniqueKeys,
|
||||
} from './AddActions';
|
||||
|
||||
import { fetchColumnTypes, RESET_COLUMN_TYPE_LIST } from '../DataActions';
|
||||
import { setDefaults, setPk, createTableSql } from './AddActions';
|
||||
import { validationError, resetValidation } from './AddActions';
|
||||
|
||||
import {
|
||||
ATLEAST_ONE_PRIMARY_KEY_MSG,
|
||||
ATLEAST_ONE_COLUMN_MSG,
|
||||
@ -48,35 +49,85 @@ import gqlPattern, {
|
||||
gqlColumnErrorNotif,
|
||||
} from '../Common/GraphQLValidation';
|
||||
|
||||
import styles from '../../../Common/TableCommon/Table.scss';
|
||||
|
||||
/*
|
||||
const typeDescriptionDict = convertListToDictUsingKV(
|
||||
'value',
|
||||
'description',
|
||||
dataTypes
|
||||
);
|
||||
*/
|
||||
/* AddTable is a wrapper which wraps
|
||||
* 1) Table Name input
|
||||
* 2) Columns inputs
|
||||
* 3) Primary Key input
|
||||
* 4) Comment Input
|
||||
* 5) Add Table button
|
||||
* */
|
||||
|
||||
class AddTable extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props.dispatch(setDefaults());
|
||||
const { columns, dispatch } = this.props;
|
||||
columns.map((column, i) => {
|
||||
let defValue = '';
|
||||
if ('default' in column) {
|
||||
defValue = column.default.value;
|
||||
}
|
||||
if (defValue === '') {
|
||||
dispatch(removeColDefault(i));
|
||||
}
|
||||
});
|
||||
this.onTableNameChange = this.onTableNameChange.bind(this);
|
||||
this.onTableCommentChange = this.onTableCommentChange.bind(this);
|
||||
this.onRemoveColumn = this.onRemoveColumn.bind(this);
|
||||
this.onColumnChange = this.onColumnNameChange.bind(this);
|
||||
this.onColTypeChange = this.onColTypeChange.bind(this);
|
||||
this.onColNullableChange = this.onColNullableChange.bind(this);
|
||||
this.onColUniqueChange = this.onColUniqueChange.bind(this);
|
||||
this.setColDefaultValue = this.setColDefaultValue.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchColumnTypes());
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch(setDefaults());
|
||||
this.props.dispatch({
|
||||
type: RESET_COLUMN_TYPE_LIST,
|
||||
});
|
||||
}
|
||||
onTableNameChange = e => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setTableName(e.target.value));
|
||||
};
|
||||
onTableCommentChange = e => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setTableComment(e.target.value));
|
||||
};
|
||||
onRemoveColumn = i => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(removeColumn(i));
|
||||
};
|
||||
onColumnNameChange = (i, isNullableChecked, e) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setColName(e.target.value, i, isNullableChecked));
|
||||
};
|
||||
onColTypeChange = (i, value) => {
|
||||
const { dispatch, columns } = this.props;
|
||||
dispatch(setColType(value, i));
|
||||
if (i + 1 === columns.length) {
|
||||
dispatch(addCol());
|
||||
}
|
||||
};
|
||||
onColNullableChange = (i, e) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setColNullable(e.target.checked, i));
|
||||
};
|
||||
|
||||
onColUniqueChange = (i, numUniqueKeys, isColumnUnique, _uindex) => {
|
||||
const { dispatch, uniqueKeys } = this.props;
|
||||
if (isColumnUnique) {
|
||||
dispatch(
|
||||
setUniqueKeys([
|
||||
...uniqueKeys.slice(0, _uindex),
|
||||
...uniqueKeys.slice(_uindex + 1),
|
||||
])
|
||||
);
|
||||
} else {
|
||||
const newUniqueKeys = JSON.parse(JSON.stringify(uniqueKeys));
|
||||
newUniqueKeys[numUniqueKeys - 1] = [i];
|
||||
dispatch(setUniqueKeys([...newUniqueKeys, []]));
|
||||
}
|
||||
};
|
||||
|
||||
setColDefaultValue = (i, isNullableChecked, e) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(setColDefault(e.target.value, i, isNullableChecked));
|
||||
};
|
||||
|
||||
columnValidation() {
|
||||
if (this.props.columns.length <= 0) {
|
||||
// this.props.dispatch(validationError(ATLEAST_ONE_COLUMN_MSG));
|
||||
@ -232,181 +283,22 @@ class AddTable extends Component {
|
||||
lastError,
|
||||
lastSuccess,
|
||||
internalError,
|
||||
dataTypes,
|
||||
} = this.props;
|
||||
|
||||
const cols = columns.map((column, i) => {
|
||||
let removeIcon;
|
||||
if (i + 1 === columns.length) {
|
||||
removeIcon = (
|
||||
<i className={`${styles.iClickable} ${styles.fontAwosomeClose}`} />
|
||||
);
|
||||
} else {
|
||||
removeIcon = (
|
||||
<i
|
||||
className={`${styles.iClickable} ${
|
||||
styles.fontAwosomeClose
|
||||
} fa-lg fa fa-times`}
|
||||
onClick={() => {
|
||||
dispatch(removeColumn(i));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
const getCreateBtnText = () => {
|
||||
let createBtnText = 'Add Table';
|
||||
if (ongoingRequest) {
|
||||
createBtnText = 'Creating...';
|
||||
} else if (lastError) {
|
||||
createBtnText = 'Creating Failed. Try again';
|
||||
} else if (internalError) {
|
||||
createBtnText = 'Creating Failed. Try again';
|
||||
} else if (lastSuccess) {
|
||||
createBtnText = 'Created! Redirecting...';
|
||||
}
|
||||
let defValue = '';
|
||||
if ('default' in column) {
|
||||
defValue = column.default.value;
|
||||
}
|
||||
let defPlaceholder = 'default_value';
|
||||
if (column.type === TIMESTAMP) {
|
||||
defPlaceholder = 'example: now()';
|
||||
} else if (column.type === DATE) {
|
||||
defPlaceholder = '';
|
||||
} else if (column.type === UUID) {
|
||||
defPlaceholder = 'example: gen_random_uuid()';
|
||||
}
|
||||
|
||||
let isColumnUnique = false;
|
||||
let _uindex;
|
||||
const numUniqueKeys = uniqueKeys.length;
|
||||
for (let _i = numUniqueKeys - 1; _i >= 0; _i--) {
|
||||
const key = uniqueKeys[_i];
|
||||
if (key.length === 1) {
|
||||
if (key[0] === i) {
|
||||
isColumnUnique = true;
|
||||
_uindex = _i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const toggleUnique = () => {
|
||||
if (isColumnUnique) {
|
||||
dispatch(
|
||||
setUniqueKeys([
|
||||
...uniqueKeys.slice(0, _uindex),
|
||||
...uniqueKeys.slice(_uindex + 1),
|
||||
])
|
||||
);
|
||||
} else {
|
||||
const newUniqueKeys = JSON.parse(JSON.stringify(uniqueKeys));
|
||||
newUniqueKeys[numUniqueKeys - 1] = [i];
|
||||
dispatch(setUniqueKeys([...newUniqueKeys, []]));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={i} className={`${styles.display_flex} form-group`}>
|
||||
<input
|
||||
type="text"
|
||||
className={`${styles.input} form-control ${styles.add_mar_right}`}
|
||||
value={column.name}
|
||||
placeholder="column_name"
|
||||
onChange={e => {
|
||||
dispatch(
|
||||
setColName(e.target.value, i, this.refs[`nullable${i}`].checked)
|
||||
);
|
||||
}}
|
||||
data-test={`column-${i}`}
|
||||
/>
|
||||
<select
|
||||
value={column.type}
|
||||
className={`${styles.select} ${styles.select200} form-control ${
|
||||
styles.add_pad_left
|
||||
}`}
|
||||
onChange={e => {
|
||||
dispatch(
|
||||
setColType(e.target.value, i, this.refs[`nullable${i}`].checked)
|
||||
);
|
||||
if (i + 1 === columns.length) {
|
||||
dispatch(addCol());
|
||||
}
|
||||
}}
|
||||
data-test={`col-type-${i}`}
|
||||
>
|
||||
{column.type === '' ? (
|
||||
<option disabled value="">
|
||||
-- type --
|
||||
</option>
|
||||
) : null}
|
||||
{/* The below makes a set of options based of the available datatype. Refer Common/Datatypes.js for more info. */}
|
||||
{dataTypes.map((datatype, index) => (
|
||||
<option
|
||||
value={datatype.value}
|
||||
key={index}
|
||||
title={datatype.description}
|
||||
>
|
||||
{datatype.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{/*
|
||||
{typeDescriptionDict && typeDescriptionDict[column.type] ? (
|
||||
<span>
|
||||
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={tooltip.dataTypeDescription(
|
||||
typeDescriptionDict[column.type]
|
||||
)}
|
||||
>
|
||||
<i className="fa fa-question-circle" aria-hidden="true" />
|
||||
</OverlayTrigger>{' '}
|
||||
|
||||
</span>
|
||||
) : null}
|
||||
*/}
|
||||
<input
|
||||
placeholder={defPlaceholder}
|
||||
type="text"
|
||||
value={defValue}
|
||||
className={`${styles.inputDefault} ${
|
||||
styles.defaultWidth
|
||||
} form-control ${styles.add_pad_left}`}
|
||||
onChange={e => {
|
||||
dispatch(
|
||||
setColDefault(
|
||||
e.target.value,
|
||||
i,
|
||||
this.refs[`nullable${i}`].checked
|
||||
)
|
||||
);
|
||||
}}
|
||||
data-test={`col-default-${i}`}
|
||||
/>{' '}
|
||||
<input
|
||||
className={`${styles.inputCheckbox} form-control `}
|
||||
checked={columns[i].nullable}
|
||||
type="checkbox"
|
||||
ref={`nullable${i}`}
|
||||
onChange={e => {
|
||||
dispatch(setColNullable(e.target.checked, i));
|
||||
}}
|
||||
data-test={`nullable-${i}`}
|
||||
/>{' '}
|
||||
<label>Nullable</label>
|
||||
<input
|
||||
className={`${styles.inputCheckbox} form-control `}
|
||||
checked={isColumnUnique}
|
||||
type="checkbox"
|
||||
ref={`unique${i}`}
|
||||
onChange={toggleUnique}
|
||||
data-test={`unique-${i.toString()}`}
|
||||
/>{' '}
|
||||
<label>Unique</label>
|
||||
{removeIcon}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
let createBtnText = 'Create';
|
||||
if (ongoingRequest) {
|
||||
createBtnText = 'Creating...';
|
||||
} else if (lastError) {
|
||||
createBtnText = 'Creating Failed. Try again';
|
||||
} else if (internalError) {
|
||||
createBtnText = 'Creating Failed. Try again';
|
||||
} else if (lastSuccess) {
|
||||
createBtnText = 'Created! Redirecting...';
|
||||
}
|
||||
return createBtnText;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -424,19 +316,19 @@ class AddTable extends Component {
|
||||
<div
|
||||
className={`${styles.addCol} col-xs-12 ${styles.padd_left_remove}`}
|
||||
>
|
||||
<h4 className={styles.subheading_text}>Table Name </h4>
|
||||
<input
|
||||
type="text"
|
||||
data-test="tableName"
|
||||
placeholder="table_name"
|
||||
className={`${styles.tableNameInput} form-control`}
|
||||
onChange={e => {
|
||||
dispatch(setTableName(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<TableName onChange={this.onTableNameChange.bind(this)} />
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Columns</h4>
|
||||
{cols}
|
||||
<TableColumns
|
||||
uniqueKeys={uniqueKeys}
|
||||
dataTypes={dataTypes}
|
||||
columns={columns}
|
||||
onRemoveColumn={this.onRemoveColumn}
|
||||
onColumnChange={this.onColumnNameChange}
|
||||
onColTypeChange={this.onColTypeChange}
|
||||
onColNullableChange={this.onColNullableChange}
|
||||
onColUniqueChange={this.onColUniqueChange}
|
||||
setColDefaultValue={this.setColDefaultValue}
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>
|
||||
Primary Key
|
||||
@ -505,16 +397,7 @@ class AddTable extends Component {
|
||||
setUniqueKeys={setUniqueKeys}
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Comment </h4>
|
||||
<input
|
||||
type="text"
|
||||
data-test="tableComment"
|
||||
placeholder="comment"
|
||||
className={`${styles.tableNameInput} form-control`}
|
||||
onChange={e => {
|
||||
dispatch(setTableComment(e.target.value));
|
||||
}}
|
||||
/>
|
||||
<TableComment onChange={this.onTableCommentChange} />
|
||||
<hr />
|
||||
<Button
|
||||
type="submit"
|
||||
@ -523,7 +406,7 @@ class AddTable extends Component {
|
||||
color="yellow"
|
||||
size="sm"
|
||||
>
|
||||
{createBtnText}
|
||||
{getCreateBtnText()}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -549,6 +432,8 @@ const mapStateToProps = state => ({
|
||||
...state.addTable.table,
|
||||
allSchemas: state.tables.allSchemas,
|
||||
currentSchema: state.tables.currentSchema,
|
||||
dataTypes: state.tables.columnDataTypes,
|
||||
columnDataTypeFetchErr: state.tables.columnDataTypeFetchErr,
|
||||
});
|
||||
|
||||
const addTableConnector = connect => connect(mapStateToProps)(AddTable);
|
||||
|
143
console/src/components/Services/Data/Add/TableColumn.js
Normal file
143
console/src/components/Services/Data/Add/TableColumn.js
Normal file
@ -0,0 +1,143 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
import { commonDataTypes } from '../utils';
|
||||
import {
|
||||
getDataOptions,
|
||||
getPlaceholder,
|
||||
getDefaultValue,
|
||||
} from '../Common/utils';
|
||||
|
||||
/* Custom style object for searchable select box */
|
||||
const customSelectBoxStyles = {
|
||||
dropdownIndicator: {
|
||||
padding: '5px',
|
||||
},
|
||||
singleValue: {
|
||||
color: '#555555',
|
||||
},
|
||||
};
|
||||
|
||||
const TableColumn = props => {
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
const {
|
||||
column,
|
||||
colLength,
|
||||
colIndex: i,
|
||||
onRemoveColumn,
|
||||
onColumnChange,
|
||||
onColTypeChange,
|
||||
setColDefaultValue,
|
||||
onColNullableChange,
|
||||
onColUniqueChange,
|
||||
dataTypes: restTypes,
|
||||
uniqueKeys,
|
||||
} = props;
|
||||
|
||||
let isColumnUnique = false;
|
||||
let _uindex;
|
||||
const numUniqueKeys = uniqueKeys.length;
|
||||
for (let _i = numUniqueKeys - 1; _i >= 0; _i--) {
|
||||
const key = uniqueKeys[_i];
|
||||
if (key.length === 1) {
|
||||
if (key[0] === i) {
|
||||
isColumnUnique = true;
|
||||
_uindex = _i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleColTypeChange = selectedOption => {
|
||||
onColTypeChange(selectedOption.colIdentifier, selectedOption.value);
|
||||
};
|
||||
const { columnDataTypes, columnTypeValueMap } = getDataOptions(
|
||||
commonDataTypes,
|
||||
restTypes,
|
||||
i
|
||||
);
|
||||
const getRemoveIcon = colLen => {
|
||||
let removeIcon;
|
||||
if (i + 1 === colLen) {
|
||||
removeIcon = <i className={`${styles.fontAwosomeClose}`} />;
|
||||
} else {
|
||||
removeIcon = (
|
||||
<i
|
||||
className={`${styles.fontAwosomeClose} fa-lg fa fa-times`}
|
||||
onClick={onRemoveColumn.bind(undefined, i)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return removeIcon;
|
||||
};
|
||||
|
||||
return (
|
||||
<div key={i} className={`${styles.display_flex} form-group`}>
|
||||
<input
|
||||
type="text"
|
||||
className={`${styles.input} form-control`}
|
||||
value={column.name}
|
||||
placeholder="column_name"
|
||||
onChange={onColumnChange.bind(undefined, i, column.nullable || false)}
|
||||
data-test={`column-${i}`}
|
||||
/>
|
||||
<span
|
||||
className={`${styles.inputDefault} ${styles.defaultWidth}`}
|
||||
data-test={`col-type-${i}`}
|
||||
>
|
||||
<SearchableSelectBox
|
||||
options={columnDataTypes}
|
||||
onChange={handleColTypeChange}
|
||||
value={column.type && columnTypeValueMap[column.type]}
|
||||
bsClass={`col-type-${i} add_table_column_selector`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
placeholder={getPlaceholder(column)}
|
||||
type="text"
|
||||
value={getDefaultValue(column)}
|
||||
className={`${styles.inputDefault} ${
|
||||
styles.defaultWidth
|
||||
} form-control ${styles.add_pad_left}`}
|
||||
onChange={setColDefaultValue.bind(
|
||||
undefined,
|
||||
i,
|
||||
column.nullable || false
|
||||
)}
|
||||
data-test={`col-default-${i}`}
|
||||
/>{' '}
|
||||
<input
|
||||
className={`${styles.inputCheckbox} form-control `}
|
||||
checked={column.nullable}
|
||||
type="checkbox"
|
||||
onChange={onColNullableChange.bind(undefined, i)}
|
||||
data-test={`nullable-${i}`}
|
||||
/>{' '}
|
||||
<label>Nullable</label>
|
||||
<input
|
||||
className={`${styles.inputCheckbox} form-control `}
|
||||
checked={isColumnUnique}
|
||||
type="checkbox"
|
||||
onChange={onColUniqueChange.bind(
|
||||
undefined,
|
||||
i,
|
||||
numUniqueKeys,
|
||||
isColumnUnique,
|
||||
_uindex
|
||||
)}
|
||||
data-test={`unique-${i.toString()}`}
|
||||
/>{' '}
|
||||
<label>Unique</label>
|
||||
{getRemoveIcon(colLength)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TableColumn.propTypes = {
|
||||
colIndex: PropTypes.number.isRequired,
|
||||
column: PropTypes.object.isRequired,
|
||||
colLength: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default TableColumn;
|
31
console/src/components/Services/Data/Add/TableColumns.js
Normal file
31
console/src/components/Services/Data/Add/TableColumns.js
Normal file
@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TableColumn from './TableColumn';
|
||||
|
||||
const TableColumns = props => {
|
||||
const { columns } = props;
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
const cols = columns.map((column, i) => {
|
||||
return (
|
||||
<TableColumn
|
||||
key={`table_column_wrapper_${i}`}
|
||||
colIndex={i}
|
||||
column={column}
|
||||
colLength={columns.length}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return [
|
||||
<h4 key="table_columns_header" className={styles.subheading_text}>
|
||||
Columns
|
||||
</h4>,
|
||||
<div key="table_colums_value">{cols}</div>,
|
||||
];
|
||||
};
|
||||
|
||||
TableColumns.propTypes = {
|
||||
columns: PropTypes.array.isRequired,
|
||||
};
|
||||
|
||||
export default TableColumns;
|
28
console/src/components/Services/Data/Add/TableComment.js
Normal file
28
console/src/components/Services/Data/Add/TableComment.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TextInput from '../../../Common/TextInput/TextInput';
|
||||
|
||||
const TableComment = ({ onChange }) => {
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
return [
|
||||
<h4 key="add_table_comment_header" className={styles.subheading_text}>
|
||||
Comment
|
||||
</h4>,
|
||||
<TextInput
|
||||
key="add_table_comment_element"
|
||||
type="text"
|
||||
placeholder="comment"
|
||||
data-test="tableComment"
|
||||
bsclass={`${styles.tableNameInput}`}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
];
|
||||
};
|
||||
|
||||
TableComment.propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default TableComment;
|
28
console/src/components/Services/Data/Add/TableName.js
Normal file
28
console/src/components/Services/Data/Add/TableName.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import TextInput from '../../../Common/TextInput/TextInput';
|
||||
|
||||
const TableNameInput = ({ onChange }) => {
|
||||
const styles = require('../../../Common/TableCommon/Table.scss');
|
||||
return [
|
||||
<h4 key="add_table_input_header" className={styles.subheading_text}>
|
||||
Table Name
|
||||
</h4>,
|
||||
<TextInput
|
||||
key="add_table_input_element"
|
||||
type="text"
|
||||
placeholder="table_name"
|
||||
data-test="tableName"
|
||||
bsclass={`${styles.tableNameInput}`}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
];
|
||||
};
|
||||
|
||||
TableNameInput.propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default TableNameInput;
|
@ -1,82 +0,0 @@
|
||||
const dataTypes = [
|
||||
{
|
||||
name: 'Integer',
|
||||
value: 'integer',
|
||||
description: 'signed four-byte integer',
|
||||
hasuraDatatype: 'integer',
|
||||
},
|
||||
{
|
||||
name: 'Integer (auto-increment)',
|
||||
value: 'serial',
|
||||
description: 'autoincrementing four-byte integer',
|
||||
hasuraDatatype: null,
|
||||
},
|
||||
{
|
||||
name: 'UUID',
|
||||
value: 'uuid',
|
||||
description: 'universal unique identifier',
|
||||
hasuraDatatype: 'uuid',
|
||||
},
|
||||
{
|
||||
name: 'Big Integer',
|
||||
value: 'bigint',
|
||||
description: 'signed eight-byte integer',
|
||||
hasuraDatatype: 'bigint',
|
||||
},
|
||||
{
|
||||
name: 'Big Integer (auto-increment)',
|
||||
value: 'bigserial',
|
||||
description: 'autoincrementing eight-byte integer',
|
||||
hasuraDatatype: null,
|
||||
},
|
||||
{
|
||||
name: 'Text',
|
||||
value: 'text',
|
||||
description: 'variable-length character string',
|
||||
hasuraDatatype: 'text',
|
||||
},
|
||||
{
|
||||
name: 'Numeric',
|
||||
value: 'numeric',
|
||||
description: 'exact numeric of selected precision',
|
||||
hasuraDatatype: 'numeric',
|
||||
},
|
||||
{
|
||||
name: 'Date',
|
||||
value: 'date',
|
||||
description: 'calendar date (year, month, day)',
|
||||
hasuraDatatype: 'date',
|
||||
},
|
||||
{
|
||||
name: 'Timestamp',
|
||||
value: 'timestamp with time zone',
|
||||
description: 'date and time, including time zone',
|
||||
hasuraDatatype: 'timestamp with time zone',
|
||||
},
|
||||
{
|
||||
name: 'Time',
|
||||
value: 'time with time zone',
|
||||
description: 'time of day (no time zone)',
|
||||
hasuraDatatype: 'time with time zone',
|
||||
},
|
||||
{
|
||||
name: 'Boolean',
|
||||
value: 'boolean',
|
||||
description: 'logical Boolean (true/false)',
|
||||
hasuraDatatype: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
value: 'json',
|
||||
description: 'textual JSON data',
|
||||
hasuraDatatype: 'json',
|
||||
},
|
||||
{
|
||||
name: 'JSONB',
|
||||
value: 'jsonb',
|
||||
description: 'binary format JSON data',
|
||||
hasuraDatatype: 'jsonb',
|
||||
},
|
||||
];
|
||||
|
||||
export default dataTypes;
|
34
console/src/components/Services/Data/Common/PgInfo.js
Normal file
34
console/src/components/Services/Data/Common/PgInfo.js
Normal file
@ -0,0 +1,34 @@
|
||||
const pgCategoryCode = {
|
||||
A: 'Array types',
|
||||
B: 'Boolean types',
|
||||
C: 'Composite types',
|
||||
D: 'Date/time types',
|
||||
E: 'Enum types',
|
||||
G: 'Geometric types',
|
||||
I: 'Network address types',
|
||||
N: 'Numeric types',
|
||||
P: 'Pseudo-types',
|
||||
R: 'Range types',
|
||||
S: 'String types',
|
||||
T: 'Timespan types',
|
||||
U: 'User-defined types',
|
||||
V: 'Bit-string types',
|
||||
X: 'unknown type',
|
||||
};
|
||||
|
||||
const topCategory = ['N', 'S', 'B', 'D', 'T'];
|
||||
|
||||
const restCategory = [
|
||||
...Object.keys(pgCategoryCode).filter(p => topCategory.indexOf(p) === -1),
|
||||
];
|
||||
|
||||
const aggCategory = [...topCategory, ...restCategory];
|
||||
|
||||
const serialTypes = [
|
||||
'serial,bigserial,smallserial',
|
||||
'serial,bigserial,smallserial',
|
||||
'autoincrementing integer,large autoincrementing integer, small autoincrementing integer',
|
||||
'N',
|
||||
];
|
||||
|
||||
export { pgCategoryCode, aggCategory, serialTypes };
|
103
console/src/components/Services/Data/Common/utils.js
Normal file
103
console/src/components/Services/Data/Common/utils.js
Normal file
@ -0,0 +1,103 @@
|
||||
import { aggCategory, pgCategoryCode } from './PgInfo';
|
||||
|
||||
const getDataTypeInfo = (row, categoryInfo, colId) => {
|
||||
const columnTypeValueMap = {};
|
||||
// Splits comma seperated type names
|
||||
const typInfo = row[0].split(',');
|
||||
// Splits comma seperated type display names
|
||||
const typDisplayName = row[1].split(',');
|
||||
// Splits comma seperated type descriptions
|
||||
const typDescription = row[2].split(':');
|
||||
// Create option object for every valid type
|
||||
const currTypeObj = typInfo.map((t, i) => {
|
||||
const optObj = {
|
||||
value: t,
|
||||
label: typDisplayName[i],
|
||||
key: `${categoryInfo}_${i}`,
|
||||
colIdentifier: colId,
|
||||
description: typDescription[i],
|
||||
};
|
||||
// Memoizing option for later use
|
||||
columnTypeValueMap[t] = optObj;
|
||||
return optObj;
|
||||
});
|
||||
return { typInfo: currTypeObj, typValueMap: columnTypeValueMap };
|
||||
};
|
||||
|
||||
/*
|
||||
* Input arguments:
|
||||
* dataTypes -> Frequently used types
|
||||
* , restTypes -> Information queried from database
|
||||
* , identifier -> Identifies where this column to be tracked
|
||||
* Output:
|
||||
* 1) Type -> grouped option
|
||||
* 2) returns array of `grouped` options
|
||||
* */
|
||||
const getDataOptions = (commonDataTypes, restTypes, identifier) => {
|
||||
let columnTypeValueMap = {};
|
||||
const columnDataTypes = [];
|
||||
const mainOpts = [];
|
||||
commonDataTypes.forEach((d, dKey) => {
|
||||
mainOpts.push({
|
||||
value: d.value,
|
||||
label: d.name,
|
||||
description: d.description,
|
||||
key: dKey,
|
||||
colIdentifier: identifier,
|
||||
});
|
||||
columnTypeValueMap[d.value] = mainOpts[mainOpts.length - 1];
|
||||
});
|
||||
columnDataTypes.push({
|
||||
label: 'Frequently Used Types',
|
||||
options: mainOpts,
|
||||
});
|
||||
|
||||
/*
|
||||
* restTypes will be a list of arrays,
|
||||
* each array will have
|
||||
* [
|
||||
* "Types available in a particular group",
|
||||
* "Display Name of a type",
|
||||
* "Description of a type",
|
||||
* "Category the particular type belongs to"
|
||||
* ]
|
||||
* */
|
||||
aggCategory.forEach(category => {
|
||||
const categoryRow = restTypes.filter(r => r[3] === category);
|
||||
if (categoryRow.length > 0) {
|
||||
const { typInfo, typValueMap } = getDataTypeInfo(
|
||||
categoryRow[0],
|
||||
pgCategoryCode[category],
|
||||
identifier
|
||||
);
|
||||
columnTypeValueMap = { ...columnTypeValueMap, ...typValueMap };
|
||||
columnDataTypes.push({
|
||||
label: pgCategoryCode[category],
|
||||
options: typInfo,
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
columnTypeValueMap,
|
||||
columnDataTypes,
|
||||
};
|
||||
};
|
||||
|
||||
const getPlaceholder = column => {
|
||||
switch (column.type) {
|
||||
case 'timestamptz':
|
||||
return 'example: now()';
|
||||
case 'date':
|
||||
return '';
|
||||
case 'uuid':
|
||||
return 'example: gen_random_uuid()';
|
||||
default:
|
||||
return 'default_value';
|
||||
}
|
||||
};
|
||||
|
||||
const getDefaultValue = column => {
|
||||
return ('default' in column && column.default.value) || '';
|
||||
};
|
||||
|
||||
export { getDataOptions, getPlaceholder, getDefaultValue, getDataTypeInfo };
|
@ -21,6 +21,8 @@ import {
|
||||
} from '../Metadata/Actions';
|
||||
import globals from '../../../Globals';
|
||||
|
||||
import { fetchColumnTypesQuery } from './utils';
|
||||
|
||||
import { SERVER_CONSOLE_MODE } from '../../../constants';
|
||||
|
||||
const SET_TABLE = 'Data/SET_TABLE';
|
||||
@ -43,6 +45,10 @@ const UPDATE_REMOTE_SCHEMA_MANUAL_REL = 'Data/UPDATE_SCHEMA_MANUAL_REL';
|
||||
const SET_CONSISTENT_SCHEMA = 'Data/SET_CONSISTENT_SCHEMA';
|
||||
const SET_CONSISTENT_FUNCTIONS = 'Data/SET_CONSISTENT_FUNCTIONS';
|
||||
|
||||
const FETCH_COLUMN_TYPE_LIST = 'Data/FETCH_COLUMN_TYPE_LIST';
|
||||
const FETCH_COLUMN_TYPE_LIST_FAIL = 'Data/FETCH_COLUMN_TYPE_LIST_FAIL';
|
||||
const RESET_COLUMN_TYPE_LIST = 'Data/RESET_COLUMN_TYPE_LIST';
|
||||
|
||||
const MAKE_REQUEST = 'ModifyTable/MAKE_REQUEST';
|
||||
const REQUEST_SUCCESS = 'ModifyTable/REQUEST_SUCCESS';
|
||||
const REQUEST_ERROR = 'ModifyTable/REQUEST_ERROR';
|
||||
@ -655,6 +661,48 @@ const fetchTableListBySchema = (schemaName, successAction, errorAction) => (
|
||||
);
|
||||
};
|
||||
|
||||
/* */
|
||||
const fetchColumnTypes = () => {
|
||||
return (dispatch, getState) => {
|
||||
const url = Endpoints.getSchema;
|
||||
const reqQuery = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnTypesQuery,
|
||||
},
|
||||
};
|
||||
const options = {
|
||||
credentials: globalCookiePolicy,
|
||||
method: 'POST',
|
||||
headers: dataHeaders(getState),
|
||||
body: JSON.stringify(reqQuery),
|
||||
};
|
||||
return dispatch(requestAction(url, options)).then(
|
||||
data => {
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_LIST,
|
||||
data: data.result.slice(1),
|
||||
});
|
||||
},
|
||||
error => {
|
||||
dispatch(
|
||||
showErrorNotification(
|
||||
'Error fetching column types',
|
||||
'Kindly reach out to us in case you face this issue again',
|
||||
error,
|
||||
error
|
||||
)
|
||||
);
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_LIST_FAIL,
|
||||
data: error,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
/* */
|
||||
|
||||
/* ******************************************************* */
|
||||
const dataReducer = (state = defaultState, action) => {
|
||||
// eslint-disable-line no-unused-vars
|
||||
@ -788,6 +836,25 @@ const dataReducer = (state = defaultState, action) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
case FETCH_COLUMN_TYPE_LIST:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: action.data,
|
||||
columnDataTypeFetchErr: 'Error fetching data',
|
||||
};
|
||||
|
||||
case FETCH_COLUMN_TYPE_LIST_FAIL:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: [],
|
||||
columnDataTypeFetchErr: action.data,
|
||||
};
|
||||
case RESET_COLUMN_TYPE_LIST:
|
||||
return {
|
||||
...state,
|
||||
columnDataTypes: [...defaultState.columnDataTypes],
|
||||
columnDataTypeFetchErr: defaultState.columnDataTypes,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
@ -823,4 +890,7 @@ export {
|
||||
initQueries,
|
||||
setConsistentSchema,
|
||||
setConsistentFunctions,
|
||||
//
|
||||
fetchColumnTypes,
|
||||
RESET_COLUMN_TYPE_LIST,
|
||||
};
|
||||
|
@ -125,9 +125,13 @@ const defaultModifyState = {
|
||||
viewDefinition: null,
|
||||
viewDefinitionError: null,
|
||||
tableCommentEdit: { enabled: false, editedValue: null },
|
||||
alterColumnOptions: [], // Store supported implicit column -> column casts
|
||||
alterColumnOptionsFetchErr: null,
|
||||
};
|
||||
|
||||
const defaultState = {
|
||||
columnDataTypes: [], // To store list of column types supported by postgres
|
||||
columnDataTypeFetchErr: null,
|
||||
currentTable: null,
|
||||
view: { ...defaultViewState },
|
||||
modify: { ...defaultModifyState },
|
||||
|
@ -13,7 +13,7 @@ const getSQLValue = value => {
|
||||
return sqlValue.replace(/['"]+/g, '');
|
||||
};
|
||||
|
||||
const parseCreateSQL = (sql) => {
|
||||
const parseCreateSQL = sql => {
|
||||
const _objects = [];
|
||||
|
||||
const regExp = createSQLRegex;
|
||||
|
@ -207,13 +207,7 @@ const ViewRows = ({
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={
|
||||
styles.tableActionBtn +
|
||||
' ' +
|
||||
styles.add_mar_right_small +
|
||||
' ' +
|
||||
styles.remove_margin_right
|
||||
}
|
||||
className={styles.add_mar_right_small}
|
||||
color="white"
|
||||
size="xs"
|
||||
onClick={disabled ? disabledOnClick : handleClick}
|
||||
|
@ -18,6 +18,8 @@ import {
|
||||
EDIT_COLUMN,
|
||||
SET_PRIMARY_KEYS,
|
||||
SET_FOREIGN_KEYS,
|
||||
FETCH_COLUMN_TYPE_CASTS,
|
||||
FETCH_COLUMN_TYPE_CASTS_FAIL,
|
||||
RESET,
|
||||
SET_UNIQUE_KEYS,
|
||||
} from '../TableModify/ModifyActions';
|
||||
@ -552,6 +554,21 @@ const modifyReducer = (tableName, schemas, modifyStateOrig, action) => {
|
||||
...modifyState,
|
||||
fkModify: action.fks,
|
||||
};
|
||||
|
||||
case FETCH_COLUMN_TYPE_CASTS:
|
||||
return {
|
||||
...modifyState,
|
||||
alterColumnOptions: action.data,
|
||||
alterColumnOptionsFetchErr: null,
|
||||
};
|
||||
|
||||
case FETCH_COLUMN_TYPE_CASTS_FAIL:
|
||||
return {
|
||||
...modifyState,
|
||||
alterColumnOptions: [],
|
||||
alterColumnOptionsFetchErr: action.data,
|
||||
};
|
||||
|
||||
case SET_UNIQUE_KEYS:
|
||||
return {
|
||||
...modifyState,
|
||||
|
@ -1,7 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { showErrorNotification } from '../../Common/Notification';
|
||||
import gqlPattern, { gqlColumnErrorNotif } from '../Common/GraphQLValidation';
|
||||
import dataTypes from '../Common/DataTypes';
|
||||
import { commonDataTypes } from '../utils';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
|
||||
import { getDataOptions } from '../Common/utils';
|
||||
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import { addColSql } from '../TableModify/ModifyActions';
|
||||
|
||||
@ -67,8 +72,8 @@ const useColumnEditor = (dispatch, tableName) => {
|
||||
},
|
||||
colType: {
|
||||
value: colType,
|
||||
onChange: e => {
|
||||
setColumnState({ ...columnState, colType: e.target.value });
|
||||
onChange: selected => {
|
||||
setColumnState({ ...columnState, colType: selected.value });
|
||||
},
|
||||
},
|
||||
colNull: {
|
||||
@ -93,13 +98,7 @@ const useColumnEditor = (dispatch, tableName) => {
|
||||
};
|
||||
};
|
||||
|
||||
const alterTypeOptions = dataTypes.map((datatype, index) => (
|
||||
<option value={datatype.value} key={index} title={datatype.description}>
|
||||
{datatype.name}
|
||||
</option>
|
||||
));
|
||||
|
||||
const ColumnCreator = ({ dispatch, tableName }) => {
|
||||
const ColumnCreator = ({ dispatch, tableName, dataTypes: restTypes = [] }) => {
|
||||
const {
|
||||
colName,
|
||||
colType,
|
||||
@ -109,6 +108,30 @@ const ColumnCreator = ({ dispatch, tableName }) => {
|
||||
onSubmit,
|
||||
} = useColumnEditor(dispatch, tableName);
|
||||
|
||||
const { columnDataTypes, columnTypeValueMap } = getDataOptions(
|
||||
commonDataTypes,
|
||||
restTypes,
|
||||
0
|
||||
);
|
||||
|
||||
const customSelectBoxStyles = {
|
||||
container: {
|
||||
width: '186px',
|
||||
},
|
||||
dropdownIndicator: {
|
||||
padding: '5px',
|
||||
},
|
||||
placeholder: {
|
||||
top: '44%',
|
||||
fontSize: '12px',
|
||||
},
|
||||
singleValue: {
|
||||
fontSize: '12px',
|
||||
top: '44%',
|
||||
color: '#555555',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.activeEdit}>
|
||||
<form
|
||||
@ -122,17 +145,15 @@ const ColumnCreator = ({ dispatch, tableName }) => {
|
||||
data-test="column-name"
|
||||
{...colName}
|
||||
/>
|
||||
<select
|
||||
className={`${styles.select} input-sm form-control`}
|
||||
data-test="data-type"
|
||||
{...colType}
|
||||
>
|
||||
<option disabled value="">
|
||||
-- type --
|
||||
</option>
|
||||
{alterTypeOptions}
|
||||
</select>
|
||||
|
||||
<span className={`${styles.select}`} data-test="col-type-0">
|
||||
<SearchableSelectBox
|
||||
options={columnDataTypes}
|
||||
onChange={colType.onChange}
|
||||
value={colType.value && columnTypeValueMap[colType.value]}
|
||||
bsClass={`col-type-${0} modify_select`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
className={`${styles.input} ${styles.nullable} input-sm form-control`}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import dataTypes from '../Common/DataTypes';
|
||||
import { convertListToDictUsingKV } from '../../../../utils/data';
|
||||
|
||||
import SearchableSelectBox from '../../../Common/SearchableSelect/SearchableSelect';
|
||||
|
||||
/*
|
||||
import {
|
||||
INTEGER,
|
||||
SERIAL,
|
||||
@ -11,9 +13,10 @@ import {
|
||||
JSONB,
|
||||
TIMESTAMP,
|
||||
TIME,
|
||||
NUMERIC,
|
||||
TEXT,
|
||||
} from '../utils';
|
||||
} from '../../../../constants';
|
||||
*/
|
||||
|
||||
import { getValidAlterOptions } from './utils';
|
||||
|
||||
const ColumnEditor = ({
|
||||
onSubmit,
|
||||
@ -22,6 +25,7 @@ const ColumnEditor = ({
|
||||
columnProperties,
|
||||
selectedProperties,
|
||||
editColumn,
|
||||
alterTypeOptions,
|
||||
}) => {
|
||||
const colName = columnProperties.name;
|
||||
|
||||
@ -37,89 +41,40 @@ const ColumnEditor = ({
|
||||
}
|
||||
}, [columnComment]);
|
||||
|
||||
// filter the datatypes where hasuraDatatype === null
|
||||
const typeMap = convertListToDictUsingKV(
|
||||
'hasuraDatatype',
|
||||
'value',
|
||||
dataTypes.filter(dataType => dataType.hasuraDatatype)
|
||||
);
|
||||
|
||||
const getAlternateTypeOptions = columntype => {
|
||||
const generateOptions = datatypeOptions => {
|
||||
const options = [];
|
||||
|
||||
dataTypes.forEach(datatype => {
|
||||
if (datatypeOptions.includes(datatype.value)) {
|
||||
options.push(
|
||||
<option
|
||||
value={datatype.value}
|
||||
key={datatype.name}
|
||||
title={datatype.description}
|
||||
>
|
||||
{datatype.name}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let finalDefaultValue = typeMap[columnProperties.type];
|
||||
if (!finalDefaultValue) {
|
||||
finalDefaultValue = columnProperties.type;
|
||||
options.push(
|
||||
<option value={finalDefaultValue} key={finalDefaultValue}>
|
||||
{finalDefaultValue}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
const integerOptions = [INTEGER, SERIAL, BIGINT, BIGSERIAL, NUMERIC, TEXT];
|
||||
const bigintOptions = [BIGINT, BIGSERIAL, NUMERIC, TEXT];
|
||||
const uuidOptions = [UUID, TEXT];
|
||||
const jsonOptions = [JSON, JSONB, TEXT];
|
||||
const timestampOptions = [TIMESTAMP, TEXT];
|
||||
const timeOptions = [TIME, TEXT];
|
||||
|
||||
switch (columntype) {
|
||||
case INTEGER:
|
||||
return generateOptions(integerOptions);
|
||||
|
||||
case SERIAL:
|
||||
return generateOptions(integerOptions);
|
||||
|
||||
case BIGINT:
|
||||
return generateOptions(bigintOptions);
|
||||
|
||||
case BIGSERIAL:
|
||||
return generateOptions(bigintOptions);
|
||||
|
||||
case UUID:
|
||||
return generateOptions(uuidOptions);
|
||||
|
||||
case JSONDTYPE:
|
||||
return generateOptions(jsonOptions);
|
||||
|
||||
case JSONB:
|
||||
return generateOptions(jsonOptions);
|
||||
|
||||
case TIMESTAMP:
|
||||
return generateOptions(timestampOptions);
|
||||
|
||||
case TIME:
|
||||
return generateOptions(timeOptions);
|
||||
|
||||
default:
|
||||
return generateOptions([columntype, TEXT]);
|
||||
}
|
||||
const getColumnType = () => {
|
||||
return (
|
||||
colName in selectedProperties &&
|
||||
'type' in selectedProperties[colName] &&
|
||||
selectedProperties[colName].type
|
||||
);
|
||||
};
|
||||
const columnTypePG = getColumnType();
|
||||
|
||||
const customSelectBoxStyles = {
|
||||
dropdownIndicator: {
|
||||
padding: '5px',
|
||||
},
|
||||
placeholder: {
|
||||
top: '44%',
|
||||
fontSize: '12px',
|
||||
},
|
||||
singleValue: {
|
||||
fontSize: '12px',
|
||||
top: '44%',
|
||||
color: '#555555',
|
||||
},
|
||||
};
|
||||
|
||||
const { alterOptions, alterOptionsValueMap } = getValidAlterOptions(
|
||||
alterTypeOptions,
|
||||
colName
|
||||
);
|
||||
|
||||
const updateColumnName = e => {
|
||||
dispatch(editColumn(colName, 'name', e.target.value));
|
||||
};
|
||||
const updateColumnType = e => {
|
||||
dispatch(editColumn(colName, 'type', e.target.value));
|
||||
const updateColumnType = selected => {
|
||||
dispatch(editColumn(colName, 'type', selected.value));
|
||||
};
|
||||
const updateColumnDef = e => {
|
||||
dispatch(editColumn(colName, 'default', e.target.value));
|
||||
@ -152,14 +107,13 @@ const ColumnEditor = ({
|
||||
<div className={`${styles.display_flex} form-group`}>
|
||||
<label className="col-xs-2">Type</label>
|
||||
<div className="col-xs-6">
|
||||
<select
|
||||
value={selectedProperties[colName].type}
|
||||
<SearchableSelectBox
|
||||
options={alterOptions}
|
||||
onChange={updateColumnType}
|
||||
className="input-sm form-control"
|
||||
disabled={columnProperties.pkConstraint}
|
||||
>
|
||||
{getAlternateTypeOptions(columnProperties.type)}
|
||||
</select>
|
||||
value={columnTypePG && alterOptionsValueMap[columnTypePG]}
|
||||
bsClass={`col-type-${0} modify_select`}
|
||||
styleOverrides={customSelectBoxStyles}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${styles.display_flex} form-group`}>
|
||||
|
@ -20,6 +20,8 @@ const ColumnEditorList = ({
|
||||
columnEdit,
|
||||
dispatch,
|
||||
columnComments,
|
||||
//
|
||||
validTypeCasts,
|
||||
}) => {
|
||||
const tableName = tableSchema.table_name;
|
||||
|
||||
@ -39,6 +41,9 @@ const ColumnEditorList = ({
|
||||
|
||||
const columns = tableSchema.columns.sort(ordinalColSort);
|
||||
|
||||
/*
|
||||
* col.udt_name contains internal representation of the data type
|
||||
* */
|
||||
return columns.map((col, i) => {
|
||||
const colName = col.column_name;
|
||||
|
||||
@ -46,7 +51,9 @@ const ColumnEditorList = ({
|
||||
name: colName,
|
||||
tableName: col.table_name,
|
||||
schemaName: col.table_schema,
|
||||
type: col.data_type !== 'USER-DEFINED' ? col.data_type : col.udt_name,
|
||||
display_type_name:
|
||||
col.data_type !== 'USER-DEFINED' ? col.data_type : col.udt_name,
|
||||
type: col.udt_name,
|
||||
isNullable: col.is_nullable === 'YES',
|
||||
pkConstraint: columnPKConstraints[colName],
|
||||
isUnique: columnUniqueConstraints[colName] ? true : false,
|
||||
@ -79,7 +86,7 @@ const ColumnEditorList = ({
|
||||
const keyProperties = () => {
|
||||
const propertiesList = [];
|
||||
|
||||
propertiesList.push(columnProperties.type);
|
||||
propertiesList.push(columnProperties.display_type_name);
|
||||
|
||||
if (columnProperties.pkConstraint) {
|
||||
propertiesList.push('primary key');
|
||||
@ -121,6 +128,7 @@ const ColumnEditorList = ({
|
||||
const colEditorExpanded = () => {
|
||||
return (
|
||||
<ColumnEditor
|
||||
alterTypeOptions={validTypeCasts[col.udt_name]}
|
||||
column={col}
|
||||
onSubmit={onSubmit}
|
||||
onDelete={safeOnDelete}
|
||||
|
@ -26,6 +26,8 @@ import {
|
||||
getUniqueConstraintName,
|
||||
} from '../Common/ReusableComponents/utils';
|
||||
|
||||
import { fetchColumnCastsQuery, convertArrayToJson } from './utils';
|
||||
|
||||
const DELETE_PK_WARNING =
|
||||
'Without a Primary key there is no way to uniquely identify a row of a table. Are you sure?';
|
||||
|
||||
@ -50,6 +52,8 @@ const SET_FOREIGN_KEYS = 'ModifyTable/SET_FOREIGN_KEYS';
|
||||
const SAVE_FOREIGN_KEY = 'ModifyTable/SAVE_FOREIGN_KEY';
|
||||
const REMOVE_FOREIGN_KEY = 'ModifyTable/REMOVE_FOREIGN_KEY';
|
||||
|
||||
const FETCH_COLUMN_TYPE_CASTS = 'ModifyTable/FETCH_COLUMN_TYPE_CASTS';
|
||||
const FETCH_COLUMN_TYPE_CASTS_FAIL = 'ModifyTable/FETCH_COLUMN_TYPE_CASTS_FAIL';
|
||||
const SET_UNIQUE_KEYS = 'ModifyTable/SET_UNIQUE_KEYS';
|
||||
const SAVE_UNIQUE_KEY = 'ModifyTable/SAVE_UNIQUE_KEY';
|
||||
const REMOVE_UNIQUE_KEY = 'ModifyTable/REMOVE_UNIQUE_KEY';
|
||||
@ -1616,6 +1620,46 @@ const saveColumnChangesSql = (colName, column) => {
|
||||
};
|
||||
};
|
||||
|
||||
const fetchColumnCasts = () => {
|
||||
return (dispatch, getState) => {
|
||||
const url = Endpoints.getSchema;
|
||||
const reqQuery = {
|
||||
type: 'run_sql',
|
||||
args: {
|
||||
sql: fetchColumnCastsQuery,
|
||||
},
|
||||
};
|
||||
const options = {
|
||||
credentials: globalCookiePolicy,
|
||||
method: 'POST',
|
||||
headers: dataHeaders(getState),
|
||||
body: JSON.stringify(reqQuery),
|
||||
};
|
||||
return dispatch(requestAction(url, options)).then(
|
||||
data => {
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_CASTS,
|
||||
data: convertArrayToJson(data.result.slice(1)),
|
||||
});
|
||||
},
|
||||
error => {
|
||||
dispatch(
|
||||
showErrorNotification(
|
||||
'Error fetching column casts information',
|
||||
'Kindly reach out to us in case you face this issue again',
|
||||
error,
|
||||
error
|
||||
)
|
||||
);
|
||||
return dispatch({
|
||||
type: FETCH_COLUMN_TYPE_CASTS_FAIL,
|
||||
data: error,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const removeUniqueKey = (index, tableName, existingConstraints, callback) => {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({ type: REMOVE_UNIQUE_KEY });
|
||||
@ -1802,6 +1846,8 @@ const saveUniqueKey = (
|
||||
};
|
||||
|
||||
export {
|
||||
FETCH_COLUMN_TYPE_CASTS,
|
||||
FETCH_COLUMN_TYPE_CASTS_FAIL,
|
||||
VIEW_DEF_REQUEST_SUCCESS,
|
||||
VIEW_DEF_REQUEST_ERROR,
|
||||
SET_COLUMN_EDIT,
|
||||
@ -1843,6 +1889,7 @@ export {
|
||||
setForeignKeys,
|
||||
saveForeignKeys,
|
||||
removeForeignKey,
|
||||
fetchColumnCasts,
|
||||
setUniqueKeys,
|
||||
removeUniqueKey,
|
||||
saveUniqueKey,
|
||||
|
@ -1,13 +1,20 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import TableHeader from '../TableCommon/TableHeader';
|
||||
|
||||
import {
|
||||
deleteTableSql,
|
||||
untrackTableSql,
|
||||
RESET,
|
||||
fetchColumnCasts,
|
||||
setUniqueKeys,
|
||||
} from '../TableModify/ModifyActions';
|
||||
import { setTable, fetchTableComment } from '../DataActions';
|
||||
import {
|
||||
setTable,
|
||||
fetchTableComment,
|
||||
fetchColumnTypes,
|
||||
RESET_COLUMN_TYPE_LIST,
|
||||
} from '../DataActions';
|
||||
import Button from '../../../Common/Button/Button';
|
||||
import ColumnEditorList from './ColumnEditorList';
|
||||
import ColumnCreator from './ColumnCreator';
|
||||
@ -23,8 +30,14 @@ class ModifyTable extends React.Component {
|
||||
dispatch({ type: RESET });
|
||||
dispatch(setTable(this.props.tableName));
|
||||
dispatch(fetchTableComment(this.props.tableName));
|
||||
dispatch(fetchColumnTypes());
|
||||
dispatch(fetchColumnCasts());
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch({
|
||||
type: RESET_COLUMN_TYPE_LIST,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tableName,
|
||||
@ -38,8 +51,11 @@ class ModifyTable extends React.Component {
|
||||
columnEdit,
|
||||
pkModify,
|
||||
fkModify,
|
||||
dataTypes,
|
||||
validTypeCasts,
|
||||
uniqueKeyModify,
|
||||
} = this.props;
|
||||
|
||||
const tableSchema = allSchemas.find(t => t.table_name === tableName);
|
||||
|
||||
const untrackBtn = (
|
||||
@ -77,6 +93,7 @@ class ModifyTable extends React.Component {
|
||||
</Button>
|
||||
);
|
||||
|
||||
// if (tableSchema.primary_key.columns > 0) {}
|
||||
return (
|
||||
<div className={`${styles.container} container-fluid`}>
|
||||
<TableHeader
|
||||
@ -102,6 +119,7 @@ class ModifyTable extends React.Component {
|
||||
/>
|
||||
<h4 className={styles.subheading_text}>Columns</h4>
|
||||
<ColumnEditorList
|
||||
validTypeCasts={validTypeCasts}
|
||||
tableSchema={tableSchema}
|
||||
columnEdit={columnEdit}
|
||||
columnComments={columnComments}
|
||||
@ -110,7 +128,11 @@ class ModifyTable extends React.Component {
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Add a new column</h4>
|
||||
<ColumnCreator dispatch={dispatch} tableName={tableName} />
|
||||
<ColumnCreator
|
||||
dispatch={dispatch}
|
||||
tableName={tableName}
|
||||
dataTypes={dataTypes}
|
||||
/>
|
||||
<hr />
|
||||
<h4 className={styles.subheading_text}>Primary Key</h4>
|
||||
<PrimaryKeyEditor
|
||||
@ -182,6 +204,9 @@ const mapStateToProps = (state, ownProps) => ({
|
||||
columnEdit: state.tables.modify.columnEdit,
|
||||
pkModify: state.tables.modify.pkModify,
|
||||
fkModify: state.tables.modify.fkModify,
|
||||
dataTypes: state.tables.columnDataTypes,
|
||||
validTypeCasts: state.tables.modify.alterColumnOptions,
|
||||
columnDataTypeFetchErr: state.tables.columnDataTypeFetchErr,
|
||||
...state.tables.modify,
|
||||
});
|
||||
|
||||
|
@ -47,6 +47,11 @@
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.column_type_select {
|
||||
width: 200px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.modifyMinWidth {
|
||||
min-width: 735px;
|
||||
}
|
||||
@ -250,7 +255,7 @@ hr {
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
margin-bottom: 15px;
|
||||
overflow: auto;
|
||||
// overflow: auto;
|
||||
|
||||
.editPermsHeading {
|
||||
font-weight: bold;
|
||||
|
62
console/src/components/Services/Data/TableModify/utils.js
Normal file
62
console/src/components/Services/Data/TableModify/utils.js
Normal file
@ -0,0 +1,62 @@
|
||||
import { getDataTypeInfo } from '../Common/utils';
|
||||
|
||||
const convertArrayToJson = (arr, keyIndex = 0) => {
|
||||
const converted = {};
|
||||
arr.forEach(a => {
|
||||
converted[a[keyIndex]] = a;
|
||||
});
|
||||
return converted;
|
||||
};
|
||||
|
||||
const getValidAlterOptions = (alterTypeOptions, colName) => {
|
||||
const { typInfo: currentInfo, typValueMap: currentMap } = getDataTypeInfo(
|
||||
alterTypeOptions.slice(0, 3),
|
||||
colName,
|
||||
0
|
||||
);
|
||||
|
||||
const {
|
||||
typInfo: validOptions,
|
||||
typValueMap: validOptionsMap,
|
||||
} = getDataTypeInfo(alterTypeOptions.slice(3, 6), colName, 0);
|
||||
|
||||
const allInfo = [...currentInfo, ...validOptions];
|
||||
const allOptionsMap = {
|
||||
...validOptionsMap,
|
||||
...currentMap,
|
||||
};
|
||||
return {
|
||||
alterOptions: allInfo,
|
||||
alterOptionsValueMap: allOptionsMap,
|
||||
};
|
||||
};
|
||||
|
||||
const fetchColumnCastsQuery = `
|
||||
SELECT ts.typname AS "Source Type",
|
||||
pg_catalog.format_type(castsource, NULL) AS "Source Info",
|
||||
pg_catalog.obj_description(castsource, 'pg_type') as "Source Descriptions",
|
||||
string_agg(tt.typname, ',') AS "Target Type",
|
||||
string_agg(pg_catalog.format_type(casttarget, NULL), ',') AS "Target Info",
|
||||
string_agg(pg_catalog.obj_description(casttarget, 'pg_type'), ':') as "Target Descriptions",
|
||||
string_agg(CASE WHEN castfunc = 0 THEN '(binary coercible)'
|
||||
ELSE p.proname
|
||||
END, ',') as "Function"
|
||||
FROM pg_catalog.pg_cast c LEFT JOIN pg_catalog.pg_proc p
|
||||
ON c.castfunc = p.oid
|
||||
LEFT JOIN pg_catalog.pg_type ts
|
||||
ON c.castsource = ts.oid
|
||||
LEFT JOIN pg_catalog.pg_namespace ns
|
||||
ON ns.oid = ts.typnamespace
|
||||
LEFT JOIN pg_catalog.pg_type tt
|
||||
ON c.casttarget = tt.oid
|
||||
LEFT JOIN pg_catalog.pg_namespace nt
|
||||
ON nt.oid = tt.typnamespace
|
||||
WHERE ( (true AND pg_catalog.pg_type_is_visible(ts.oid)
|
||||
) OR (true AND pg_catalog.pg_type_is_visible(tt.oid)
|
||||
) ) AND (c.castcontext != 'e') AND ts.typname != tt.typname
|
||||
GROUP BY ts.typname, castsource
|
||||
ORDER BY 1, 2;
|
||||
|
||||
`;
|
||||
|
||||
export { convertArrayToJson, getValidAlterOptions, fetchColumnCastsQuery };
|
@ -51,11 +51,7 @@ const permChangeTypes = {
|
||||
delete: 'delete',
|
||||
};
|
||||
|
||||
const permOpenEdit = (
|
||||
tableSchema,
|
||||
role,
|
||||
query,
|
||||
) => ({
|
||||
const permOpenEdit = (tableSchema, role, query) => ({
|
||||
type: PERM_OPEN_EDIT,
|
||||
tableSchema,
|
||||
role,
|
||||
@ -118,11 +114,7 @@ const getFilterKey = query => {
|
||||
return query === 'insert' ? 'check' : 'filter';
|
||||
};
|
||||
|
||||
const getBasePermissionsState = (
|
||||
tableSchema,
|
||||
role,
|
||||
query,
|
||||
) => {
|
||||
const getBasePermissionsState = (tableSchema, role, query) => {
|
||||
const _permissions = JSON.parse(JSON.stringify(defaultPermissionsState));
|
||||
|
||||
_permissions.table = tableSchema.table_name;
|
||||
@ -140,9 +132,7 @@ const getBasePermissionsState = (
|
||||
if (q === 'insert' || q === 'update') {
|
||||
// If set is an object
|
||||
if (!_permissions[q].columns) {
|
||||
_permissions[q].columns = tableSchema.columns.map(
|
||||
c => c.column_name
|
||||
);
|
||||
_permissions[q].columns = tableSchema.columns.map(c => c.column_name);
|
||||
}
|
||||
if ('set' in _permissions[q]) {
|
||||
if (
|
||||
|
@ -638,9 +638,9 @@ class PermissionBuilder extends React.Component {
|
||||
|
||||
const columnOptions = tableColumns.concat(tableRelationships);
|
||||
|
||||
const operatorOptions = columnOptions
|
||||
const operatorOptions = boolOperators
|
||||
.concat(['---'])
|
||||
.concat(boolOperators);
|
||||
.concat(columnOptions);
|
||||
|
||||
const _boolExpKey = renderSelect(
|
||||
dispatchOperationSelect,
|
||||
|
@ -179,3 +179,93 @@ export const getTableName = t => {
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
export const commonDataTypes = [
|
||||
{
|
||||
name: 'Integer',
|
||||
value: 'integer',
|
||||
description: 'signed four-byte integer',
|
||||
hasuraDatatype: 'integer',
|
||||
},
|
||||
{
|
||||
name: 'Integer (auto-increment)',
|
||||
value: 'serial',
|
||||
description: 'autoincrementing four-byte integer',
|
||||
hasuraDatatype: null,
|
||||
},
|
||||
{
|
||||
name: 'UUID',
|
||||
value: 'uuid',
|
||||
description: 'universal unique identifier',
|
||||
hasuraDatatype: 'uuid',
|
||||
},
|
||||
{
|
||||
name: 'Big Integer',
|
||||
value: 'bigint',
|
||||
description: 'signed eight-byte integer',
|
||||
hasuraDatatype: 'bigint',
|
||||
},
|
||||
{
|
||||
name: 'Big Integer (auto-increment)',
|
||||
value: 'bigserial',
|
||||
description: 'autoincrementing eight-byte integer',
|
||||
hasuraDatatype: null,
|
||||
},
|
||||
{
|
||||
name: 'Text',
|
||||
value: 'text',
|
||||
description: 'variable-length character string',
|
||||
hasuraDatatype: 'text',
|
||||
},
|
||||
{
|
||||
name: 'Numeric',
|
||||
value: 'numeric',
|
||||
description: 'exact numeric of selected precision',
|
||||
hasuraDatatype: 'numeric',
|
||||
},
|
||||
{
|
||||
name: 'Date',
|
||||
value: 'date',
|
||||
description: 'calendar date (year, month, day)',
|
||||
hasuraDatatype: 'date',
|
||||
},
|
||||
{
|
||||
name: 'Timestamp',
|
||||
value: 'timestamptz',
|
||||
description: 'date and time, including time zone',
|
||||
hasuraDatatype: 'timestamp with time zone',
|
||||
},
|
||||
{
|
||||
name: 'Time',
|
||||
value: 'timetz',
|
||||
description: 'time of day (no time zone)',
|
||||
hasuraDatatype: 'time with time zone',
|
||||
},
|
||||
{
|
||||
name: 'Boolean',
|
||||
value: 'boolean',
|
||||
description: 'logical Boolean (true/false)',
|
||||
hasuraDatatype: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'JSONB',
|
||||
value: 'jsonb',
|
||||
description: 'binary format JSON data',
|
||||
hasuraDatatype: 'jsonb',
|
||||
},
|
||||
];
|
||||
|
||||
export const fetchColumnTypesQuery = `
|
||||
SELECT
|
||||
string_agg(t.typname, ',') as "Type Name",
|
||||
string_agg(pg_catalog.format_type(t.oid, NULL), ',') as "Display Name",
|
||||
string_agg(pg_catalog.obj_description(t.oid, 'pg_type'), ':') as "Descriptions",
|
||||
t.typcategory
|
||||
FROM pg_catalog.pg_type t
|
||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
|
||||
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
|
||||
AND pg_catalog.pg_type_is_visible(t.oid)
|
||||
AND t.typname != 'unknown'
|
||||
AND t.typcategory != 'P'
|
||||
GROUP BY t.typcategory;`;
|
||||
|
@ -81,6 +81,11 @@ class WebhookEditor extends React.Component {
|
||||
}
|
||||
testId="webhook"
|
||||
/>
|
||||
<br />
|
||||
<small>
|
||||
Note: Specifying the webhook URL via an environmental variable is
|
||||
recommended if you have different URLs for multiple environments.
|
||||
</small>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -266,7 +266,8 @@ const ViewRows = ({
|
||||
// Insert cells corresponding to all rows
|
||||
invocationColumns.forEach(col => {
|
||||
const getCellContent = () => {
|
||||
let conditionalClassname = styles.tableCellCenterAlignedOverflow;
|
||||
let conditionalClassname =
|
||||
styles.tableCellCenterAlignedOverflow;
|
||||
const cellIndex = `${curTriggerName}-${col}-${rowIndex}`;
|
||||
if (expandedRow === cellIndex) {
|
||||
conditionalClassname = styles.tableCellExpanded;
|
||||
|
@ -288,7 +288,8 @@ const ViewRows = ({
|
||||
// Insert cells corresponding to all rows
|
||||
invocationColumns.forEach(col => {
|
||||
const getCellContent = () => {
|
||||
let conditionalClassname = styles.tableCellCenterAlignedOverflow;
|
||||
let conditionalClassname =
|
||||
styles.tableCellCenterAlignedOverflow;
|
||||
const cellIndex = `${curTriggerName}-${col}-${rowIndex}`;
|
||||
if (expandedRow === cellIndex) {
|
||||
conditionalClassname = styles.tableCellExpanded;
|
||||
|
@ -93,7 +93,9 @@ class RedeliverEvent extends Component {
|
||||
r.status === 200 ? (
|
||||
<i
|
||||
className={
|
||||
styles.invocationSuccess + ' fa fa-check invocationsSuccess ' + styles.tabletdCenter
|
||||
styles.invocationSuccess +
|
||||
' fa fa-check invocationsSuccess ' +
|
||||
styles.tabletdCenter
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
@ -212,7 +214,13 @@ class RedeliverEvent extends Component {
|
||||
<Modal.Body>
|
||||
<div className="content-fluid">
|
||||
<div>
|
||||
<div className={styles.padd_left_remove + ' col-md-12 ' + styles.padd_right_remove} >
|
||||
<div
|
||||
className={
|
||||
styles.padd_left_remove +
|
||||
' col-md-12 ' +
|
||||
styles.padd_right_remove
|
||||
}
|
||||
>
|
||||
<div className={styles.add_mar_bottom}>
|
||||
Event ID - {log.redeliverEventId}
|
||||
<Button
|
||||
|
16
console/src/theme/bootstrap.overrides.scss
vendored
16
console/src/theme/bootstrap.overrides.scss
vendored
@ -7,6 +7,22 @@
|
||||
.hljs{display:block;overflow-x:auto;padding:0.5em;background:#F0F0F0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888888}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
|
||||
/* */
|
||||
|
||||
// react select overrides: start
|
||||
.modify_select__control {
|
||||
min-height: 30px !important;
|
||||
max-height: 30px !important;
|
||||
}
|
||||
|
||||
.add_table_column_selector__control {
|
||||
min-height: 34px !important;
|
||||
max-height: 34px !important;
|
||||
}
|
||||
|
||||
.react-selectable__single-value, .react-selectable__placeholder, .react-selectable__indicator.react-selectable__dropdown-indicator {
|
||||
margin-top: -2px;
|
||||
}
|
||||
// react select overrides: end
|
||||
|
||||
input[type="radio"], input[type="checkbox"] {
|
||||
margin: 0 5px 0px 0px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user