console: fix query filter and sort validation

[DSF-488]: https://hasurahq.atlassian.net/browse/DSF-488?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9965
GitOrigin-RevId: d3fe971677033dcd3296e8f75896a57658197a8c
This commit is contained in:
Nicolas Inchauspe 2023-07-28 12:00:28 +02:00 committed by hasura-bot
parent 3aa56fc05f
commit d2192eca9d
6 changed files with 49 additions and 59 deletions

View File

@ -3,7 +3,7 @@ import { Table } from '../../../hasura-metadata-types';
import { Dialog } from '../../../../new-components/Dialog';
import { useConsoleForm } from '../../../../new-components/Form';
import React from 'react';
import { UseFormTrigger } from 'react-hook-form';
import { FieldValues, UseFormTrigger } from 'react-hook-form';
import { z } from 'zod';
import { RiPlayFill } from 'react-icons/ri';
import { FilterRows } from '../RunQuery/Filter';
@ -50,23 +50,19 @@ const transformFilterValues = (
};
const schema = z.object({
filters: z
.array(
z.object({
column: z.string(),
operator: z.string(),
value: z.any(),
})
)
.optional(),
sorts: z
.array(
z.object({
column: z.string(),
type: z.literal('asc').or(z.literal('desc')),
})
)
.optional(),
filters: z.array(
z.object({
column: z.string().min(1, 'Column is required'),
operator: z.string().min(1, 'Operator is required'),
value: z.any(),
})
),
sorts: z.array(
z.object({
column: z.string().min(1, 'Column is required'),
type: z.literal('asc').or(z.literal('desc')),
})
),
});
type Schema = z.infer<typeof schema>;
@ -102,7 +98,7 @@ export const QueryDialog = ({
const handleSubmitQuery = async (
filters: Schema['filters'],
triggerValidation: UseFormTrigger<Schema>,
triggerValidation: UseFormTrigger<FieldValues>,
sorts: Schema['sorts']
) => {
if (await triggerValidation()) {
@ -121,36 +117,25 @@ export const QueryDialog = ({
return (
<div className="m-4">
<Dialog hasBackdrop title="Query Data" onClose={onClose}>
<>
<Form onSubmit={() => {}}>
<>
<div className="p-4">
<FilterRows
name="filters"
columns={columns}
operators={supportedOperators}
onRemove={() => onSubmitHandler()}
/>
<hr className="my-4" />
<SortRows
name="sorts"
columns={columns}
onRemove={() => onSubmitHandler()}
/>
</div>
<Dialog.Footer
callToAction="Run Query"
callToActionIconPosition="start"
callToActionIcon={<RiPlayFill />}
callToDeny="Cancel"
onClose={onClose}
onSubmit={() => onSubmitHandler()}
/>
</>
</Form>
</>
<Form onSubmit={() => {}}>
<div className="p-md pt-3">
<FilterRows
name="filters"
columns={columns}
operators={supportedOperators}
/>
<hr className="my-4" />
<SortRows name="sorts" columns={columns} />
</div>
<Dialog.Footer
callToAction="Run Query"
callToActionIconPosition="start"
callToActionIcon={<RiPlayFill />}
callToDeny="Cancel"
onClose={onClose}
onSubmit={() => onSubmitHandler()}
/>
</Form>
</Dialog>
</div>
);

View File

@ -102,8 +102,8 @@ export const Testing: StoryObj<typeof DataTableOptions> = {
const canvas = within(canvasElement);
// the two where clauses should be present
expect(await canvas.findByText('AlbumId > 12')).toBeVisible();
expect(await canvas.findByText('ArtistId < 12')).toBeVisible();
expect(await canvas.findByText('AlbumId > "12"')).toBeVisible();
expect(await canvas.findByText('ArtistId < "12"')).toBeVisible();
// the two order by clauses should be present
expect(await canvas.findByText('First Name (asc)')).toBeVisible();

View File

@ -66,7 +66,7 @@ const DisplayWhereClauses = ({
<FaFilter />
</span>
<span className={twFlexCenter}>
{columnName} {operatorMap[operator]} {value}
{columnName} {operatorMap[operator]} "{value}"
</span>
<span className={`min-h-3 ${twFlexCenter}`}>
<FaRegTimesCircle

View File

@ -185,7 +185,12 @@ export const ReactTableWrapper: React.VFC<ReactTableWrapperProps> = ({
manualPagination: true,
});
if (!rows.length) return <div>No rows Available</div>;
if (!rows.length)
return (
<div className="w-full p-3 text-center font-lg text-muted bg-white border border-gray-300">
No rows Available
</div>
);
return (
<>

View File

@ -12,7 +12,7 @@ export type FilterRowsProps = {
operators: Operator[];
name: string;
initialFilters?: FiltersAndSortFormValues['filters'];
onRemove: () => void;
onRemove?: () => void;
};
export const FilterRows = ({
@ -49,7 +49,7 @@ export const FilterRows = ({
const removeEntry = (index: number) => {
remove(index);
onRemove();
onRemove?.();
};
const columnOptions: SelectItem[] = columns.map(column => {
@ -79,7 +79,7 @@ export const FilterRows = ({
{!fields.length && <div className="mb-sm italic">No Filters Present</div>}
<div className="flex flex-col">
<div className="flex flex-col gap-2 pb-2">
{fields.map((_, index) => (
<FilterRow
key={index}

View File

@ -11,7 +11,7 @@ export type SortRowsProps = {
columns: TableColumn[];
name: string;
initialSorts?: FiltersAndSortFormValues['sorts'];
onRemove: () => void;
onRemove?: () => void;
};
export const SortRows = ({
@ -52,7 +52,7 @@ export const SortRows = ({
const removeEntry = (index: number) => {
remove(index);
setTimeout(() => onRemove(), 100);
onRemove?.();
};
return (
@ -63,7 +63,7 @@ export const SortRows = ({
<div className="mb-sm italic">No sort conditions present.</div>
)}
<div className="flex flex-col">
<div className="flex flex-col gap-2 pb-2">
{fields.map((_, index) => (
<SortRow
key={index}