mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
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:
parent
3aa56fc05f
commit
d2192eca9d
@ -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>
|
||||
);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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 (
|
||||
<>
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user