From bcb46c863d6cbffd6dc8e9efa1d6679f339b8763 Mon Sep 17 00:00:00 2001 From: Luca Restagno <59067245+lucarestagno@users.noreply.github.com> Date: Thu, 22 Dec 2022 15:29:20 +0100 Subject: [PATCH] [GCU-50] Export to CSV or JSON PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7359 GitOrigin-RevId: d0ebde91206e5ba750301151ddd2ee283fb31be4 --- .../components/DataGrid/DataGrid.tsx | 15 ++ .../components/DataGrid/QueryDialog.tsx | 4 + .../parts/DataTableOptions.stories.tsx | 4 + .../DataGrid/parts/DataTableOptions.tsx | 185 ++++++++++++------ .../src/features/BrowseRows/hooks/index.ts | 4 + .../hooks/useExportRows/useExportRows.test.ts | 22 +-- .../hooks/useExportRows/useExportRows.ts | 22 ++- console/src/features/BrowseRows/index.tsx | 1 + console/src/new-components/Button/Button.tsx | 2 +- .../new-components/Dialog/Dialog.stories.tsx | 3 + console/src/new-components/Dialog/Dialog.tsx | 14 +- 11 files changed, 186 insertions(+), 90 deletions(-) diff --git a/console/src/features/BrowseRows/components/DataGrid/DataGrid.tsx b/console/src/features/BrowseRows/components/DataGrid/DataGrid.tsx index 006cc839670..d428a4494c5 100644 --- a/console/src/features/BrowseRows/components/DataGrid/DataGrid.tsx +++ b/console/src/features/BrowseRows/components/DataGrid/DataGrid.tsx @@ -28,6 +28,7 @@ import { ReactTableWrapper } from './parts/ReactTableWrapper'; import { QueryDialog } from './QueryDialog'; import { useRows, useTableColumns } from '../../hooks'; import { transformToOrderByClause } from './utils'; +import { useExportRows } from '../../hooks/useExportRows/useExportRows'; export type DataGridOptions = { where?: WhereClause[]; @@ -144,6 +145,19 @@ export const DataGrid = (props: DataGridProps) => { }); }, [pageIndex, pageSize]); + const columnNames = (tableColumnQueryResult?.columns || []).map( + column => column.name + ); + const { onExportRows } = useExportRows({ + columns: columnNames, + dataSourceName, + options: { + where: whereClauses, + order_by: orderByClauses, + }, + table, + }); + const handleOnRelationshipClick = ({ relationship, rowData, @@ -273,6 +287,7 @@ export const DataGrid = (props: DataGridProps) => { removeOrderByClause: id => { setOrderClauses(orderByClauses.filter((_, i) => i !== id)); }, + onExportRows, }} /> diff --git a/console/src/features/BrowseRows/components/DataGrid/QueryDialog.tsx b/console/src/features/BrowseRows/components/DataGrid/QueryDialog.tsx index 45905ea1060..491c4e0176e 100644 --- a/console/src/features/BrowseRows/components/DataGrid/QueryDialog.tsx +++ b/console/src/features/BrowseRows/components/DataGrid/QueryDialog.tsx @@ -5,6 +5,7 @@ import { useConsoleForm } from '@/new-components/Form'; import React from 'react'; import { UseFormTrigger } from 'react-hook-form'; import { z } from 'zod'; +import { RiPlayFill } from 'react-icons/ri'; import { FilterRows } from '../RunQuery/Filter'; import { SortRows } from '../RunQuery/Sort'; import { useTableColumns } from '../../hooks/useTableColumns'; @@ -141,6 +142,9 @@ export const QueryDialog = ({ } + callToDeny="Cancel" onClose={onClose} onSubmit={() => onSubmitHandler()} /> diff --git a/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.stories.tsx b/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.stories.tsx index 52fad7b6ec8..09320edfe63 100644 --- a/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.stories.tsx +++ b/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.stories.tsx @@ -73,6 +73,10 @@ const ComponentWrapper = () => { removeOrderByClause: id => { setOrderClauses(orderByClauses.filter((_, i) => i !== id)); }, + onExportRows: exportFileFormat => { + updateStatus(`export to ${exportFileFormat}`); + return Promise.resolve(new Error()); + }, }} />
{status}
diff --git a/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.tsx b/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.tsx index a8f8dc49c69..bae74cb681c 100644 --- a/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.tsx +++ b/console/src/features/BrowseRows/components/DataGrid/parts/DataTableOptions.tsx @@ -1,17 +1,22 @@ import { Operator, OrderBy, WhereClause } from '@/features/DataSource'; import { Badge } from '@/new-components/Badge'; import { Button } from '@/new-components/Button'; +import { DropdownButton } from '@/new-components/DropdownButton'; +import { UseExportRowsReturn } from '@/features/BrowseRows'; import clsx from 'clsx'; -import React from 'react'; +import React, { useState } from 'react'; import { FaChevronLeft, FaChevronRight, - FaSearch, - FaUndo, - FaRegTimesCircle, - FaSortAmountUpAlt, + FaFileExport, FaFilter, + FaRegTimesCircle, + FaSearch, + FaSortAmountUpAlt, + FaTimes, } from 'react-icons/fa'; +import type { ExportFileFormat } from '@/features/BrowseRows'; +import { useFireNotification } from '@/new-components/Notifications'; import { DEFAULT_PAGE_SIZES } from '../constants'; interface DataTableOptionsProps { @@ -24,6 +29,7 @@ interface DataTableOptionsProps { removeWhereClause: (id: number) => void; removeOrderByClause: (id: number) => void; disableRunQuery?: boolean; + onExportRows: UseExportRowsReturn['onExportRows']; }; pagination: { goToPreviousPage: () => void; @@ -44,24 +50,27 @@ const DisplayWhereClauses = ({ operatorMap: Record; removeWhereClause: (id: number) => void; }) => { + const twFlexCenter = 'flex items-center'; return ( <> {whereClauses.map((whereClause, id) => { const [columnName, rest] = Object.entries(whereClause)[0]; const [operator, value] = Object.entries(rest)[0]; return ( - -
- - + +
+ + + + {columnName} {operatorMap[operator]} {value} - { - removeWhereClause(id); - }} - /> + + removeWhereClause(id)} + /> +
); @@ -77,21 +86,24 @@ const DisplayOrderByClauses = ({ orderByClauses: OrderBy[]; removeOrderByClause: (id: number) => void; }) => { + const twFlexCenter = 'flex items-center'; return ( <> {orderByClauses.map((orderByClause, id) => ( - -
- - + +
+ + + + {orderByClause.column} ({orderByClause.type}) - { - removeOrderByClause(id); - }} - /> + + removeOrderByClause(id)} + /> +
))} @@ -110,55 +122,101 @@ export const DataTableOptions = (props: DataTableOptionsProps) => { const totalQueriesApplied = query.whereClauses.length + query.orderByClauses.length; + + const { fireNotification } = useFireNotification(); + const [isExporting, setExporting] = useState(false); + const onExport = (exportFileFormat: ExportFileFormat) => { + setExporting(true); + query + .onExportRows(exportFileFormat) + .catch(err => + fireNotification({ + title: 'An error occurred', + message: err?.toString() || err, + type: 'error', + }) + ) + .finally(() => { + setExporting(false); + }); + }; + return (
- {!query.disableRunQuery && ( -
- - + {totalQueriesApplied > 1 && ( +
- )} -
- )} + )} + {!query.disableRunQuery && ( +
+ + +
+ )} + + )} +