Skip to content

Commit

Permalink
Respect graphql.omit in fieldMode resolvers (#6429)
Browse files Browse the repository at this point in the history
  • Loading branch information
timleslie authored Aug 31, 2021
1 parent 32f0247 commit cbc5a68
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 22 deletions.
6 changes: 6 additions & 0 deletions .changeset/quiet-vans-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@keystone-next/keystone': patch
'@keystone-next/api-tests-legacy': patch
---

Update adminMeta `fieldMode` resolvers to respect `graphql.omit` configuration.
6 changes: 4 additions & 2 deletions packages/keystone/src/admin-ui/system/createAdminMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function createAdminMeta(
initialColumns = [
labelField,
...Object.keys(list.fields)
.filter(fieldKey => list.fields[fieldKey].access.read !== false)
.filter(fieldKey => list.fields[fieldKey].graphql.isEnabled.read)
.filter(fieldKey => fieldKey !== labelField)
.filter(fieldKey => fieldKey !== 'id'),
].slice(0, 3);
Expand Down Expand Up @@ -98,7 +98,9 @@ export function createAdminMeta(
}

for (const [fieldKey, field] of Object.entries(list.fields)) {
if (field.access.read === false) continue;
// FIXME: Disabling this entirely for now until the Admin UI can properly
// handle `omit: ['read']` correctly.
if (field.graphql.isEnabled.read === false) continue;
let search: 'default' | 'insensitive' | null = null;
if (searchFields.has(fieldKey)) {
if (whereInputFields[`${fieldKey}_contains_i`]?.type === GraphQLString) {
Expand Down
13 changes: 13 additions & 0 deletions packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export function getAdminMetaSchema({
'KeystoneAdminUIFieldMetaCreateView.fieldMode cannot be resolved during the build process'
);
}
if (!lists[rootVal.listKey].fields[rootVal.fieldPath].graphql.isEnabled.create) {
return 'hidden';
}
const listConfig = config.lists[rootVal.listKey];
const sessionFunction =
lists[rootVal.listKey].fields[rootVal.fieldPath].ui?.createView?.fieldMode ??
Expand Down Expand Up @@ -105,6 +108,9 @@ export function getAdminMetaSchema({
'KeystoneAdminUIFieldMetaListView.fieldMode cannot be resolved during the build process'
);
}
if (!lists[rootVal.listKey].fields[rootVal.fieldPath].graphql.isEnabled.read) {
return 'hidden';
}
const listConfig = config.lists[rootVal.listKey];
const sessionFunction =
lists[rootVal.listKey].fields[rootVal.fieldPath].ui?.listView?.fieldMode ??
Expand Down Expand Up @@ -141,6 +147,13 @@ export function getAdminMetaSchema({
'KeystoneAdminUIFieldMetaItemView.fieldMode cannot be resolved during the build process'
);
}
if (!lists[rootVal.listKey].fields[rootVal.fieldPath].graphql.isEnabled.read) {
return 'hidden';
} else if (
!lists[rootVal.listKey].fields[rootVal.fieldPath].graphql.isEnabled.update
) {
return 'read';
}
const item = await context
.sudo()
.db.lists[rootVal.listKey].findOne({ where: { id: rootVal.itemId } });
Expand Down
2 changes: 1 addition & 1 deletion packages/keystone/src/lib/core/graphql-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function collectTypes(
for (const field of Object.values(list.fields)) {
if (
isEnabled.query &&
field.access.read !== false &&
field.graphql.isEnabled.read &&
field.unreferencedConcreteInterfaceImplementations
) {
// this _IS_ actually necessary since they aren't implicitly referenced by other types, unlike the types above
Expand Down
2 changes: 1 addition & 1 deletion packages/keystone/src/types/config/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type CommonFieldConfig<TGeneratedListTypes extends BaseGeneratedListTypes
cacheHint?: CacheHint;
// Setting any of these values will remove the corresponding input/output types from the GraphQL schema.
// Output Types
// 'read': Does this field exist on the Item type? Will also disable filtering/ordering.
// 'read': Does this field exist on the Item type? Will also disable filtering/ordering/admimMeta
// Input Types
// 'create': Does this field exist in the create Input type?
// 'update': Does this field exist in the update Input type?
Expand Down
103 changes: 85 additions & 18 deletions tests/api-tests/access-control/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ describe(`Public schema`, () => {
expect(fieldTypes[`${listName}UpdateInput`].inputFields[name]).toBe(undefined);
}
});
test(`adminMeta - ${JSON.stringify(config)} on ${listName}`, async () => {
test(`adminMeta - build mode ${JSON.stringify(config)} on ${listName}`, async () => {
const query = `
query q($listName: String!) {
keystone {
Expand All @@ -273,27 +273,94 @@ describe(`Public schema`, () => {
const field = data!.keystone.adminMeta.list.fields.filter(
(f: any) => f.path === getFieldName(config)
)[0];

// Filters require both `read` and `filter` to be true for
if (
config.omit !== true && // Not excluded
(config.omit === undefined || !config.omit.includes('read')) && // Can read
(isFilterable || config.isFilterable) // Can filter
) {
expect(field.isFilterable).toEqual(true);
if (config.omit === true || config.omit?.includes('read')) {
// FIXME: This code path will go away once the Admin UI supports `omit: ['read']` properly.
expect(field).toBe(undefined);
} else {
expect(field.isFilterable).toEqual(false);
// Filters require both `read` and `filter` to be true for
if (
// @ts-ignore
config.omit !== true && // Not excluded
(config.omit === undefined || !config.omit.includes('read')) && // Can read
(isFilterable || config.isFilterable) // Can filter
) {
expect(field.isFilterable).toEqual(true);
} else {
expect(field.isFilterable).toEqual(false);
}

// Orderby require both `read` and `orderBy` to be true for
if (
// @ts-ignore
config.omit !== true && // Not excluded
(config.omit === undefined || !config.omit.includes('read')) && // Can read
(isOrderable || config.isOrderable) // Can orderBy
) {
expect(field.isOrderable).toEqual(true);
} else {
expect(field.isOrderable).toEqual(false);
}
}
});

// Orderby require both `read` and `orderBy` to be true for
if (
config.omit !== true && // Not excluded
(config.omit === undefined || !config.omit.includes('read')) && // Can read
(isOrderable || config.isOrderable) // Can orderBy
) {
expect(field.isOrderable).toEqual(true);
test(`adminMeta - not build mode ${JSON.stringify(config)} on ${listName}`, async () => {
const item = await context.sudo().lists[listName].createOne({ data: {} });
const query = `
query q($listName: String!) {
keystone {
adminMeta {
list(key: $listName) {
key
fields {
path
createView { fieldMode }
listView { fieldMode }
itemView(id: "${item.id}") { fieldMode }
}
}
}
}
}`;
const variables = { listName };

const { data, errors } = await context
.withSession({})
.graphql.raw({ query, variables });
expect(errors).toBe(undefined);

const field = data!.keystone.adminMeta.list.fields.filter(
(f: any) => f.path === getFieldName(config)
)[0];

if (config.omit === true || config.omit?.includes('read')) {
// FIXME: This code path will go away once the Admin UI supports `omit: ['read']` properly.
expect(field).toBe(undefined);
} else {
expect(field.isOrderable).toEqual(false);
// createView - edit/hidden (hidden if omit.create)
// @ts-ignore
if (config.omit === true || config.omit?.includes('create')) {
expect(field.createView.fieldMode).toEqual('hidden');
} else {
expect(field.createView.fieldMode).toEqual('edit');
}

// listView - read/hidden (hidden if omit.read)
// @ts-ignore
if (config.omit === true || config.omit?.includes('read')) {
expect(field.listView.fieldMode).toEqual('hidden');
} else {
expect(field.listView.fieldMode).toEqual('read');
}

// itemView - edit/read/hidden (read if omit.update, hidden if omit.read)
// @ts-ignore
if (config.omit === true || config.omit?.includes('read')) {
expect(field.itemView.fieldMode).toEqual('hidden');
} else if (config.omit?.includes('update')) {
expect(field.itemView.fieldMode).toEqual('read');
} else {
expect(field.itemView.fieldMode).toEqual('edit');
}
}
});
}
Expand Down

0 comments on commit cbc5a68

Please sign in to comment.