mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
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:
parent
6323f4f7b1
commit
2814934cf7
@ -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)
|
||||
|
@ -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;';
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
77
console/src/components/Services/Data/RawSQL/ResultTable.tsx
Normal file
77
console/src/components/Services/Data/RawSQL/ResultTable.tsx
Normal 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;
|
Loading…
Reference in New Issue
Block a user