Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Input error: only a int can be passed to id filters for AdminUI #8810

Merged
merged 7 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-error-message.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@keystone-6/core": minor
---

Adds error messages for GraphQL errors on the List view in the AdminUI
5 changes: 5 additions & 0 deletions .changeset/fix-id-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@keystone-6/core": patch
---

Fixes `Input error: only a int can be passed to id filters` for AdminUI
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { jsx } from '@keystone-ui/core';
import { FieldContainer, FieldLabel, TextInput } from '@keystone-ui/fields';
import {
import type {
CardValueComponent,
CellComponent,
FieldController,
Expand Down Expand Up @@ -31,13 +31,12 @@ export const CardValue: CardValueComponent = ({ item, field }) => {

export const controller = (
config: FieldControllerConfig<IdFieldConfig>
): FieldController<void, string> & { idFieldKind: IdFieldConfig['kind'] } => {
): FieldController<void, string> => {
return {
path: config.path,
label: config.label,
description: config.description,
graphqlSelection: config.path,
idFieldKind: config.fieldMeta.kind,
defaultValue: undefined,
deserialize: () => {},
serialize: () => ({}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { CellLink } from '../../../../admin-ui/components';
import { PageContainer, HEADER_HEIGHT } from '../../../../admin-ui/components/PageContainer';
import { Pagination, PaginationLabel } from '../../../../admin-ui/components/Pagination';
import { useList } from '../../../../admin-ui/context';
import { GraphQLErrorNotice } from '../../../../admin-ui/components/GraphQLErrorNotice';
import { Link, useRouter } from '../../../../admin-ui/router';
import { useFilter } from '../../../../fields/types/relationship/views/RelationshipSelect';
import { CreateButtonLink } from '../../../../admin-ui/components/CreateButtonLink';
Expand Down Expand Up @@ -146,7 +147,7 @@ const ListPage = ({ listKey }: ListPageProps) => {

const metaQuery = useQuery(listMetaGraphqlQuery, { variables: { listKey } });

let { listViewFieldModesByField, filterableFields, orderableFields } = useMemo(() => {
const { listViewFieldModesByField, filterableFields, orderableFields } = useMemo(() => {
const listViewFieldModesByField: Record<string, 'read' | 'hidden'> = {};
const orderableFields = new Set<string>();
const filterableFields = new Set<string>();
Expand Down Expand Up @@ -183,26 +184,28 @@ const ListPage = ({ listKey }: ListPageProps) => {
}
};

let selectedFields = useSelectedFields(list, listViewFieldModesByField);
const selectedFields = useSelectedFields(list, listViewFieldModesByField);

let {
const {
data: newData,
error: newError,
refetch,
} = useQuery(
useMemo(() => {
let selectedGqlFields = [...selectedFields]
const selectedGqlFields = [...selectedFields]
.map(fieldPath => {
return list.fields[fieldPath].controller.graphqlSelection;
})
.join('\n');

// TODO: FIXME: this is bad
return gql`
query ($where: ${list.gqlNames.whereInputName}, $take: Int!, $skip: Int!, $orderBy: [${
list.gqlNames.listOrderName
}!]) {
items: ${
list.gqlNames.listQueryName
}(where: $where,take: $take, skip: $skip, orderBy: $orderBy) {
}(where: $where, take: $take, skip: $skip, orderBy: $orderBy) {
${
// TODO: maybe namespace all the fields instead of doing this
selectedFields.has('id') ? '' : 'id'
Expand All @@ -226,14 +229,12 @@ const ListPage = ({ listKey }: ListPageProps) => {
}
);

let [dataState, setDataState] = useState({ data: newData, error: newError });

const [dataState, setDataState] = useState({ data: newData, error: newError });
if (newData && dataState.data !== newData) {
setDataState({ data: newData, error: newError });
}

const { data, error } = dataState;

const dataGetter = makeDataGetter<
DeepNullable<{ count: number; items: { id: string; [key: string]: any }[] }>
>(data, error?.graphQLErrors);
Expand All @@ -260,10 +261,11 @@ const ListPage = ({ listKey }: ListPageProps) => {

return (
<PageContainer header={<ListPageHeader listKey={listKey} />} title={list.label}>
{metaQuery.error ? (
// TODO: Show errors nicely and with information
'Error...'
) : data && metaQuery.data ? (
{error?.graphQLErrors.length || error?.networkError ? (
<GraphQLErrorNotice errors={error?.graphQLErrors} networkError={error?.networkError} />
) : null}
{metaQuery.error ? 'Error...' : null}
{data && metaQuery.data ? (
<Fragment>
{list.description !== null && (
<p css={{ marginTop: '24px', maxWidth: '704px' }}>{list.description}</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,37 @@ function useDebouncedValue<T>(value: T, limitMs: number) {
return debouncedValue;
}

function isInt(x: string) {
return Number.isInteger(Number(x));
}

function isBigInt(x: string) {
try {
BigInt(x);
return true;
} catch {
return true;
}
}

export function useFilter(search: string, list: ListMeta, searchFields: string[]) {
return useMemo(() => {
if (!search.length) return { OR: [] };

const trimmedSearch = search.trim();
if (!trimmedSearch.length) return { OR: [] };

const conditions: Record<string, any>[] = [];
if (trimmedSearch.length > 0) {
const { type: idFieldType } = (list.fields.id.fieldMeta as any) ?? {};
if (idFieldType === 'String') {
conditions.push({ id: { equals: trimmedSearch } });
} else if (idFieldType === 'Int' && isInt(trimmedSearch)) {
conditions.push({ id: { equals: Number(trimmedSearch) } });
} else if (idFieldType === 'BigInt' && isBigInt(trimmedSearch)) {
conditions.push({ id: { equals: trimmedSearch } });
} else if (idFieldType === 'UUID') {
conditions.push({ id: { equals: trimmedSearch } }); // TODO: remove in breaking change?
}

if ((list.fields.id.fieldMeta as any)?.type === 'String') {
conditions.push({ id: { equals: trimmedSearch } });
}

Expand Down
14 changes: 7 additions & 7 deletions packages/core/src/lib/id-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,31 +144,31 @@ export function idFieldType(
config: IdFieldConfig,
isSingleton: boolean
): FieldTypeFunc<BaseListTypeInfo> {
const { kind, type, default_ } = unpack(config);
const { kind, type: type_, default_ } = unpack(config);
const parseTypeFn = {
Int: isInt,
BigInt: isBigInt,
String: isString,
UUID: isUuid, // TODO: remove in breaking change
}[kind === 'uuid' ? 'UUID' : type];
}[kind === 'uuid' ? 'UUID' : type_];

function parse(value: IDType) {
const result = parseTypeFn(value);
if (result === undefined) {
throw userInputError(`Only a ${type.toLowerCase()} can be passed to id filters`);
throw userInputError(`Only a ${type_.toLowerCase()} can be passed to id filters`);
}
return result;
}

return meta => {
if (kind === 'autoincrement' && type === 'BigInt' && meta.provider === 'sqlite') {
throw new Error(`{ kind: ${kind}, type: ${type} } is not supported by SQLite`);
if (meta.provider === 'sqlite' && kind === 'autoincrement' && type_ === 'BigInt') {
throw new Error(`{ kind: ${kind}, type: ${type_} } is not supported by SQLite`);
}

return fieldType({
kind: 'scalar',
mode: 'required',
scalar: type,
scalar: type_,
nativeType: NATIVE_TYPES[meta.provider]?.[kind],
default: isSingleton ? undefined : default_,
})({
Expand All @@ -195,7 +195,7 @@ export function idFieldType(
},
}),
views: '@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/id-field-view',
getAdminMeta: () => ({ kind }),
getAdminMeta: () => ({ kind, type: type_ }),
ui: {
createView: {
fieldMode: 'hidden',
Expand Down
1 change: 1 addition & 0 deletions tests/api-tests/admin-meta.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ test(
description: null,
fieldMeta: {
kind: 'cuid',
type: 'String',
},
isNonNull: [],
itemView: {
Expand Down