console: add pagination on rawsql results page

GITHUB_PR_NUMBER: 5629
GITHUB_PR_URL: https://github.com/hasura/graphql-engine/pull/5629

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

Co-authored-by: Sooraj <8408875+soorajshankar@users.noreply.github.com>
GitOrigin-RevId: 9bf8c6f9068fc04160e9e9ebce2600b30e523a90
This commit is contained in:
hasura-bot 2021-07-22 15:27:30 +05:30
parent 6323f4f7b1
commit 2814934cf7
6 changed files with 114 additions and 47 deletions

View File

@ -5,6 +5,7 @@
- server: Fixing bug in ReplaceMetadata parser - Moving from Alternative to committed-choice.
- server: Relax the unique operation name constraint when adding a query to a query collection
- console: add pagination on the Raw SQL results page
## v2.0.3
(Add entries below in the order of server, console, cli, docs, others)

View File

@ -32,13 +32,32 @@ export const passCreateTable = () => {
export const passInsertValues = () => {
clearText();
prevStr = 'INSERT INTO Apic_test_table_rsql VALUES (1);';
cy.get('textarea').type(prevStr, { force: true });
// eslint-disable-next-line prefer-spread
const str = Array.apply(null, Array(15))
.map(
(_, ix: number) => `INSERT INTO Apic_test_table_rsql VALUES (${+ix + 1});`
)
.join('\n');
cy.get('textarea').type(str, { force: true });
cy.wait(1000);
cy.get(getElementFromAlias('run-sql')).click();
cy.wait(5000);
};
export const readQuery = () => {
clearText();
prevStr = 'SELECT * FROM public.Apic_test_table_rsql;';
cy.get('textarea').type(prevStr, { force: true });
cy.wait(1000); // debounce
cy.get(getElementFromAlias('run-sql')).click();
cy.wait(3000); // debounce
cy.get('div.rt-tr-group').should('have.length', 10);
cy.get('button.-btn').last().click();
cy.wait(500);
cy.get('div.rt-tr-group').should('have.length', 5);
cy.get('div.rt-td').first().should('have.text', '11');
cy.get('div.rt-td').last().should('have.text', "NULL");
};
export const passAlterTable = () => {
clearText();
prevStr = 'ALTER TABLE Apic_test_table_rsql ADD COLUMN name text;';

View File

@ -5,6 +5,7 @@ import {
passCreateView,
passInsertValues,
passAlterTable,
readQuery,
} from './spec';
import { testMode } from '../../../helpers/common';
import { setMetaData } from '../../validators/validators';
@ -28,6 +29,7 @@ export const runRawSQLTests = () => {
it('Pass create table', passCreateTable);
it('Pass insert values', passInsertValues);
it('Pass alter table', passAlterTable);
it('Read from table', readQuery);
it('Pass create view', passCreateView);
it('Delete test table', delTestTables);
});

View File

@ -123,6 +123,10 @@
overflow: unset;
}
.result-table .rt-table {
overflow: auto;
}
.ReactTable .rt-table .rt-tbody {
margin-bottom: 10px;
border: solid 1px rgba(0, 0, 0, 0.05);

View File

@ -27,6 +27,7 @@ import {
} from '../../../Common/AceEditor/utils';
import { CLI_CONSOLE_MODE } from '../../../../constants';
import NotesSection from './molecules/NotesSection';
import ResultTable from './ResultTable';
import { getLSItem, setLSItem, LS_KEYS } from '../../../../utils/localStorage';
import DropDownSelector from './DropDownSelector';
import { getSourceDriver } from '../utils';
@ -279,50 +280,6 @@ const RawSQL = ({
);
};
const getResultTable = () => {
let resultTable = null;
if (resultType && resultType !== 'command') {
const getTableHeadings = () => {
return resultHeaders.map((columnName, i) => (
<th key={i}>{columnName}</th>
));
};
const getRows = () => {
return result.map((row, i) => (
<tr key={i}>
{row.map((columnValue, j) => (
<td key={j}>{columnValue}</td>
))}
</tr>
));
};
resultTable = (
<div
className={`${styles.addCol} col-xs-12 ${styles.padd_left_remove}`}
>
<h4 className={styles.subheading_text}>SQL Result:</h4>
<div className={styles.tableContainer}>
<table
className={`table table-bordered table-striped table-hover ${styles.table} `}
>
<thead>
<tr>{getTableHeadings()}</tr>
</thead>
<tbody>{getRows()}</tbody>
</table>
</div>
<br />
<br />
</div>
);
}
return resultTable;
};
const getMetadataCascadeSection = () => {
return (
<div className={styles.add_mar_top_small}>
@ -547,7 +504,14 @@ const RawSQL = ({
{getMigrationWarningModal()}
<div className={styles.add_mar_bottom}>{getResultTable()}</div>
<div className={styles.add_mar_bottom}>
{resultType &&
resultType !== 'command' &&
result &&
result?.length > 0 && (
<ResultTable rows={result} headers={resultHeaders} />
)}
</div>
</div>
);
};

View File

@ -0,0 +1,77 @@
import React, { useMemo, ReactElement, ReactText } from 'react';
import ReactTable from 'react-table';
import { getColWidth } from '../../../Common/TableCommon/DragFoldTable';
import styles from '../../../Common/TableCommon/Table.scss';
interface ResultTableProps {
headers: string[];
rows: Array<string[]>;
}
const getColCellContent = (rowColumnValue: ReactText) => {
let cellValue: React.ReactText | ReactElement = '';
let cellTitle: React.ReactText | ReactElement = '';
if (rowColumnValue === null) {
cellValue = <i>NULL</i>;
cellTitle = 'NULL';
} else if (rowColumnValue === undefined) {
cellValue = 'NULL';
cellTitle = cellValue;
} else if (typeof rowColumnValue === 'object') {
cellValue = JSON.stringify(rowColumnValue, null, 4);
cellTitle = cellValue;
} else {
cellValue = rowColumnValue.toString();
cellTitle = cellValue;
}
return (
<div className={styles.wd100} title={cellTitle}>
{cellValue}
</div>
);
};
const getTableConfig = (headers: string[], rows: Array<string[]>) => {
const dataMap: Record<string, any>[] = [];
const data = rows.map(i => {
const result: Record<string, any> = {};
const resultMap: Record<string, any> = {};
headers.forEach((hdr, hIndex) => {
result[hdr] = getColCellContent(i[hIndex]);
resultMap[hdr] = i[hIndex];
});
dataMap.push(resultMap);
return result;
});
const columns = headers.map(i => ({
Header: i,
accessor: i,
minWidth: Math.ceil(getColWidth(i, dataMap)),
}));
return { columns, data };
};
const ResultTable: React.FC<ResultTableProps> = ({ headers, rows }) => {
const tableConfig = useMemo(() => getTableConfig(headers, rows), [
headers,
rows,
]);
return (
<div className={`${styles.addCol} col-xs-12 ${styles.padd_left_remove}`}>
<h4 className={styles.subheading_text}>SQL Result:</h4>
<div className={styles.tableContainer}>
<ReactTable
{...tableConfig}
minRows={0} // if selected pagination is 100 and there are only 56 rows, hide empty rows
defaultPageSize={rows.length > 10 ? 10 : rows.length}
className="-striped -highlight result-table"
/>
</div>
<br />
</div>
);
};
export default ResultTable;